Skip to main content
This guide walks you through integrating a Stripe “app2web” flow with Helium.

What You’ll Accomplish

By the end of this guide, you’ll have:
  • A Stripe account connected to Helium, with products synced and ready to add to paywalls.
  • Paywalls that offer Stripe products.
  • A hosted web checkout flow that lets users purchase in their browser and deep-links them back into your app.
  • Entitlement tracking across Stripe, the Helium SDK, and (optionally) RevenueCat.

Prerequisites

Before you start, make sure you have:
  • The Helium SDK already integrated in your app.
  • A deep link scheme or universal link configured in your app — users need a way back into your app after purchase.
  • Admin access to your Helium dashboard.

Implementation Steps

1. Connect Stripe to Helium

Go to the Helium Integrations page, click the Stripe tab, and Connect Stripe. Create a new account or connect an existing Stripe account. Sync your products and ensure the APPLE PAY DOMAIN status is Verified.
Helium does not yet support Stripe sandbox.

2. Adjust Stripe Products

Assign Stripe products to appropriate buckets. Add free/paid trials as needed.

3. Build your paywalls

For a short walkthrough, see Build an App2Web paywall. Stripe checkout requires two paywalls:
  1. The original paywall, shown in-app, containing your Stripe products (we recommend adding iOS products too as a backup if user decides to not use Stripe).
  2. A hosted web paywall, which runs the actual Stripe checkout in the user’s browser on clickthrough.to.
When the user taps a CTA on the original paywall, they’re kicked out to the hosted web paywall, where they complete the purchase. To set this up:
  1. Create the original paywall and add Stripe products to it.
  2. Create a hosted web paywall (the editor will prompt you).
  3. Link the two. The original paywall can’t be published without a linked hosted web paywall.
The hosted web paywall doesn’t have to show the same products as the original — you can use it to customize the checkout experience (e.g., upsell a different plan at purchase time). Hosted web paywalls can’t be added to workflows, experiments, or targeting rules; they exist only to back a Stripe paywall.

4. SDK integration

Enable external web checkout before initializing Helium:
The redirectURL is set once, globally. Checkout redirects back to it whether the purchase succeeds, is canceled, or fails. Make sure it’s registered as a deep link in your app (via scheme or universal link).
On older SDK versions that don’t have redirectURL, use the equivalent two-URL form with the same URL for both: enableExternalWebCheckout(successURL:cancelURL:paymentProcessors:). That form still works, but is deprecated.
Set your user ID on Helium before the user reaches a paywall. If you must set user ID after showing a paywall, set the allowWebCheckoutWithoutUserId option to true.Handle the checkout return. Whether checkout succeeds, is canceled, or fails, the user is deep-linked back to your app via the redirect URL. For a smoother handoff, call Helium.shared.handleURL(url) from your onOpenURL / application(_:open:) handler.Add a “Manage Subscription” button so users can cancel or update payment methods via Stripe’s customer portal:
**The Helium SDK will return an unauthenticated link as Stripe customer portal, so your users will have to provide email and log in. For a smoother experience, we recommend creating a pre-authenticated link.

5. (Optional) Connect RevenueCat

If you use RevenueCat alongside Stripe, follow these additional steps so that RevenueCat will be able to track entitlements for Stripe purchases:
1

Visit your RevenueCat Account Settings and find the Connect Stripe button

2

Install the Revenue Cat app to your Stripe account

3

Open RevenueCat Dashboard

  • Open the dashboard: https://app.revenuecat.com/
  • Select your Project > Apps & Providers > Add Web Config
  • Find your Stripe account and complete the flow
4

Select the Stripe web configuration you just added and configure Stripe webhooks to send to RevenueCat

5

Enable Track new purchases from server-to-server notifications

Make sure to enter rc_user_id as the Metadata field key:
Download (4)
6

Configure your Stripe products with RevenueCat

  1. Visit Product catalog for your desired project in RevenueCat dashboard.
  2. In the Products tab, find the Stripe section and add Stripe products
  3. Go to Entitlements tab, select desired entitlement/s, click Attach and add the Stripe products you just created
  4. If you rely on Offerings in your RevenueCat integration, you can also add the Stripe products there

Testing

To test without affecting production traffic, create a test targeting group that includes:
  • Stripe eligible users
  • sandbox or debug environment
