Skip to content
Create account or Sign in
/
Ask AI
Create accountSign in
Get started
Payments
Revenue
Platforms and marketplaces
Money management
Developer resources
APIs & SDKsHelp
OverviewAccept a paymentUpgrade your integration
Online payments
OverviewFind your use case
Use Payment Links
Build a payments page
    Overview
    Quickstart guides
      Create a Stripe-hosted checkout page
      Embed a full payment page on your site
      Build an integration with an embedded form
    How Checkout works
    Checkout Studio
    Customize look and feel
    Collect additional information
    Collect taxes
    Collect surcharges
    Dynamically update checkout
    Extend checkout with custom components
    Manage your product catalog
    Subscriptions
    Manage payment methods
    Let customers pay in their local currency
    Add discounts, upsells, and optional items
    Set up future payments
    Save payment details during payment
    After the payment
    Migrate from legacy Checkout
    Migrate Checkout to use Prices
Build a custom integration with Elements
Build an in-app integration
Use Managed Payments
Recurring payments
In-person payments
Terminal overview
Availability
Readers
No code
Custom integration
Payment methods
Add payment methods
Manage payment methods
Faster checkout with Link
Payment operations
Analytics
Balances and settlement time
Compliance and security
Currencies
Declines
Disputes
Radar
Payouts
ReceiptsRefunds and cancellations
Advanced integrations
Custom payment flows
Flexible acquiring
Off-Session Payments
Multiprocessor orchestration
Beyond payments
Incorporate your company
Crypto
Agentic commerce
Financial Connections
Climate
Verify identities
United States
English (United States)
  1. Home/
  2. Payments/
  3. Build a payments page/
  4. Quickstart guides
Public preview

Build an integration with an embedded formPublic preview

The following guide describes how to use the embedded form with Checkout Sessions.

You can also build and preview your embedded Checkout form through Checkout studio, which provides a centralized Dashboard page for configuring and monitoring your Checkout integrations.

Set up Stripe
Server-side

First, create a Stripe account or sign in.

Use our official libraries to access the Stripe API from your application:

Command Line
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
# Available as a gem sudo gem install stripe
Gemfile
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
# If you use bundler, you can add this line to your Gemfile gem 'stripe'

Enable payment methods

By default, Stripe uses your payment methods settings to determine which payment methods the embedded form presents. You can also configure specific payment methods on your Checkout Session using the payment_method_types attribute.

Create a Checkout Session
Server-side

Create a Checkout Session on your server to control the payment flow. The Checkout Session defines your line items, shipping options, and other settings for the payment.

Command Line
cURL
Stripe CLI
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
curl https://api.stripe.com/v1/checkout/sessions \ -u "sk_test_BQokikJOvBiI2HlWgH4olfQ2:" \ -d "line_items[0][price]={{PRICE_ID}}" \ -d "line_items[0][quantity]=1" \ -d mode=payment \ -d ui_mode=form \ -d return_url={{RETURN_URL}} \ -d integration_identifier=embedded_web_0001

Set ui_mode to form to integrate with the embedded form. The returned CheckoutSession object includes a client secret, which the client uses to securely display the checkout interface.

The Checkout Sessions API supports an optional integration_identifier parameter you can set when creating a session. Use it to label this form integration with a recognizable name and measure its conversion independently from other Checkout integrations you run.

You can also configure the following options on the CheckoutSession:

  • automatic_tax: Enable automatic tax calculation
  • automatic_tax[address_collection_precision]: Control billing address collection in embedded forms for tax calculation when automatic tax is enabled
  • billing_address_collection: Collect billing addresses
  • customer_email: Prefill the customer’s email address
  • customer: Prefill customer data from an existing Customer object
  • name_collection: Collect your customers’ business name, individual name, or both
  • shipping_address_collection: Collect shipping addresses
  • shipping_options: Provide shipping rate options
  • submit_type: Specify the type of transaction being performed
  • phone_number_collection: Collect your customer’s phone number
  • tax_id_collection: Collect tax IDs
  • allow_promotion_codes: Allow customer-redeemable promotion codes

