Get 50% off during WWDC 2025!

Design+Code logo

Quick links

Suggested search

PayPal Developer Account

First things first, you will need to create a developer account if you don't already have one. From PayPal's developer's home page, follow the leads to sign up for a business account. Fill all the forms by providing your business and personal information. Once your account gets created, you will be redirected to the dashboard. Switch to the developer dashboard by clicking on Developer, then Dashboard under your name.

A few points to note, a Default Application is already annexed to your account. Equally under Sandbox/Accounts, you can see both a test personal and business accounts were already generated for you. The default application and sandbox accounts will be sufficient for our testing in this demo. If you want to create more, see the Get Started documentation.

react-paypal-js

The official library that allows us to render the out of the box PayPal button is react-paypal-js . Personally, I rather go with the official source if their package works well. react-paypal-js provides a simple alternative way of loading their javascript SDK in React in lieu of inserting it in the script tag in the index.html file. It follows best practices in regards to the loading of the SDK in the sense that it supports async loading and inform when the loading has finished, thus optimizing performance . Other benefits include script reloading and components re-rendering on criteria change as well as some components ready to be used such as the checkout button itself. Working with a module also encapsulates data, meaning because everything is compartmentalized, data is protected and only necessary ones are accessed until being used.

We have already prepared a starter project from code sandbox in the DesignCode team named PayPal Checkout Template . Fork that template to create your own sandbox. This is link to the final project. Install @paypal/react-paypal-js as a dependency.

npm install @paypal/react-paypal-js

PayPal Checkout Button

Create a new file called PaypalCheckoutButton.js under the components folder. This component will hold all the logic and styling for the checkout button. To it, pass in the props as arguments which contains the product . The product information is needed to tell the button what order to create.

// PaypalCheckoutButton.js
const PaypalCheckoutButton = (props) => {
  const { product } = props;

	return (
		<>
		</>
	);
};

export default PaypalCheckoutButton;

Before continuing further on this file, let's import the PaypalCheckoutButton in Checkout.js to be able to see the progress live. Here, we define the product with a description of Design+Code React Hooks Course and a price of $19 . Then underneath the checkout title, add a div element for the button container and the PaypalCheckoutButton as a child. The PayPal button should be wrapped inside a container for the layout.

// Checkout.js
import PaypalCheckoutButton from "./PaypalCheckoutButton";

const Checkout = () => {
  const product = {
    description: "Design+Code React Hooks Course",
    price: 19
  };

  return (
    ...
      <div className="paypal-button-container">
        <PaypalCheckoutButton product={product} />
      </div>
    </div>
  );
};

export default Checkout;

PayPalScriptProvider

Note that since we are using a React library, react-paypal-js includes the PayPalScriptProvider that acts as a context provider for managing states. It is suggested to add it to the root of the React app so import PayPalScriptProvider in App.js and include it in the return statement outside of the App element.

It takes a prop options to configure the SDK to begin with. One attribute that is absolutely mandatory is the client-id whose value is the client ID of your PayPal developer account. Go to the dashboard, select My Apps and Credentials , then Default Application , copy the Client ID.Make sure you are under Sandbox since we are still on the developing mode. Save it to the .env file as REACTAPPPAYPALCLIENTID . The reason we prefix a custom environment variable with REACTAPP is so that React doesn't ignore it and knows it's safe to use in client side. Then, pass that environment variable to the client-id by reading it from the process.env.

// App.js
import { PayPalScriptProvider } from "@paypal/react-paypal-js";

export default function App() {
  return (
    <PayPalScriptProvider
      options={{ "client-id": process.env.REACT_APP_PAYPAL_CLIENT_ID }}
    >
      <div className="App">
        ...
      </div>
    </PayPalScriptProvider>
  );
}

You can set other initial configurations like the currency or locale for example. For the whole list, see their JavaScript SDK script configuration guide. Since I want to use the default currency USD and other default options, I don't need to specify them.

PayPalButtons

As mentioned earlier, the library comes with predefined components. One of them is PayPalButtons . To render the checkout button, add it to the import statement and return it.

// PaypalCheckoutButton.js
import { PayPalButtons } from "@paypal/react-paypal-js";

const PaypalCheckoutButton = (props) => {
  const { product } = props;

  return (
    <PayPalButtons />
  );
}

At this point, you should see the default PayPal buttons with the option to pay with a PayPal account or a card.

Button Styling

Let's style the button a bit, shall we? There are many different styling options to choose from to match closest to your design system. You may see how the button could look like on this Customize the PayPal Buttons documentation, except that the size is replaced with height for the SDK. I will set it as below:

style={{
  color: "silver",
  layout: "horizontal",
  height: 48,
  tagline: false,
  shape: "pill"
}}

Button Props

It's time to insert other button props based on the events flow. I recommend you go over the available button props to know which ones you should include to satisfy your business payment requirements. Check their Github/Storybook documentation on PayPalButtons.

createOrder