Target the App2Web paywall to that group, then run through these scenarios before going live:
  1. Happy path purchase. Open an App2Web paywall in-app, tap a web product, and confirm the app correctly opens the browser. Complete the standard purchase flow, then confirm you’re deep-linked back with an active entitlement. Dismiss the paywall before purchasing as well, and confirm the app returns to the expected screen.
  2. Entitlement sync. After purchase, confirm hasActiveStripeEntitlement() returns true immediately, and that RevenueCat (if connected) updates within a few seconds.
  3. Cancel flow. Open the customer portal from your app, cancel a subscription, and confirm the entitlement expires at period end.
  4. Canceled checkout. Back out of the checkout page without paying and confirm you’re deep-linked back to the app with no entitlement granted and no success state shown.
  5. Pre-login purchase (if applicable). If your App2Web paywall can be shown before you set a durable user_id, make a purchase before setting it. Set the durable user ID afterwards and confirm the entitlement attaches correctly.

Appendix

How entitlements work

Testing sign-in, access, or RevenueCat delivery? See How to test App2Web entitlements. Helium maps your user_id to Stripe’s customer_id. If the user isn’t logged in at purchase time, we use the helium_persistent_id as a stand-in and reconcile once a real user ID is set. On successful purchase, the SDK’s entitlement cache updates immediately. The Helium backend processes Stripe’s webhook to update the customer mapping and forward events to your analytics/revenue pipeline. Entitlements are also checked server-side (which ultimately reflects Stripe’s transaction state), so they stay consistent across devices.

Why two paywalls?

The original in-app paywall presents your Stripe offerings. The hosted web paywall — served from clickthrough.to — runs the actual Stripe checkout, which has to happen in a browser. The two can be customized independently and don’t need to show the same products.

Apple Pay readiness

Web checkout on iOS pays with Apple Pay. A small share of users open it from a browser that cannot complete an Apple Pay payment, and they come back to the app without buying. Apple Pay readiness keeps those users out of web checkout so you can route them to an in-app purchase paywall instead. How it works. On launch, the SDK checks whether Apple Pay can pay on the checkout domain and reports the result to Helium as the webApplePayReadiness targeting variable. The Stripe A2W Eligible targeting preset excludes users whose result is notReady. Those users no longer match your App2Web audience, so give them an IAP-only rule later in the same workflow, or they get no paywall. Everyone else keeps seeing web checkout, including users on older SDKs and users whose result is unknown. The result is an optimization signal, not a guarantee, since the user’s Wallet can change between the check and checkout. Presenting a paywall does not wait for it, apart from the first-launch wait described under Launch timing. Versions. iOS only. Measurement is on by default from Helium iOS 4.13.0, expo-helium 3.6.3, @tryheliumai/paywall-sdk-react-native 3.1.13, and helium_flutter 3.3.14. Earlier versions report ready without measuring, unless you opted in during the beta. Measurement runs only when external web checkout is already configured when the launch request is sent. Call enableExternalWebCheckout before you initialize Helium, as shown above. If you configure it later, users report unknown:notMeasured and the readiness rule excludes no one. Turning it off. Set the flag before you initialize Helium. Users then report unknown:notMeasured and keep seeing web checkout.
If you drive the flag from remote config, read the value cached from the previous session and default to true. A value fetched after initialization only takes effect on the next launch. Launch timing. On the first launch with measurement on, after install or after updating to a version that measures by default, the SDK waits up to two seconds for the measurement before it requests your paywall configuration. Later launches send the stored result immediately and re-measure in the background. A launch into the background skips the measurement and the wait, and the SDK measures once the app becomes active. Apps that declare WKAppBoundDomains. Add bundles.clickthrough.to to that list in your Info.plist. Without it, iOS blocks the check: users report unknown:probeFailed on that first launch and unknown:notMeasured afterwards. Checkout still works and users still see web checkout, but users who are not ready are no longer excluded. Apps that don’t declare WKAppBoundDomains need no change. Targeting. webApplePayReadiness is ready, notReady, or unknown:<reason> when the measurement could not answer. The Stripe A2W Eligible preset already handles it. If you built a Stripe audience without the preset, add a rule that webApplePayReadiness is not notReady. If an audience uses the standalone Browser Apple Pay ready preset from the beta, keep it unless you also add the Stripe A2W Eligible preset to that audience, since it may be the only readiness rule there.

Known limitations and gotchas

  • Availability: Stripe App2Web is currently supported for US storefronts only.
  • Publish states: both the original paywall and its linked hosted web paywall must be published before the flow works end-to-end.
  • Localizations: hosted web paywalls currently support one language.
  • Testing: App2Web previews and SDK requirements cover simulated purchases and real purchases on eligible US devices. Also test through a real trigger to verify targeting and your post-purchase handlers.

Before you go live

Run through the App2Web go-live checklist before sending traffic to this flow. See the App2Web FAQ for attribution, checkout behavior, and evaluating experiment results.