Unsupported CheckoutSession parameters

The embedded form doesn’t support consent_collection.

Set up Stripe Elements
Client-side

The embedded form is available as a feature of Stripe.js. Install React Stripe.js and the Stripe.js loader from the npm public registry.

Command Line
npm install --save @stripe/react-stripe-js @stripe/stripe-js

Create clientSecret as a Promise<string> | string containing the client secret returned by your server. Wrap your application with the CheckoutFormProvider component, passing in clientSecret and the stripe instance.

App.jsx
import React, {useMemo} from 'react'; import {CheckoutFormProvider, CheckoutForm} from '@stripe/react-stripe-js/checkout'; import {loadStripe} from '@stripe/stripe-js'; const stripePromise = loadStripe('pk_test_TYooMQauvdEDq54NiTphI7jx'); const App = () => { const clientSecret = useMemo(() => ( fetch('/create-checkout-session', {method: 'POST'}) .then((response) => response.json()) .then((json) => json.client_secret) ), []); return ( <CheckoutFormProvider stripe={stripePromise} options={{clientSecret}} > <CheckoutForm /> </CheckoutFormProvider> ); }; export default App;

Create and mount
Client-side

The embedded form contains an iframe that securely sends the payment information to Stripe over an HTTPS connection.

The CheckoutForm component is already rendered inside CheckoutFormProvider in the previous step. No additional mounting is required for React.

You can specify the layout to render the embedded form as a single-step or multi-step embedded form.

Prefill customer email

You can prefill the customer’s email address using one of two approaches, depending on whether you want the email to be editable.

Set the email on the Checkout Session (non-editable)

Pass customer_email when creating the Checkout Session on your server. The email is displayed in the embedded form but the customer can’t change it. You can also pass a Customer ID to the customer field to prefill the email stored on the Customer.

Set a default email on the client (editable)

Pass defaultValues.email when initializing the SDK to prefill an editable email. The customer can modify this value in the embedded form.

App.jsx
<CheckoutFormProvider stripe={stripePromise} options={{ clientSecret, defaultValues: { email: 'customer@example.com', }, }} > <CheckoutForm /> </CheckoutFormProvider>

Finalize payment
Client-side

The Checkout Session you created on the server automatically determines the line items, total amount, and available payment methods. The embedded form uses this information to display the appropriate interface.

Handle payment confirmation

Handle the confirm event when your customer finalizes their payment:

App.jsx
import React, {useMemo} from 'react'; import {CheckoutFormProvider, CheckoutForm, useCheckoutForm} from '@stripe/react-stripe-js/checkout'; import {loadStripe} from '@stripe/stripe-js'; const stripePromise = loadStripe('pk_test_TYooMQauvdEDq54NiTphI7jx'); const CheckoutPage = () => { const checkoutState = useCheckoutForm(); if (checkoutState.type === 'error') { return <div>Error: {checkoutState.error.message}</div>; } const onConfirm = (event) => { if (checkoutState.type === 'success') { checkoutState.checkout.confirm({formConfirmEvent: event}); } }; return <CheckoutForm onConfirm={onConfirm} />; }; const App = () => { const clientSecret = useMemo(() => ( fetch('/create-checkout-session', {method: 'POST'}) .then((response) => response.json()) .then((json) => json.client_secret) ), []); return ( <CheckoutFormProvider stripe={stripePromise} options={{clientSecret}} > <CheckoutPage /> </CheckoutFormProvider> ); }; export default App;

Handle errors

The embedded form automatically shows localized customer-facing error messages during client confirmation. If a problem prevents the confirm method from continuing, the confirm method can raise an exception. Catch and handle those exceptions.

