Build your first feature
This guide shows you where your code goes and the 2-file edit that makes a feature paid. Build here any time; nothing before this step depends on it.
Where your code goes
Section titled “Where your code goes”The popup renders a card titled “Your feature goes here”. That is
apps/extension/components/YourFeature.tsx, a small commented component
that is yours to gut:
- Rename it freely (update the import in
apps/extension/entrypoints/popup/main.tsx). - Replace its two buttons with your real UI. Keep the primitives from
@extensionstart/uiand the token color scales; both themes come free. - Talk to the background only through
sendMessagefrom@/utils/messaging. It is typed, so wrong payloads won’t compile.
Unlike the demos, YourFeature.tsx is core: the wizard never prunes it.
Count free actions
Section titled “Count free actions”The default value-first preset raises the paywall on the 10th recorded
action. Record one after your feature does its work:
sendMessage("gateAction", { name: "your-free-action" }).catch(console.error);This is the free button in YourFeature.tsx, verbatim.
Make a feature premium: the 2-file edit
Section titled “Make a feature premium: the 2-file edit”File 1: apps/extension/entrypoints/background/gates.ts. Add your
feature ID to the list at the top:
export const PREMIUM_FEATURES = ["premium-demo", "export-pdf"];File 2: your call site. Ask the gate engine before running the feature:
const decision = await sendMessage("gateFeature", { feature: "export-pdf" });if (decision !== null) return; // the wall is already rendering; stop// …run the premium feature…The premium button in YourFeature.tsx does exactly this with the
"premium-demo" ID, so you can compare against a working example.
What the engine handles for you
Section titled “What the engine handles for you”- The wall renders itself in the popup, sidepanel, and content-script surfaces; you never build wall UI.
- Dismissals cool down. A dismissed paywall stays quiet for 24 hours.
Every timing number lives in
gates.ts. - Sign-in chains. Signed-out users see the sign-in wall first, then the paywall. Sign-in never fires standalone, which keeps you inside store policy.
- Usage mirrors to the server. Events flush to
POST /gate/eventsevery minute; anything with stakes reads server counters, not client ones.
Delete the demos when ready
Section titled “Delete the demos when ready”- GateDemo (
apps/extension/components/GateDemo.tsx): once your own feature callsgateFeature, delete the file and its twoGateDemolines inentrypoints/popup/main.tsx. Don’t prune thegatemodule to remove it; that would delete your paywall engine too. - Highlighter: the content-script demo is the
content-demomodule; rerunpnpm create extstartor see the module system.
Next: 5. Ship it. For presets, timing knobs, and manual wall control, see Paywalls.