CRXKit
CRXKit is the part you have not written yet: license keys, a free tier that holds, and one MV3 build that goes to Chrome, Edge and Firefox. Fill in one file and take money.
free
after a key
Every one of these is a day you already know how to spend, and none of them is your product.
A network failure is recorded as "can't tell", never "invalid". Fourteen days of offline grace, and a downgrade only after the window expires and three checks in a row fail. Dropping a paying customer during a provider outage is the worst thing this code can do.
Service workers are torn down constantly, so re-checks run on alarms rather than timers, and every piece of state lives in storage. The popup, options page and content script all ask one place for the plan.
Polar and Lemon Squeezy behind one interface. Switching is the string on line 9 of
lib/config.ts. Adding a third means implementing three methods.
A daily quota with its own reset, spent with one await consume(1) before the
work. Pro short-circuits it.
Two permissions, not ten. Firefox's data collection declaration, required on new listings since November 2025. A sources zip for AMO. The manifest differences between the three stores live in one file, and today that file is 54 lines.
CI builds all three browsers and lints against AMO rules on every push. Dependency pull requests arrive on Mondays, already tested by the time you look at them.
Deciding whether someone is on Pro sounds like a boolean. It is six cases, and the two in the middle are where the refund requests come from.
| Situation | Plan |
|---|---|
| No key stored | free |
| Past the provider's own expiry | free, immediately |
| Checked within 24 hours | pro |
| Stale, inside the 14-day grace window | pro, flagged as on grace |
| Grace expired and 3 checks in a row failed | free |
| Provider says revoked or refunded | free, cache cleared |
You would get here eventually. The question is whether you get here before or after the first customer emails you from a train.
Small enough to read, which is the point. No UI kit, no state library, no generator.
lib/ config.ts 53 lines — the only file you edit license.ts 106 lines — the state machine above quota.ts 37 lines — free tier counting storage.ts cache, on top of WXT storage types.ts the LicenseProvider interface providers/ polar.ts Polar adapter lemonsqueezy.ts entrypoints/ background.ts alarms, and the one place plans are answered content.ts example, asks the background rather than deciding popup/ React — badge, quota meter, upgrade link options/ React — key entry, licence status site/ this page and the documentation wxt.config.ts the only place the three browsers differ
One payment. The version you receive is yours permanently, and updates keep arriving while your repository access does.
One person, any number of products.
$79
once, not a subscription
One company, everyone in it.
$199
once, not a subscription
Payments run through Polar, which is the merchant of record and files VAT and sales tax. Full terms in the licence, which you can read before you buy.
Repository invitations are being sent by hand at the moment, while an issue with the automatic invitation is resolved with Polar. Expect access the same day rather than the same minute. If it has not arrived, open an issue at github.com/crxkit/support with your order ID and your GitHub username — that repository is public, so you can reach us before you have access to anything else.
Licence validation in a browser extension runs on the client. Someone determined to bypass it will bypass it, and obfuscation only costs you debugging time. What protects revenue in practice is convenience and a steady update cadence, not a lock. If a capability genuinely must not be copied, it belongs on a server — and then the licence check is what authorises the request.
It is also not a UI kit, not a backend, and not your product. It is the paid-extension plumbing and the store paperwork, so that the part only you can write is the part you spend your week on.
Polar, for a new product. It is a merchant of record built for developer tools, so it files VAT and sales tax for you, and its licence keys are what the kit checks by default.
Lemon Squeezy is supported for people already selling there. It was acquired by Stripe in 2024 and the long-term direction is Stripe Managed Payments.
No. The extension talks to your payment provider's API directly, and the two host permissions in the manifest are the only network access it has.
Yes. Firefox has been MV3 since 109, so the code never forks. The
differences that remain — a stable extension ID, the data collection declaration — are in
wxt.config.ts, and npm run zip:all produces all three uploads.
Not included. Safari needs Xcode, an Apple Developer account and a conversion step, and pretending otherwise would be the kind of promise that produces refunds.
The source is delivered immediately and cannot be returned, so refunds are handled case by case before repository access has been used. Polar's own consumer rules apply on top, and where they give you more, they win.
You are invited to the private repository on purchase, so updates are a pull. Anything that changes for you is written down in the changelog.