App.jsx
const onConfirm = async (event) => { if (checkoutState.type === 'success') { try { await checkoutState.checkout.confirm({formConfirmEvent: event}); } catch (error) { console.error('Payment confirmation error:', error); } } };

Customize redirect behavior

By default, after a successful payment, the embedded form redirects your customer to the return_url that you specify when you create the Checkout Session. To prevent redirects for payment methods that don’t require a redirect, such as cards, set redirect to 'if_required' when calling confirm. To learn more, see Customize redirect behavior.

Handle post-payment events
Server-side

The Checkout Session defines your line items, shipping options, and other settings for the payment. After a customer confirms payment on the client, handle the result on your server rather than relying on client-side state.

  • Webhooks Recommended: Listen for the checkout.session.completed event, which Stripe sends when the payment succeeds. This approach ensures you’re notified even if the customer closes their browser before the redirect.
  • Return page: Retrieve the Checkout Session using its ID to check the payment status and show the appropriate result to your customer on the page you set as the return_url.

Learn how to fulfill orders after receiving a payment.

Test the integration

Before you go live, test each payment method integration. Click Pay to complete the payment, which redirects you to the specified return page.

If you see the return page, and the payment appears in the list of successful payments in the Dashboard, your integration is working.

Use Stripe’s test card numbers to test card payments. For example:

Payment succeeds
Payment requires 3DS authentication
Payment is declined

Customize the layout and appearance

You can customize the embedded form by setting its options or by using the Appearance API.

Layout

Use the layout option to control how the embedded form presents checkout steps.

  • Expanded: Use this layout for a single-step checkout. It’s ideal for traditional checkout forms that sit directly on the web page.
  • Compact Private preview: Use this layout for multi-step checkout. It’s ideal for more compact UI layouts like modals, popups, and chat UIs.

When you leave layout undefined, Stripe renders the layout it determines has the best conversion.

Request access to the compact layout

The compact layout displays the embedded form as a multi-step checkout flow. It's available by request in private preview. Enter your email address below to request access.

App.jsx
const checkoutFormOptions = { layout: 'expanded', }; <CheckoutForm options={checkoutFormOptions} onConfirm={onConfirm} />

Embedded form options

You can configure the appearance of each express payment method button and pass saved contacts using options.

App.jsx
const checkoutFormOptions = { expressCheckout: { buttonTheme: { applePay: 'white-outline' }, paymentMethods: { applePay: 'always' } } }; <CheckoutForm options={checkoutFormOptions} onConfirm={onConfirm} />

The embedded form supports the following options:

expressCheckout.buttonThemeSpecify a theme per one-click payment button. See buttonTheme.
expressCheckout.paymentMethodsSpecify which one-click payment buttons show. See paymentMethods.
contactsAn array of objects representing saved addresses, each containing name, address, and phone properties. See contacts.

Appearance API

You can use the Appearance API to control the style of the embedded form by applying a theme or updating specific details. However, the embedded form doesn’t support the rules option.

For instance, choose the “flat” theme and override the primary text color.

App.jsx
const appearance = { theme: 'flat', variables: { colorPrimaryText: '#262626' } }; <CheckoutFormProvider stripe={stripePromise} options={{
clientSecret
, appearance }} > <CheckoutForm /> </CheckoutFormProvider>

Disclose Stripe to your customers

Stripe collects information on customer interactions with Elements to provide services to you, prevent fraud, and improve its services. This includes using cookies and IP addresses to identify which Elements a customer saw during a single checkout session. You’re responsible for disclosing and obtaining all rights and consents necessary for Stripe to use data in these ways. For more information, visit our privacy center.

See also

  • Save a customer’s payment method when they use it for a payment
Was this page helpful?
YesNo
  • Need help? Contact Support.
  • Chat with Stripe developers on Discord.
  • Check out our changelog.
  • Questions? Contact Sales.
  • LLM? Read llms.txt.
  • Powered by Markdoc
On this page