2
18 Comments

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 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

on August 5, 2026
  1. 1

    gongshaojie12, here it is, since there is no working DM here I will just drop it in the thread.

    The part you said you would poke at hardest, the line that decides whether it is a real move or a dressed up alert, works like this. It does not just flag a stale follow up or a slipping number. It ranks it against what it actually costs if left alone and gives you the one next action, not a report to interpret. If that next action ever reads like a dressed up alert, that is exactly the spot to tell me it is broken.

    Fastest way in is to email hello@founderflowhq.ai and I will get you access directly. If you would rather I walk you through it live first, happy to do that instead, your call.

    1. 1

      okay, "ranks it against what it costs if left alone" is the right answer and it's the part i was actually worried you'd hand-wave. most of these things stop at "here's a thing that changed" and leave the ranking to the human, which is just alerting with extra steps. opportunity cost as the sort key is the whole game — it's the difference between a list and a decision. so yeah, credit where it's due, you're solving the hard half, not the easy half.

      the one action instead of a report thing lands with me too, funny enough for a grandfathering reason. this whole thread was me trying to collapse a fuzzy call ("when do i charge, who's exempt") into two clean knobs so future-me isn't re-litigating it every time. "one next action, not a report to interpret" is the same instinct — don't make the tired person at 11pm do the synthesis. that's the right shape.

      and the "if the next action reads like a dressed up alert, that's the spot to tell me it's broken" line is a good tell that you actually know where the knife's edge is. that's usually the founder who's stared at their own false positives, not the one who hasn't shipped yet.

      on getting in — i'll take you up on the live walk-through over the email/access route, and here's the honest why: if i sign up for access right now i'm a dead account, because i've got nothing for it to watch. no clients to go quiet, no revenue line, one install metric that's still basically zero and i'm eyeballing it by hand. me poking at a dashboard with no data in it tells you nothing useful. but a live look where i push back on the one-action logic and tell you what reads as signal vs dressed-up — that i can actually do, and it's probably worth more to you than another empty seat right now anyway.

      ping me and let's find a time. no promises i'll be nice about the false positives.

      1. 2

        Fair, a dead account tells me nothing either. Live walk-through it is, and honestly I would rather have you try to break the one-action logic in real time than sign up quietly.

        What timezone are you in, and does mornings or afternoons generally work better for you? Once I know that I can get a real time locked on our end and come back with something concrete instead of guessing.

        1. 1

          i'm in china, UTC+8, so i'm basically a full flip from you — which actually works out cleaner than it sounds. my evenings line up with your mornings, and mornings are exactly when you said you'd rather have me poking at things anyway.

          so if you're on US time, anything in your 9–11am window is my 9–11pm, and 11pm me is wide awake and at his most annoying, which is the version of me you want in this call. give me a day and one of those slots and i'll lock it on my end too.

          and just so you're not walking in blind — i'm going to come at the one-action logic from the "quiet week" angle first. the case i most expect to break it is the stretch where nothing's technically wrong but something's still off. if it stays silent through that, that's the false positive in reverse, and that's the first thing i'm poking at.

          your call on the day. i'll bring the skepticism, you bring the thing that's supposed to survive it.

  2. 1

    Splitting the paid flag from the since date is the right instinct, most people try to solve this with a special case instead of a second variable and it turns into a mess of exceptions within a year. To answer the actual question, I have seen founders give a window instead of a permanent grandfather, and it tends to create the exact resentment they were trying to avoid, since the goodwill gets clawed back the moment the window closes. Permanent free for early users costs less than people expect and it is remembered longer than any discount would be.

    1. 1

      "a special case instead of a second variable" is exactly the trap i almost walked into. my first sketch was literally an if-branch for "old users" bolted onto the paid check, and you could already feel it — that's the thing that's clean for one feature and a swamp by the third. making the gate value itself carry a since date instead of hardcoding an exception is the move that keeps it from rotting. it's the difference between the rule knowing about time and me patching around its blindness forever.

      and your point about the window clawing back goodwill is the part i hadn't put into words but instinctively backed away from. a window doesn't read as "we gave you a year for free." it reads as "the free thing you were using has a countdown on it now," and the resentment lands exactly when they'd otherwise be happiest with you. you don't get credit for the year, you get blamed for the ending. a permanent grandfather is the only version where the goodwill compounds instead of expiring.

      the "costs less than people expect" line is the one that actually settles it for me, and for a slightly brutal reason: my early cohort is small. permanently comping a few hundred early users costs me close to nothing in real revenue, because the whole point is i price this later, once there are far more new users than old ones. the grandfather bill is largest in absolute terms exactly when i can least afford it and smallest relative to revenue exactly when it matters — early. so the "expensive" version is the cheap one, as long as i ship it early. which, conveniently, is also the only time it's honest to. thanks for the sanity check.

      1. 1

        The cohort size point is the part people usually miss when they panic about grandfathering. It feels scary in principle because you are imagining it at scale, but at the moment you actually have to decide, the scale you are protecting against does not exist yet. Glad the framing helped.

        1. 1

          "the scale you're protecting against doesn't exist yet" — that's the sentence, and it's a nice little trap the brain sets for itself. you run the worst-case math against the userbase you hope to have, then flinch at a bill that only exists in that imagined future, and let it stop you from making the cheap promise today. the decision and the fear are living in two different time zones.

          what makes it worse is the asymmetry cuts the honest way for once: the version that feels expensive (grandfather everyone forever) is only ever cheap if you commit while the cohort's tiny — and that's the same window where it's the only honest call anyway. procrastinating doesn't make it safer, it makes it both pricier and less sincere. rare to get "do the generous thing" and "do the cheap thing" pointing the same direction, so i'm taking it. thanks again — this thread genuinely tightened my thinking on it.

          1. 1

            Good luck with the timing on it. The founders who move while the cohort is small usually do not regret it a year later.

              1. 1

                Good luck getting NotebookBloom's pricing switch shipped, the installedAt approach is a clean way to handle it. Since we have gone back and forth a few times now on how you think through decisions like this, I would actually value your take on something I am building too. It is called FounderFlow, it watches for the quiet stuff a founder misses, a client gone quiet, a number drifting wrong, and tells you what to do about it instead of just alerting you. Want me to show you how it works sometime?

                1. 1

                  ha, appreciate that — and the pitch is smoother for being buried under three rounds of actual thinking, which is more than i can say for most of the DMs.

                  here's the honest thing: "watches for the quiet stuff and tells you what to do instead of just alerting" is basically the whole religion of the product i'm building, just pointed at a different target. NotebookBloom's worst failure mode isn't a crash, it's the scrape quietly returning half the data and looking fine — so i've got a whole layer that exists to turn silent-wrong into loud-wrong: a check that yells if a save comes back lopsided, telemetry that pings me the second a selector stops matching. so you're preaching to someone who already bought the sermon. the "don't just alert, say what to do" part is the bit most tools skip and it's the only part that matters, so you're aiming at the right thing.

                  where i'm the wrong guy right now is stage. i'm pre-launch and solo — i don't have clients to go quiet or a revenue number to drift, the only metric i'm watching is an install count that's still basically zero, and i'm doing that by hand because there's nothing to automate yet. the day i've got real users and numbers moving on their own, the quiet-drift problem becomes real for me and this conversation gets a lot more interesting. so not a no, more a "not at the stage where i'd be a useful test." bookmarking it.

                  happy to give you a real look at it though — DM me whenever and i'll poke at it and tell you what actually lands vs what feels like noise, since that's apparently what we do now. this thread earned that much.

                  1. 1

                    Fair, and honestly that is the right call for where you are. No point testing on numbers that do not exist yet.

                    I will take you up on the other offer though. I would rather have your honest read on it than another silent tester, especially from someone who thinks in these terms. I will send it over by DM.

                    1. 1

                      deal. send it over.

                      fair warning on what you're signing up for: i'll give it a real hour, not a courtesy skim, and i'll be blunt about the parts that feel like noise even if it stings — that's the only kind of read that's worth anything, and it's the kind i wish more people had given me at this stage. the polite ones cost me weeks.

                      and since we've spent this whole thread inside my head anyway, you already know where i'm going to lean hardest: the "tells you what to do about it" half. anyone can surface a quiet signal — the whole game is whether the next line is a real move or just a dressed-up alert. that's the part i'd get wrong on my own product on a bad day, so it's the part i'll poke at first. if it holds up there, you've got something.

                      talk in the DMs. this thread earned that much, and then some.

  3. 1

    The interesting part is that you've already made the grandfathering decision before you've charged anyone.

    Have your early users actually expressed an expectation that today's free features should remain free for them, or is permanent grandfathering still mostly a principle you've chosen in advance?

    1. 1

      it's a principle chosen in advance, full stop. nobody has asked me for this. i haven't charged a cent, so no early user has ever had a free feature taken away and gotten upset — there's no demand here, there's just me deciding what kind of thing this is before the pressure exists to decide it badly.

      and honestly that's the whole reason i did it now instead of later. the moment a user is upset about losing a feature is the worst possible moment to design the policy that protects them — you're reacting, you're doing damage control, and every incentive is to grandfather as few people as you can get away with. deciding it while it costs me nothing and benefits no one i can point to is the only time i'll make the generous call cleanly. i wanted it locked in as code before i had a reason to argue myself out of it.

      there's also a slightly self-interested honesty i should own: i'm not doing this because early users demanded it, i'm doing it because i've been the early user who championed a small tool and then watched it paywall the exact feature i'd told my friends about. that stung more than the money did. so this is less "responding to my users' expectation" and more "not becoming the thing that burned me." you framed it right — it's a principle, not a request. i'd just argue the pre-commitment is the point, not a weakness. the promises you make before they cost anything are the only ones you can be sure you meant.

      good question though, genuinely — you keep asking the one that makes me say the less flattering version out loud.

      1. 1

        Appreciate the candid answer, Shaojie.

        I sent you a short email because it raised something that felt better continued there.

        1. 1

          appreciate that, aryan — will pick it up over email. talk soon.