crxpaydocs

Free trials

Configure trial length, card-required behavior, and the trial-ending webhook. Watch the funnel tick in the dashboard.

Trials are configured per price. You pick the length, whether a card is required up front, and what happens if the trial ends without a payment method. crxpay handles the rest — Stripe runs the clock, the dashboard shows the funnel, and your SDK gets a clean trial_ending event so you can send a save-offer.

Configure a trial

Open Products → [product] → Pricing in the dashboard. When you add or edit a price, pick a trial length (None, 3d, 7d, 14d, 30d, or custom) and the two trial toggles:

SettingOffOn (default)
Require card to start trialAnyone can start the trial with just an email. Higher signup, lower conversion.Stripe collects a card up front. Lower signup, higher conversion.
Auto-convert when trial endsThe subscription pauses instead of activating. User keeps their place; you prompt them to add a card.Normal behavior — Stripe charges the card the moment the trial ends.

The auto-convert toggle is only meaningful when "Require card" is off, since there's nothing to charge otherwise.

Start a trial from the SDK

startTrial is an explicit helper over openCheckout. Use whichever reads better in context:

// Explicit — preferred
await CrxPay.startTrial({ plan: 'price_123' });

// Or just open checkout on a trial price
await CrxPay.openCheckout('price_123');

Both open Stripe Checkout in a new tab. Trial length and card-required behavior come from the price config, so the SDK call stays the same whether you change the trial from 7d to 30d later.

The trial_ending webhook

crxpay fires subscription.trial_ending to every configured endpoint 72 hours before the trial runs out. Use it to send a save-offer email, show a dashboard banner, or trigger a push notification.

Payload:

{
  "extensionId": "ext_...",
  "customerId": "cust_...",
  "subscriptionId": "sub_...",
  "event": {
    "type": "subscription.trial_ending",
    "data": {
      "status": "trialing",
      "mode": "live",
      "trialEnd": "2026-04-24T12:00:00.000Z",
      "processorSubscriptionId": "sub_1Abc..."
    }
  },
  "timestamp": 1714300000000,
  "deliveredAt": "2026-04-21T12:00:00.000Z"
}

Dedup is handled for you. Stripe sometimes fires its own customer.subscription.trial_will_end and an internal hourly cron also scans trials in the 72h window; both paths de-dup against the same unique index, so your endpoint only sees the event once per trial.

Watch the funnel

/p/:extId/trials shows a cohort over the last 7 / 28 / 90 days:

  • Started — trials opened in the window
  • Still trialing — trials in the middle right now
  • Converted — paid subscriptions that started as trials
  • Cancelled in trial — trials that ended without a payment

Activated / Paywall viewed / Checkout started are reserved columns — they start showing real numbers once you wire the corresponding SDK events. For now they render as "not yet instrumented."

The Expiring in the next 72 hours table is the same pool your webhook will fire on. Jump from a row to the customer detail to see the timeline and send an ad-hoc email if you want to override the automated flow.

Recipe: save-offer on trial_ending

// In your extension's background service worker
CrxPay.on('trial_ending', (sub) => {
  if (!sub.trialEndsAt) return;
  // Show an inline offer — e.g. a badge on the toolbar icon
  chrome.action.setBadgeText({ text: '50%' });
  chrome.action.setBadgeBackgroundColor({ color: '#F25A5A' });
});

The event also fires when your developer webhook endpoint receives subscription.trial_ending, so you can send the email from there and light up the in-extension badge from the SDK — both paths run independently and won't conflict.

Was this page helpful?

Your feedback shapes what we document next.