Stripe Checkout vs Payment Intents: Choosing the Right Integration
Stripe offers multiple payment integration paths. Here's when to use each.
Stripe Checkout: Fastest to Ship
Stripe-hosted checkout page. You redirect to Stripe, they handle everything.
// Create a Checkout Session
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line_items: [{
price: 'price_H5ggYwtDq4fbrJ',
quantity: 1,
}],
mode: 'payment', // 'subscription' for recurring
success_url: `${YOUR_DOMAIN}/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${YOUR_DOMAIN}/cancel`,
customer_email: user.email,
metadata: { userId: user.id },
});
// Redirect user to Stripe
return { url: session.url };
Use Checkout when: you want to ship payments in an hour, don't need custom UI, selling digital products.
Payment Intents: Custom Checkout UI
Full control over the checkout flow with Stripe Elements:
// Server: create payment intent
const paymentIntent = await stripe.paymentIntents.create({
amount: 2999, // $29.99 in cents
currency: 'usd',
automatic_payment_methods: { enabled: true },
metadata: { userId: user.id, productId: product.id },
});
return { clientSecret: paymentIntent.client_secret };
// Client: Stripe Elements
import { loadStripe } from '@stripe/stripe-js';
import { Elements, PaymentElement, useStripe, useElements } from '@stripe/react-stripe-js';
const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_KEY!);
function CheckoutForm({ clientSecret }: { clientSecret: string }) {
const stripe = useStripe();
const elements = useElements();
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
const { error } = await stripe!.confirmPayment({
elements: elements!,
confirmParams: { return_url: `${window.location.origin}/success` },
});
if (error) setErrorMessage(error.message);
};
return (
<form onSubmit={handleSubmit}>
<PaymentElement />
<button type='submit'>Pay $29.99</button>
</form>
);
}
Decision Matrix
| Checkout | Payment Intents | |
|---|---|---|
| Setup time | 1 hour | 1 day |
| UI control | None | Full |
| Handles 3DS/SCA | Yes | Yes |
| Embedded in your app | No | Yes |
| Best for | Simple products | Custom flows |
Subscriptions
For recurring billing, always use Checkout or Billing Portal — they handle:
- Trial periods
- Upgrade/downgrade
- Failed payment retry
- Cancellation flows
Full Stripe integration — Checkout, webhooks, subscription lifecycle, and customer portal — is built into the AI SaaS Starter Kit.
Top comments (0)