Skip to main content
Gating is two checks, not one: an authoritative one on your backend, and a cosmetic one in your UI so the customer isn’t surprised.

The server check is the real one

userId is the Kerne user id — the same id the subscription was created against. Read it from whatever your request already carries.
A denial isn’t just “don’t run the code” — decide what the caller sees. For an API route, a 403 with a machine-readable reason your frontend can act on beats a generic failure. For a page render, redirect to your pricing page rather than rendering a broken state. If the action is the thing being counted, use consume() instead: it checks and increments atomically, so a burst of concurrent requests can’t all slip past the limit. Acting on behalf of a specific request’s user rather than your own backend identity? Scope the client to their token first:

The client check is for UX only

<Access> (and the useAccess hook under it) handles the loading state and scopes to the logged-in user.
A client-side check is a convenience, never a security boundary — anyone can bypass it by editing the page. Always re-check on the server before doing the thing being gated.
Don’t wait for a “Save” click to tell someone they’ve hit a limit — disable the control ahead of time:

Block, or keep serving and charge?

The same mechanism, one setting apart. The judgment call is which fits what you’re limiting. Block once the allowance is gone — “You’ve reached your 5 team member limit.” Right for things a customer should decide to buy more of on purpose: seats, storage, expensive infrastructure. Nobody should discover they bought more of these as a surprise invoice line. Keep serving and charge for the excess — “the next ones are billed at $0.005 each.” Right for bandwidth, email sends, anything usage-shaped where blocking makes a customer angry without protecting anything. See Designing your pricing. One thing to know before relying on it: a money ceiling stops the charging, never the service. If you want consumption to stop, that’s a separate ceiling in units — see why the cap doesn’t block.

Don’t lose the user’s work over it

Someone who spends 30 minutes on a report and gets blocked on “Save” doesn’t file a support ticket about your quota — they leave. “Error: storage limit reached” throws that work away; “Draft saved locally — upgrade to publish” doesn’t. Check before the expensive step starts, not only when they submit its result.