Can a Capacitor app use Stripe? Apple and Google payment rules in 2026
When a Capacitor app can charge with Stripe, when it must use In-App Purchase, and what the US link-out ruling and the new EU terms changed. With a working Stripe Checkout flow that returns to the app.
“Can I just use Stripe?” is one of the first questions every team asks when their web app becomes a Capacitor app. The honest answer in 2026 is: it depends on what you sell, and where your users are. The rules moved a lot in the last eighteen months, so here is the current picture, followed by a checkout flow that works.
This is a practical summary, not legal advice. App Store and Play policies change, and the US rules are still in court. Check the current guidelines before you launch a payment change.
The rules at a glance
| What you sell | iOS | Android (Google Play) |
|---|---|---|
| Physical goods and real-world services (food, rides, tickets, consulting) | Stripe or any processor. In-App Purchase is not used. | Stripe or any processor. |
| Digital content and subscriptions, default | In-App Purchase | Google Play Billing |
| Digital goods, US storefront | In-App Purchase, plus a link to your own web checkout is allowed | Check Play’s current US programs for alternative billing and external links |
| Digital goods, EU storefronts (from 1 October 2026) | In-App Purchase (26%), alternative processor (20%) or web link-out (15%) | Play’s EU alternative billing and external offers programs |
| Reader apps (content bought elsewhere: books, music, video) | May link to your website to manage accounts, with Apple’s entitlement | See Play’s policy for the equivalent case |
The US: link-outs are allowed
Since the April 2025 court order in Epic v. Apple, apps on the US storefront can include buttons and links that send users to a website to buy digital goods, and Apple may not restrict how those links look. As of September 2026, Apple charges no commission on those purchases. The Ninth Circuit upheld the contempt finding but said Apple may eventually charge a commission tied to its actual costs; the district court is working out that rate, and the Supreme Court is set to hear Apple's appeal this term.
In practice: a link-out to Stripe Checkout is allowed on the US storefront today, and the economics may change. Build it so the commission is a number you can update, not an assumption baked into your pricing.
The EU: three options, three rates
From 1 October 2026, Apple's new EU terms apply: 26% for In-App Purchase, 20% for an alternative processor inside the app, 15% for a web link-out, with lower rates for small businesses. Users under 13 cannot see web purchase links, and users under 18 need a parental gate. Details in Apple's new EU terms.
A Stripe Checkout flow that returns to the app
For physical goods, or digital goods where a link-out is allowed, the cleanest setup is Stripe Checkout in the system browser. Card details never touch your WebView, Apple Pay and Google Pay work inside Checkout, and you do not need a native Stripe SDK.
1. Create the session on your server. Use a universal link (iOS) or app link (Android) as the return URL so the purchase ends back in the app:
// server
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
line_items: [{ price: 'price_pro_monthly', quantity: 1 }],
client_reference_id: user.id,
success_url: 'https://app.example.com/checkout/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://app.example.com/checkout/cancel',
});
return { url: session.url };2. Open it from the app with the Browser plugin, which uses SFSafariViewController on iOS and Custom Tabs on Android:
import { Browser } from '@capacitor/browser';
async function startCheckout() {
const { url } = await api.post('/billing/checkout');
await Browser.open({ url });
}3. Handle the return. When Stripe redirects to your universal link, the OS opens your app and fires appUrlOpen:
import { App } from '@capacitor/app';
import { Browser } from '@capacitor/browser';
App.addListener('appUrlOpen', async ({ url }) => {
const { pathname } = new URL(url);
if (pathname.startsWith('/checkout/')) {
await Browser.close();
await refreshEntitlements();
router.push(pathname === '/checkout/success' ? '/welcome-pro' : '/pricing');
}
});If you have not set up universal links yet, see deep links and universal links.
4. Grant access from the webhook, not the redirect. The redirect tells you the user came back. The checkout.session.completed webhook tells you they paid. Unlock features on the server when the webhook arrives, and have the app read entitlements from your API.
Show the right option to the right user
With different rules per country, the app should not hard-code which payment options exist. Let the server decide from the user's storefront and age, and return a list:
// GET /billing/options
{
"options": [
{ "type": "iap", "productId": "pro_monthly" },
{ "type": "web", "label": "Pay on our website", "url": "/billing/checkout" }
]
}When a court ruling or a policy update changes the rules, you update the server, not every installed app.
Where live updates fit: a new way to pay is something Apple and Google expect to review, so ship the first version of any payment flow in a store build. After that, the paywall is web code: copy, layout, plan order, how you present annual pricing. Those are the changes that move revenue, and you can ship them over the air.
Iterate your paywall weekly
Pricing pages are rarely right the first time. Teams that test often find large gains in small details, but a store review for every experiment limits you to a handful per quarter.
With OtaKit, paywall changes in a Capacitor app go out the same day. Release to a staging channel for your own devices, then to production, or to a subset first with a staged rollout. If you use In-App Purchase as well, see in-app purchases in Capacitor.