- Get Started
- Product
- Resources
- Tools & SDKs
- Framework
- Reference
Menu
- Get Started
- Product
- Resources
- Tools & SDKs
- Framework
- Reference
Payment with Stripe in React Storefront
In this document, you'll learn how to use Stripe for payment during checkout in a React-based storefront.
Tip: For other types of storefronts, the steps are similar. However, refer to Stripe's documentation for available tools for your tech stack.
1. Install Stripe SDK#
In your storefront, use the following command to install Stripe's JS and React SDKs:
2. Add Stripe Environment Variables#
Next, add an environment variable holding your Stripe publishable API key.
For example:
Tip: For Next.js storefronts, the environment variable's name must be prefixed with NEXT_PUBLIC . If your storefront's framework requires a different prefix, make sure to change it.
3. Create Stripe Component#
Then, create a file holding the following Stripe component:
Note: This snippet assumes you're using the provider from the Cart Context guide in your storefront.
1"use client" // include with Next.js 13+2 3import { 4 CardElement, 5 Elements, 6 useElements, 7 useStripe,8} from "@stripe/react-stripe-js"9import { loadStripe } from "@stripe/stripe-js"10import { useCart } from "../../providers/cart"11import { useState } from "react"12 13const stripePromise = loadStripe(14 process.env.NEXT_PUBLIC_STRIPE_PK || "temp"15)16 17export default function StripePayment() {18 const { cart } = useCart()19 const clientSecret = cart?.payment_collection?.20 payment_sessions?.[0].data.client_secret as string21 22 return (23 <div>24 <Elements stripe={stripePromise} options={{25 clientSecret,26 }}>27 <StripeForm clientSecret={clientSecret} />28 </Elements>29 </div>30 )31}32 33const StripeForm = ({ 34 clientSecret,35}: {36 clientSecret: string | undefined37}) => {38 const { cart, refreshCart } = useCart()39 const [loading, setLoading] = useState(false)40 41 const stripe = useStripe()42 const elements = useElements()43 44 async function handlePayment(45 e: React.MouseEvent<HTMLButtonElement, MouseEvent>46 ) {47 e.preventDefault()48 const card = elements?.getElement(CardElement)49 50 if (51 !stripe || 52 !elements ||53 !card ||54 !cart ||55 !clientSecret56 ) {57 return58 }59 60 setLoading(true)61 stripe?.confirmCardPayment(clientSecret, {62 payment_method: {63 card,64 billing_details: {65 name: cart.billing_address?.first_name,66 email: cart.email,67 phone: cart.billing_address?.phone,68 address: {69 city: cart.billing_address?.city,70 country: cart.billing_address?.country_code,71 line1: cart.billing_address?.address_1,72 line2: cart.billing_address?.address_2,73 postal_code: cart.billing_address?.postal_code,74 },75 },76 },77 })78 .then(({ error }) => {79 if (error) {80 // TODO handle errors81 console.error(error)82 return83 }84 85 fetch(86 `http://localhost:9000/store/carts/${cart.id}/complete`,87 {88 credentials: "include",89 headers: {90 "x-publishable-api-key": process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY || "temp",91 },92 method: "POST",93 }94 )95 .then((res) => res.json())96 .then(({ type, cart, order, error }) => {97 if (type === "cart" && cart) {98 // an error occured99 console.error(error)100 } else if (type === "order" && order) {101 // TODO redirect to order success page102 alert("Order placed.")103 console.log(order)104 refreshCart()105 }106 })107 })108 .finally(() => setLoading(false))109 }110 111 return (112 <form>113 <CardElement />114 <button115 onClick={handlePayment}116 disabled={loading}117 >118 Place Order119 </button>120 </form>121 )122}
In the code snippet above, you:
- Create a
StripePayment
component that wraps the actual form with Stripe'sElements
component.- In the
StripePayment
component, you obtain the client secret from the payment session'sdata
field. This is set in the Medusa application.
- In the
- Create a
StripeForm
component that holds the actual form. In this component, you implement ahandlePayment
function that does the following:- Use Stripe's
confirmCardPayment
method to accept the card details from the customer. - Once the customer enters their card details and submit their order, the resolution function of the
confirmCardPayment
method is executed. - In the resolution function, you send a request to the Complete Cart API route to complete the cart and place the order.
- In the received response of the request, if the
type
iscart
, it means that the cart completion failed. The error is set in theerror
response field. - If the
type
isorder
, it means the card was completed and the order was placed successfully. You can access the order in theorder
response field. - When the order is placed, you refresh the cart. You can redirect the customer to an order success page at this point.
- Use Stripe's
4. Use the Stripe Component#
You can now use the Stripe component in the checkout flow. You should render it after the customer chooses Stripe as a payment provider.
For example, you can use it in the getPaymentUi
function defined in the Payment Checkout Step guide:
1const getPaymentUi = useCallback(() => {2 const activePaymentSession = cart?.payment_collection?.3 payment_sessions?.[0]4 if (!activePaymentSession) {5 return6 }7 8 switch(true) {9 case activePaymentSession.provider_id.startsWith("pp_stripe_"):10 return <StripePayment />11 // ...12 }13} , [cart])
More Resources#
Refer to Stripe's documentation for more details on integrating it in your storefront.
Was this page helpful?