DEV Community

Cover image for Implementing Stripe Payments in a React App and on Stripe Hosted Page: A Step-by-Step Guide
Momin Mahmud
Momin Mahmud

Posted on

Implementing Stripe Payments in a React App and on Stripe Hosted Page: A Step-by-Step Guide

Introduction:

In this blog post, I will walk you through the process of integrating Stripe payments into a React application. Stripe offers a seamless way to accept payments online, and with their Payment Element and React Stripe.js library, it becomes even easier to implement within your React projects.

Step 1: Set up Stripe

First, you'll need to set up your Stripe account and obtain your publishable key. This key will be used to connect your React application with Stripe's API.

Step 2: Install Dependencies

Using npm or yarn, install the necessary dependencies for integrating Stripe into your React application. This includes @stripe/react-stripe-js and @stripe/stripe-js packages.

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

Step 3: Configure Stripe Elements Provider

In your React application, wrap your checkout page component with the Elements provider from @stripe/react-stripe-js. Use the loadStripe function to load your Stripe instance with your publishable key.

Step 4: Add Payment Element Component

Create a checkout form component where you'll include the PaymentElement component provided by Stripe. This component handles the collection of payment details from the user.

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('pk_test_51Oms7lDHd6wvkNXn2q0ORqQYjpQlJW2zpR36LTnmtkrTS3TCRUKpyXPXt9bkc8ZJ0pkwAxpWODvvynMoABsERAZQ00JXOBTvLk');

function App() {
  const options = {
    mode: 'payment',
    amount: 1099,
    currency: 'usd',
    // Fully customizable with appearance API.
    appearance: {/*...*/},
  };

  return (
    <Elements stripe={stripePromise} options={options}>
      <CheckoutForm />
    </Elements>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));

import React from 'react';
import {PaymentElement} from '@stripe/react-stripe-js';

const CheckoutForm = () => {
  return (
    <form>
      <PaymentElement />
      <button>Submit</button>
    </form>
  );
};

export default CheckoutForm;
Enter fullscreen mode Exit fullscreen mode

Step 5: Create PaymentIntent on Server

On the server side, use a backend framework (e.g., Node.js with Express) to create a route for creating a PaymentIntent. This involves using the Stripe API to create a PaymentIntent with the desired amount and currency.

using System;
using Microsoft.AspNetCore.Mvc;
using Stripe;

namespace StripeExampleApi.Controllers
{
  [Route("create-intent")]
  [ApiController]
  public class CheckoutApiController : Controller
  {
    public CheckoutApiController()
    {
      StripeConfiguration.ApiKey = "sk_test_51Oms7lDHd6wvkNXnWTQ2NMtzJOtXij2UtdyW9FAKS4HZOnSWonZMeaPGXMoqcTiSYFokhK3BIvolPTcwthggS4TS00LL9O97bC"
    }

