A founder building a small SaaS tool asked me to look at his trial gating before he started actively marketing it, mostly as a formality. He'd tested it himself dozens of times: sign up, use premium features for 14 days, get locked out on day 15 exactly as designed. He was confident, and his confidence was based on something real, just not on the whole picture.
What his testing actually proved
Every test he'd run went through the app's normal interface, the same way a real user would sign up and click around. And through that interface, the gate worked exactly as intended, because the interface checked the trial expiry date correctly before showing premium features. What he hadn't tested was whether that check existed anywhere else, specifically on the API endpoints doing the actual work behind those features.
What we found
The interface hid premium features correctly once a trial expired. The underlying API endpoints that those features actually called, the ones doing the real work of generating a report or exporting data, never checked the trial status at all. They checked only whether a request came from a logged-in user, any logged-in user, trial expired or not. Calling those endpoints directly, bypassing the interface entirely, kept working forever.
The trial looked like it ended. The feature it was supposed to gate never actually noticed.
Why this is such an easy gap to end up with
Trial and subscription gating usually gets built at the interface layer first, since that's what a normal user interacts with and what a quick demo needs to show working. The deeper check, does this specific request, regardless of where it comes from, actually have an active subscription, is a separate piece of work, and it's easy for it to simply never get added if every test happens through the same interface that already enforces the rule correctly.
How to check your own app
- Sign up for a trial with a test account, and let it expire (or manually set its expiry in the past if your system allows that for testing).
- Open your browser's developer tools and find the actual API request behind a premium feature.
- Send that request directly, bypassing the interface entirely, using the expired trial account's session.
- If the feature still works, that's the gap, confirmed directly, regardless of what the interface itself shows.
The fix, and the actual lesson
Every endpoint that does premium work needs to check subscription or trial status itself, on the server, as part of that same request, not rely on the interface having already decided not to show the button. He fixed it within a day once it was pointed out. The broader lesson holds well beyond trial gating: anything the interface decides not to show a user is not the same thing as anything the server has actually decided to refuse.
Related reading
- The Feature That Worked Fine for Three Weeks, Until Someone Found the API Directly
- How to Check Whether Someone Can Just Edit the Price Your App Charges Them
- Myth: "I Used a Reputable AI Coding Tool, So It Already Checked for This"
If your app gates anything behind a trial or a plan, it's worth having someone actually test the endpoints, not just the interface.
Scan my app free