Payment Request ButtonDeprecated
Collect payment and address information from customers who use Apple Pay, Google Pay, or Link.
Legacy feature
The content on this page refers to a Legacy Element. Use the Express Checkout Element instead. If you have an existing Payment Request Button integration, use our migration guide to switch to Express Checkout Element.
The Payment Request Button has the following limitations:
- Only supports card payment methods
- Link is supported, but only when card funding sources are used
- Only shows one payment option
Demo
Caution
The Payment Request Button Element dynamically displays wallet options during checkout, giving you a single integration for Apple Pay, Google Pay, and Link. Alternatively, you can use the Express Checkout Element to offer multiple one-click payment buttons to your customers. Compare the Express Checkout Element and Payment Request Button.
Customers see Apple Pay or Google Pay if they enabled them on their device, and depending on the browser they use. If Link appears, it could be because customers:
- Don’t have Apple Pay or Google Pay enabled on their device.
- Use Chrome with active, authenticated Link sessions.
Prerequisites
Before you start, you need to:
- Review the requirements for each payment button type:
- Apple Pay requires macOS 10.12.1+ or iOS 10.1+.
- Compatible devices automatically support Google Pay.
- Register and verify your domain in both test and live mode.
- Add a payment method to your browser. For example, you can save a card in Chrome, add a card to your Google Pay account, or add a card to your Wallet for Safari.
- Serve your application over HTTPS. This is a requirement both in development and production. One way to get started is to use a service such as ngrok.
Set up Stripe Elements
Note
The demo in CodeSandbox lets you try out React Stripe.js without having to create a new project.
Add Stripe.js and Elements to your page
To use Element components, wrap your checkout page component in an Elements provider. Call loadStripe
with your publishable key and pass the returned Promise
to the Elements
provider.
import React from 'react'; import ReactDOM from 'react-dom'; import {Elements} from '@stripe/react-stripe-js'; import {loadStripe} from '@stripe/stripe-js'; import CheckoutForm from './CheckoutForm'; // Make sure to call `loadStripe` outside of a component's render to avoid // recreating the `Stripe` object on every render. const stripePromise = loadStripe(
); function App() { return ( <Elements stripe={stripePromise}> <CheckoutForm /> </Elements> ); }; ReactDOM.render(<App />, document.getElementById('root'));'pk_test_TYooMQauvdEDq54NiTphI7jx'
Create a paymentRequest instanceClient-side
In your checkout form component, create an instance of stripe.paymentRequest with all required options.
import React, {useState, useEffect} from 'react'; import {PaymentRequestButtonElement, useStripe} from '@stripe/react-stripe-js'; const CheckoutForm = () => { const stripe = useStripe(); const [paymentRequest, setPaymentRequest] = useState(null); useEffect(() => { if (stripe) { const pr = stripe.paymentRequest({ country: 'US', currency: 'usd', total: { label: 'Demo total', amount: 1099, }, requestPayerName: true, requestPayerEmail: true, }); } }, [stripe]); // Use a traditional checkout form. return 'Insert your form or button component here.'; }
Note
Use the requestPayerName
parameter to collect the payer’s billing address for Apple Pay. You can use the billing address to perform address verification and block fraudulent payments. All other payment methods automatically collect the billing address when one is available.
Render the Payment Request Button ElementClient-side
Check to make sure that your customer has an active payment method using canMakePayment. If they do, render the <PaymentRequestButtonElement>
. If they don’t, you can’t render the Element, and we encourage you to show a traditional checkout form instead.
import React, {useState, useEffect} from 'react'; import {PaymentRequestButtonElement, useStripe} from '@stripe/react-stripe-js'; const CheckoutForm = () => { const stripe = useStripe(); const [paymentRequest, setPaymentRequest] = useState(null); useEffect(() => { if (stripe) { const pr = stripe.paymentRequest({ country: 'US', currency: 'usd', total: { label: 'Demo total', amount: 1099, }, requestPayerName: true, requestPayerEmail: true, }); // Check the availability of the Payment Request API. pr.canMakePayment().then(result => { if (result) { setPaymentRequest(pr); } }); } }, [stripe]); if (paymentRequest) { return <PaymentRequestButtonElement options={{paymentRequest}} /> } // Use a traditional checkout form. return 'Insert your form or button component here.'; }
Create a PaymentIntentServer-side
Stripe uses a PaymentIntent object to represent your intent to collect payment from a customer, tracking charge attempts and payment state changes throughout the process.
Create a PaymentIntent
on your server with an amount and currency. Always decide how much to charge on the server side, a trusted environment, as opposed to the client. This prevents malicious customers from being able to choose their own prices.
Included in the returned PaymentIntent is a client secret, which you use to securely complete the payment process instead of passing the entire PaymentIntent object. Send the client secret back to the client to use in the next step.
Complete the paymentClient-side
Listen to the paymentmethod
event to receive a PaymentMethod object. Pass the PaymentMethod ID and the PaymentIntent’s client secret to stripe.confirmCardPayment to complete the payment.
paymentRequest.on('paymentmethod', async (ev) => { // Confirm the PaymentIntent without handling potential next actions (yet). const {paymentIntent, error: confirmError} = await stripe.confirmCardPayment( clientSecret, {payment_method: ev.paymentMethod.id}, {handleActions: false} ); if (confirmError) { // Report to the browser that the payment failed, prompting it to // re-show the payment interface, or show an error message and close // the payment interface. ev.complete('fail'); } else { // Report to the browser that the confirmation was successful, prompting // it to close the browser payment method collection interface. ev.complete('success'); // Check if the PaymentIntent requires any actions and, if so, let Stripe.js // handle the flow. If using an API version older than "2019-02-11" // instead check for: `paymentIntent.status === "requires_source_action"`. if (paymentIntent.status === "requires_action") { // Let Stripe.js handle the rest of the payment flow. const {error} = await stripe.confirmCardPayment(clientSecret); if (error) { // The payment failed -- ask your customer for a new payment method. } else { // The payment has succeeded -- show a success message to your customer. } } else { // The payment has succeeded -- show a success message to your customer. } } });
Caution
The customer can dismiss the payment interface in some browsers even after they authorize the payment. This means that you might receive a cancel event on your PaymentRequest object after receiving a token
or paymentmethod
event. If you use the cancel
event as a hook for canceling the customer’s order, make sure you also refund the payment that you just created.
Test your integration
To test your integration you must use HTTPS and a supported browser. If you use the paymentRequestButton
Element within an iframe, the iframe must have the allow attribute set to equal “payment *”.
In addition, each payment method and browser has specific requirements:
Collect shipping information
To collect shipping information, begin by including requestShipping: true
when creating the payment request.
You can also provide an array of shippingOptions
at this point, if your shipping options don’t depend on the customer’s address.
const paymentRequest = stripe.paymentRequest({ country: 'US', currency: 'usd', total: { label: 'Demo total', amount: 1099, }, requestShipping: true, // `shippingOptions` is optional at this point: shippingOptions: [ // The first shipping option in this list appears as the default // option in the browser payment interface. { id: 'free-shipping', label: 'Free shipping', detail: 'Arrives in 5 to 7 days', amount: 0, }, ], });
Next, listen to the shippingaddresschange
event to detect when a customer selects a shipping address. Use the address to fetch valid shipping options from your server, update the total, or perform other business logic. The address data on the shippingaddresschange
event might be anonymized by the browser to not reveal sensitive information that isn’t necessary for shipping cost calculation.
The customer must provide valid shippingOptions
at this point to proceed in the flow.
paymentRequest.on('shippingaddresschange', async (ev) => { if (ev.shippingAddress.country !== 'US') { ev.updateWith({status: 'invalid_shipping_address'}); } else { // Perform server-side request to fetch shipping options const response = await fetch('/calculateShipping', { data: JSON.stringify({ shippingAddress: ev.shippingAddress }) }); const result = await response.json(); ev.updateWith({ status: 'success', shippingOptions: result.supportedShippingOptions, }); } });
Display line items
Use displayItems to display PaymentItem objects and show the price breakdown in the browser’s payment interface.
const pr = stripe.paymentRequest({ country: 'US', currency: 'usd', total: { label: 'Demo total', amount: 2000, }, displayItems: [ { label: 'Sample item', amount: 1000, }, { label: 'Shipping cost', amount: 1000, } ], });
Style the button
Use the following parameters to customize the Element:
const options = { paymentRequest, style: { paymentRequestButton: { type: 'default', // One of 'default', 'book', 'buy', or 'donate' // Defaults to 'default' theme: 'dark', // One of 'dark', 'light', or 'light-outline' // Defaults to 'dark' height: '64px', // Defaults to '40px'. The width is always '100%'. }, } } <PaymentRequestButtonElement options={options} />
Using your own button
If you want to design your own button instead of using the paymentRequestButton
Element, you can show your custom button based on the result of paymentRequest.canMakePayment(). Then, use paymentRequest.show() to display the browser interface when your button is clicked.
When building your own button, follow the Apple Pay Human Interface Guidelines and Google Pay Brand Guidelines.
Use the Payment Request Button with Stripe Connect
Connect platforms might need to take additional steps when using the Payment Request Button:
If you’re creating direct charges or adding the token to a Customer on the connected account, you must set the
stripeAccount
option on the frontend Stripe instance:const stripe = Stripe(
, { apiVersion: "2024-11-20.acacia", stripeAccount: 'CONNECTED_STRIPE_ACCOUNT_ID', });'pk_test_TYooMQauvdEDq54NiTphI7jx'If you specified on_behalf_of when creating the Payment or Setup intent, you must pass the same value to the paymentRequest instance using the onBehalfOf option:
const paymentRequest = stripe.paymentRequest({ country: 'US', currency: 'usd', total: { label: 'Demo total', amount: 1099, }, requestPayerName: true, requestPayerEmail: true, onBehalfOf: 'CONNECTED_STRIPE_ACCOUNT_ID', });
Register all domains where you plan to show the Payment Request Button.
On your frontend, before creating the
PaymentRequest
instance, set thestripeAccount
option on the Stripe instance:const stripe = Stripe(
, { apiVersion: "2024-11-20.acacia", stripeAccount: 'CONNECTED_STRIPE_ACCOUNT_ID', });'pk_test_TYooMQauvdEDq54NiTphI7jx'Register all domains where you plan to show the Payment Request Button.
Link for the Payment Request Button
When new customers come to your site, they can use Link in the Payment Request Button to pay with their saved payment details. With Link, they don’t need to manually enter their payment information. Link requires domain registration.
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.