Let's start with createOrder . It's a function that gets called after the user clicks on the button to make a one-time payment and launches the checkout screen. It provides data and actions as parameters. The actions is used to create an order with the transaction details. To the purchase_units , set a description and the amount as below. If you wish to charge the customer in a different currency than defined in the initial options, you may add it in the amount object. It is at this step that the buyer approves the transaction.

createOrder={(data, actions) => {
  return actions.order.create({
    purchase_units: [
      {
        description: product.description,
        amount: {
          value: product.price
        }
      }
    ]
  });
}}

onApprove

Once the transaction is authorized, the onApprove event is called. Similarly, the arguments are also data and actions . At this moment, we need to capture the order. It is important to note that without capturing, no money will be deducted from the buyer's account and you would be doing all of this for nothing. capture is a promised function that returns the order, therefore we will use async/await. Then, call the handleApprove function to personalize the user experience after checking out successfully, passing in the orderID derived from data.

onApprove={async (data, actions) => {
  const order = await actions.order.capture(); 
  console.log("order", order);

  handleApprove(data.orderID);
}}

Now, create the handleApprove function with the orderId as parameter. Here, you may send a request to your backend server to fulfill the order. If the response is successful, we update the paidFor state to true . You would need to import useState and add a state for paidFor with an initial value of false beforehand. You may want to refresh the user's account or subscription status as well. If the returned response is error, warn the user with an error message. Then underneath, read the paidFor state. If true, alert a success message.

// PaypalCheckoutButton.js
import { useState } from "react";
import { PayPalButtons } from "@paypal/react-paypal-js";

const PaypalCheckoutButton = (props) => {
  const { product } = props;

  const [paidFor, setPaidFor] = useState(false);

  const handleApprove = (orderId) => {
    // Call backend function to fulfill order

    // if response is success
    setPaidFor(true);
    // Refresh user's account or subscription status

    // if response is error
    // alert("Your payment was processed successfully. However, we are unable to fulfill your purchase. Please contact us at support@designcode.io for assistance.");
  };

  if (paidFor) {
    // Display success message, modal or redirect user to success page
    alert("Thank you for your purchase!");
  }

  ...
}

onError

In the event of an error, the process jumps to the onError function for which we save that error in a new state. I would also console error it.

onError={(err) => {
  setError(err);
  console.error("PayPal Checkout onError", err);
}}

If the error state is not null, alert the user of it.

const [error, setError] = useState(null);

...

if (error) {
  // Display error message, modal or redirect user to error page
  alert(error);
}

Now that there is a state for the error, replace the alert to setError in the handleApprove function.

// setError("Your payment was processed successfully. However, we are unable to fulfill your purchase. Please contact us at support@designcode.io for assistance.")

onCancel

You may want to perform any action when the customer cancels the checkout. Insert the onCancel prop for that.

onCancel={() => {
  // Display cancel message, modal or redirect user to cancel page or back to cart
}}

onClick

Last but not least, onClick provides an interim step for validation before proceeding to checkout. Let's say if you are offering a subscription, you could check whether your user is subscribed beforehand, or you could prevent them from repurchasing the same product.

Return from this function actions.reject to fail the checkout or actions.resolve to continue with the checkout, which proceeds to the next step createOrder . Below is an example.

onClick={(data, actions) => {
  // Validate on button click, client or server side
  const hasAlreadyBoughtCourse = false;

  if (hasAlreadyBoughtCourse) {
    setError(
      "You already bought this course. Go to your account to view your list of courses."
    );

    return actions.reject();
  } else {
    return actions.resolve();
  }
}}

Testing

To be able to test a payment, you will need a buyer and a merchant accounts to emulate the transaction in their respective accounts. As said earlier, these accounts were already created when you signed up. Let's use them for testing.

On the PayPal developer dashbord under Sandbox/Accounts, view the buyer account to get the credentials. Copy the email and password, paste them in the checkout window to login, and continue with the payment.

Once the transaction is complete, go to https://sandbox.paypal.com and login under both the buyer and business accounts to view the transaction details.

Shortcomings

From my experience working with PayPal, I find it is lagging behind other payment platforms such as Stripe. There are some shortcomings that irritate me. For example, the transaction ID shown on the client account is not the same as that of the merchant. When a customer gives me a transaction ID, this information does not prove useful to me. I find there is discrepancy there. Data is everything, and there is definitely lack of data, both on the dashboard and the reports. It would be nice to be able to view the order attached to the transaction and a way to retrieve the order ID on the dashboard. This is just my take on PayPal.

Still, because PayPal is widely spread and very secure, the customers want it and in response, we need to give what the customers want.

Learn with videos and source files. Available to Pro subscribers only.

Purchase includes access to 50+ courses, 320+ premium tutorials, 300+ hours of videos, source files and certificates.

BACK TO

Stripe Checkout Client Only

Templates and source code

Download source files

Download the videos and assets to refer and learn offline without interuption.

check

Design template

check

Source code for all sections

check

Video files, ePub and subtitles

Browse all downloads