    [HttpPost]
    public ActionResult Post()
    {
      var options = new PaymentIntentCreateOptions
      {
          Amount = 1099,
          Currency = "usd",
          // In the latest version of the API, specifying the `automatic_payment_methods` parameter is optional because Stripe enables its functionality by default.
          AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions
          {
              Enabled = true,
          },
      };
      var service = new PaymentIntentService();
      PaymentIntent intent = service.Create(options);
      return Json(new {client_secret = intent.ClientSecret});
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 6: Submit Payment to Stripe

Back in your React application, handle form submission by calling the handleSubmit function. Inside this function, trigger form validation and wallet collection with elements.submit(). Then, fetch the client secret from your server and confirm the PaymentIntent using stripe.confirmPayment().

Step 7: Handle Payment Confirmation

After confirming the PaymentIntent, handle any errors that may occur during the payment process. If successful, your customer will be redirected to the specified return URL.

import React, {useState} from 'react';
import {useStripe, useElements, PaymentElement} from '@stripe/react-stripe-js';

export default function CheckoutForm() {
  const stripe = useStripe();
  const elements = useElements();

  const [errorMessage, setErrorMessage] = useState();
  const [loading, setLoading] = useState(false);

  const handleError = (error) => {
    setLoading(false);
    setErrorMessage(error.message);
  }

  const handleSubmit = async (event) => {
    // We don't want to let default form submission happen here,
    // which would refresh the page.
    event.preventDefault();

    if (!stripe) {
      // Stripe.js hasn't yet loaded.
      // Make sure to disable form submission until Stripe.js has loaded.
      return;
    }

    setLoading(true);

    // Trigger form validation and wallet collection
    const {error: submitError} = await elements.submit();
    if (submitError) {
      handleError(submitError);
      return;
    }

    // Create the PaymentIntent and obtain clientSecret
    const res = await fetch("/create-intent", {
      method: "POST",
    });

    const {client_secret: clientSecret} = await res.json();

    // Confirm the PaymentIntent using the details collected by the Payment Element
    const {error} = await stripe.confirmPayment({
      elements,
      clientSecret,
      confirmParams: {
        return_url: 'https://example.com/order/123/complete',
      },
    });

    if (error) {
      // This point is only reached if there's an immediate error when
      // confirming the payment. Show the error to your customer (for example, payment details incomplete)
      handleError(error);
    } else {
      // Your customer is redirected to your `return_url`. For some payment
      // methods like iDEAL, your customer is redirected to an intermediate
      // site first to authorize the payment, then redirected to the `return_url`.
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <PaymentElement />
      <button type="submit" disabled={!stripe || loading}>
        Submit Payment
      </button>
      {errorMessage && <div>{errorMessage}</div>}
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

Change Request

So, my client recently approached me with some concerns regarding our current implementation of Stripe payments within our React application. They emphasized the importance of compliance with industry regulations and the need to address potential security vulnerabilities. After a thorough discussion, we collectively decided that it would be best to modify our approach. Specifically, we agreed to transition the payment process to an external page. This decision was made to enhance security by isolating the payment transaction from our main application environment, thus reducing the risk of unauthorized access to sensitive payment information. By moving to an external page for payment processing, we aim to bolster our data protection measures and ensure strict adherence to regulatory requirements. This adjustment demonstrates our unwavering commitment to maintaining the highest standards of security and compliance throughout our payment ecosystem.

Payment on Stripe Hosted Page

Step 1: Install Stripe.NET Package

Begin by installing the Stripe.NET package using either the dotnet CLI or NuGet package manager. This package provides access to the Stripe API from your .NET Core application, enabling seamless integration with Stripe Checkout.

# Install with dotnet
dotnet add package Stripe.net
dotnet restore
Enter fullscreen mode Exit fullscreen mode

Step 2: Add Checkout Button to Your Website

In your HTML page, add a checkout button that calls a server-side endpoint to create a Checkout Session. This session represents what your customer sees when redirected to the payment form and can be configured with line items, currencies, success URL, and cancel URL.

<html>
  <head>
    <title>Buy cool new product</title>
  </head>
  <body>
    <!-- Use action="/create-checkout-session.php" if your server is PHP based. -->
    <form action="/create-checkout-session" method="POST">
      <button type="submit">Checkout</button>
    </form>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Step 3: Configure Server-Side Endpoint

Set up a server-side endpoint using ASP.NET MVC framework to handle the creation of a Checkout Session. Utilize the Stripe.NET library to create a session with the desired line items, currency, success URL, and cancel URL. Upon creation, redirect the customer to the session URL returned by Stripe.

// This example sets up an endpoint using the ASP.NET MVC framework.
// Watch this video to get started: https://youtu.be/2-mMOB8MhmE.

using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Stripe;
using Stripe.Checkout;

namespace server.Controllers
{
  public class PaymentsController : Controller
  {
    public PaymentsController()
    {
      StripeConfiguration.ApiKey = "sk_test_51Oms7lDHd6wvkNXnWTQ2NMtzJOtXij2UtdyW9FAKS4HZOnSWonZMeaPGXMoqcTiSYFokhK3BIvolPTcwthggS4TS00LL9O97bC";
    }

    [HttpPost("create-checkout-session")]
    public ActionResult CreateCheckoutSession()
    {
      var options = new SessionCreateOptions
      {
        LineItems = new List<SessionLineItemOptions>
        {
          new SessionLineItemOptions
          {
            PriceData = new SessionLineItemPriceDataOptions
            {
              UnitAmount = 2000,
              Currency = "usd",
              ProductData = new SessionLineItemPriceDataProductDataOptions
              {
                Name = "T-shirt",
              },
            },
            Quantity = 1,
          },
        },
        Mode = "payment",
        SuccessUrl = "http://localhost:4242/success",
        CancelUrl = "http://localhost:4242/cancel",
      };

      var service = new SessionService();
      Session session = service.Create(options);

      Response.Headers.Add("Location", session.Url);
      return new StatusCodeResult(303);
    }
  }
}

Enter fullscreen mode Exit fullscreen mode

Step 4: Create a Success Page

Create a minimal success page to display to the customer after a successful payment submission. This page should convey gratitude for the order and provide contact information for further inquiries.

<html>
  <head><title>Thanks for your order!</title></head>
  <body>
    <h1>Thanks for your order!</h1>
    <p>
      We appreciate your business!
      If you have any questions, please email
      <a href="mailto:orders@example.com">orders@example.com</a>.
    </p>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Step 5: Test Your Integration

Test your Stripe-hosted payment form integration by creating a Checkout Session and filling out payment details with test card information. Verify successful payment redirection to the designated success URL and check the payment details in the Stripe Dashboard.

  • Click your checkout button.

  • Fill out the payment details with the test card information:

  • Enter 4242 4242 4242 4242 as the card number.

  • Enter any future date for card expiry.

  • Enter any 3-digit number for CVC.

  • Enter any billing postal code.

  • Click Pay.

  • You’re redirected to your new success page.

Conclusion:

Implementing Stripe payments in your React application is made simple with the Stripe Payment Element and React Stripe.js library. By following these steps, you can securely accept payments from your users while providing a seamless checkout experience.

With this guide, you can enhance your e-commerce or subscription-based application by integrating Stripe payments, empowering you to monetize your services with ease.

Top comments (0)