Monthly, annual, lifetime. Create any billing cadence from the dashboard. Proration, upgrades, downgrades, and plan switches all handled by Stripe Connect under the hood.
Subscriptions
Subscription billing, actually solved for extensions.
Trials, renewals, grace periods, entitlements, and recovery — all MV3-native, all signed to the browser so a flaky network can’t break your users’ Pro status.
Finite state machine
A subscription that literally can’t enter a wrong state.
Every subscription is an XState machine under the hood. The UI only ever reads a typed status — so “active but unpaid” and “canceled but still Pro” are impossible by construction.
type SubStatus = | 'trialing' | 'active' | 'past_due' | 'canceled' | 'expired'; interface Subscription { status: SubStatus; entitlements: string[]; renewsAt?: Date; graceUntil?: Date; hasEntitlement(e: string): boolean; on(e: SubEvent, cb: () => void): void; }
Offline-signed cache
Entitlements survive the subway, the coffee shop, and a server restart.
Every SDK load writes an HMAC-signed subscription snapshot to chrome.storage.local. Your code reads from it synchronously, and Chrome refuses to touch anything the server didn’t sign.
- ✓Synchronous reads0ms — no network on the critical path
- ✓Forgery-proofHMAC signature verified on every read
- ✓Fresh-when-possibleBackground revalidation, stale-while-revalidate
- ✓Privacy-safeNothing leaves the browser without auth
{
"status": "active",
"entitlements": ["pro", "team"],
"renewsAt": "2026-05-14",
"sig": "v1.hmac-sha256:9f3c…"
}Everything you expect. Nothing you have to wire up.
Plans, trials, coupons, grace periods — all configurable, none duct-taped.
Free trials with or without a card. 3 / 7 / 14 / 30-day trials, gated or ungated, with auto-convert or opt-in renewal. Trial length is a dashboard knob, not a deploy.
Coupons, promos, and intro offers. Percentage, fixed amount, first-N-months pricing, and one-click win-back offers. Expire, cap, and target by cohort.
Grace periods that recover revenue. Configure grace windows for past-due customers. The SDK keeps them Pro while smart retries recover 22% of failed charges on average.
Tiny API, zero ceremony
One import. Three methods. Your paywall is done.
The SDK is 14 KB gzipped, MV3-native, and never throws. Check an entitlement synchronously, subscribe to state changes, or handle webhooks server-side — the shape is the same everywhere.
- →Synchronous checks
hasEntitlement()reads from the signed cache - →Typed events
on("active" | "past_due" | "canceled", …) - →Idempotent webhooksRetries are safe by construction
import { CrxPay } from '@crxpay/sdk'; const sub = await CrxPay.ready(); if (sub.hasEntitlement('pro')) { // unlock the feature — synchronous, 0ms enableProMode(); } else { CrxPay.showPaywall({ plan: 'annual' }); }
Receipts
The numbers behind the subscription engine.
Real telemetry from production extensions — sampled from the last 90 days, across free, paid, and freemium tiers.
Ready to grow?
Our entire suite of features comes standard — and your first $2,500 in tracked revenue is free.