How do I start charging later without punishing the people who showed up first?
My plan has always been: launch almost everything free, get people using it, and start charging for individual features later, once there's a reason to. I wrote earlier about the remote switch that lets me flip a feature
My plan has always been: launch almost everything free, get people using it, and start charging for individual features later, once there's a reason to. I wrote earlier about the remote switch that lets me flip a feature to paid without shipping a new release.
But there's a nasty problem hiding inside "charge later," and it took me a while to name it.
The day I flip, say, flashcard export from free to paid β what happens to the person who's been using flashcard export every day for three months? Under the naive version of my switch, they open the app tomorrow and a thing they relied on is suddenly locked. I just punished my most engaged user. Worse: I punished them specifically because they showed up early, before I figured out how to make money. The people who gave me my first reviews and told their friends would be the exact people I paywall first.
That's backwards. Early users should be rewarded for being early, not billed for it.
The answer is an old idea with an ugly name: grandfathering. When you start charging for something, the people who were already there keep it free β forever.
The tricky part is that my switch had no sense of time. It knew "is this feature paid?" but not "paid for whom, since when?" So I taught it.
Two pieces. First, every install now quietly records when it first ran β an installedAt timestamp, written the very first time the extension loads. Second, my paywall switch can now hold more than just on/off. Instead of "flashcard export = paid," I can set "flashcard export = paid for anyone who installed after March 1st." Everyone with an installedAt before that date sails through free, permanently. Everyone after pays. Same one-value flip, no new release β it just now carries a "since when" alongside the "paid."
In code it's a tiny change: the gate value went from a boolean to either a boolean or a little object with a paid flag and a since date. The check became "if you're not paid, and your install predates the cutoff, you're exempt." That's it. But the behavior it buys is exactly the promise I want to make: get here early, keep it free, no asterisks.
One honest limitation. installedAt is only accurate for people who install after I shipped this timestamp logic. Anyone already using the extension before that gets stamped with "now" the first time they upgrade β so they look slightly newer than they really are. The practical consequence is oddly motivating: the earlier I ship this, the more of my real early users get correctly grandfathered. Deploying the loyalty machinery is itself time-sensitive.
What I like about this is that it dissolves a conflict I thought I had to live with. "Grow with free, monetize later" felt like it was in tension with "don't betray the people who believed in you early." It isn't β you just need your paywall to remember who was here first. The strategy decides when to charge; the timestamp decides who's exempt. Two separate knobs, no contradiction.
I haven't charged anyone a cent yet. But the machine that will, someday, already knows to let my first users through for free. That feels like the right thing to build before I need it, not after someone gets burned.
How do you handle your earliest users when pricing changes β grandfather them forever, give them a window, or something else?
β building NotebookBloom in public, #15
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.