Dev.to WebDev πŸ›  Dev πŸ‘ 0 πŸ“– 3 min read

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

πŸ“° Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.