crxpay

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.

Monthly, annual, lifetimeOffline-signed entitlementsGrace periods + dunning
Subscription
Your App Pro
ACTIVE
$9.99/ month
Renews in12 days
Entitlements
prounlimitedteam
Offline
HMAC-signed
Webhook
invoice.paid
Your account
Stripe Connect

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.

Lifecycle · sub.status
Trialing7-day trialActivePro unlockedPast dueGrace + retryRecoveredDunning winCanceledWin-back offer
normal transitionrecoveryfailurewin-back
Subscription.ts
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 reads
    0ms — no network on the critical path
  • Forgery-proof
    HMAC signature verified on every read
  • Fresh-when-possible
    Background revalidation, stale-while-revalidate
  • Privacy-safe
    Nothing leaves the browser without auth
chrome.storage.local
Offline-safe
{
  "status": "active",
  "entitlements": ["pro", "team"],
  "renewsAt": "2026-05-14",
  "sig": "v1.hmac-sha256:9f3c…"
}
Signature verified · cache is authentic
Web Crypto API · 0.3ms · no network
Online
Reads from cache → background refresh
Offline
Still reads from cache → Pro stays Pro
No network?
No problem.

Everything you expect. Nothing you have to wire up.

Plans, trials, coupons, grace periods — all configurable, none duct-taped.

Monthly
$9.99 /mo
AnnualSave 25%
$89 /yr
Lifetime
$199 once

Monthly, annual, lifetime. Create any billing cadence from the dashboard. Proration, upgrades, downgrades, and plan switches all handled by Stripe Connect under the hood.

Free trial
7 daysthen $9.99/mo
Day 3 of 74 days left
3-day7-day14-day30-day

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.

Promo code
WINBACK30
30% off for 3 months
Percentage30% off
Fixed$5 off
Intro$3 × 3mo
Free mo.1 month

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 period · 7 days
1
2
3
D+0D+2D+4D+6
Recovered $14.99 · still Pro the whole time

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 webhooks
    Retries are safe by construction
background.ts
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.

0+
Extensions running crxpay
across 32 categories
0%
Median dunning recovery
vs 6% industry baseline
0ms
SDK cold start, p95
measured across 12M loads
0.00%
Entitlement API uptime
trailing 90 days

Ready to grow?

Our entire suite of features comes standard — and your first $2,500 in tracked revenue is free.