checkout

Customize the PayPal Checkout Flow

For more complex integrations, you can add any of these options to the PayPal Checkout JavaScript, checkout.js:

See checkout.js advanced documentation in the PayPal Checkout Github repo.

Implement the Pay Now checkout flow

In the Pay Now checkout flow, payment occurs immediately after your buyer clicks the Pay Now button. It's a best practice to enable Pay Now in your integration. To initialize the Pay Now checkout flow, set commit to true as shown in this example:

paypal.Button.render({
  commit: true
});

Show a confirmation page

In the onAuthorize callback, show your buyer a confirmation page. Use the payment and buyer details from actions.payment.get().

Note: You must show a confirmation without redirecting the page. If you redirect the page, the actions.payment.execute() and actions.payment.get() functions are not available. Alternatively, you can implement a server integration or Braintree SDK integration to execute the payment on the server.

This example code adds a confirmation page in the OnAuthorize function.

Tip: Try it in the interactive code demo.

paypal.Button.render({
  env: 'production', // Optional: specify 'sandbox' environment
  client: {
    sandbox:    'xxxxxxxxx',
    production: 'xxxxxxxxx'
  },
  commit: true, // Optional: show a 'Pay Now' button in the checkout flow
  payment: function (data, actions) {
    return actions.payment.create({
      payment: {
        transactions: [
          {
            amount: {
              total: '1.00',
              currency: 'USD'
            }
          }
        ]
      }
    });
  },
  onAuthorize: function (data, actions) {
    // Get the payment details
    return actions.payment.get()
      .then(function (paymentDetails) {
        // Show a confirmation using the details from paymentDetails
        // Then listen for a click on your confirm button
        document.querySelector('#confirm-button')
          .addEventListener('click', function () {
            // Execute the payment
            return actions.payment.execute()
              .then(function () {
                // Show a success page to the buyer
              });
          });
      });
  }
}, '#paypal-button');

Show a cancellation page

Normally when a buyer cancels a payment, the buyer is returned to the parent page. Instead, you can use the onCancel function to show a cancellation page or return to a shopping cart:

paypal.Button.render({
  env: 'production', // Specify 'sandbox' for the test environment
  payment: function () {
    // Set up the payment here, when the buyer clicks on the button
  },
  onAuthorize: function (data, actions) {
    // Execute the payment here, when the buyer approves the transaction
  },
  onCancel: function (data, actions) {
    // Show a cancel page or return to cart
  }
}, '#paypal-button');

Manage funding source failure

If your buyer's funding source fails, the REST Payments API returns an INSTRUMENT_DECLINED error. A funding source may fail for these reasons:

  • The billing address associated with the financial instrument could not be confirmed.
  • The transaction exceeds the card limit.
  • The card issuer denied the transaction.

To handle this error, restart the payment in the onAuthorize function so the buyer can select a different payment option:

paypal.Button.render({
  //Configure environment
  env: 'production', // To test, set to `sandbox`
  payment: function () {
    // Set up the payment here, when the buyer clicks on the button
  },
  onAuthorize: function (data, actions) {
    // Call your server to execute the payment
    return paypal.request.post(EXECUTE_URL, data)
                 .then(function (res) {          
                    // check for ERROR CODE=INSTRUMENT_DECLINED and restart
                    if (res.error === 'INSTRUMENT_DECLINED') {
                      return actions.restart();
                    }
                 });
  }
}, '#paypal-button');

To test the error handling flow, see Negative Testing for REST API.

Handle checkout flow errors

If an error prevents buyer checkout, define an error page using the onError callback:

paypal.Button.render({
  env: 'production', // Specify 'sandbox' for the test environment
  payment: function () {
    // Set up the payment here, when the buyer clicks on the button
  },
  onAuthorize: function (data, actions) {
    // Execute the payment here, when the buyer approves the transaction
  },
  onError: function (err) {
    // Show an error page here, when an error occurs
  }
}, '#paypal-button');

Pass web experience profile options

As a merchant, you can use the Payment Experience API to create web experience profiles to customize payment flow experiences. When you create a payment, you can reference a web experience profile that provides your customers with a seamless experience from your merchant cart to the payment flow. To further customize the payment flow experience, pass extra options in actions.payment.create().

In this example, we pass the no_shipping integer of 1 so the shipping address isn't displayed on PayPal pages:

paypal.Button.render({
  env: 'production', // Optional: specify 'sandbox' environment
  client: {
    sandbox:    'xxxxxxxxx',
    production: 'xxxxxxxxx'
  },
  commit: true, // Optional: show a 'Pay Now' button in the checkout flow
  payment: function (data, actions) {
    return actions.payment.create({
      payment: {
        transactions: [
          {
            amount: {
              total: '1.00',
              currency: 'USD'
            }
          }
        ]
      },
      experience: {
        input_fields: {
          no_shipping: 1
        }
      }
    });
  },
  onAuthorize: function (data, actions) {
    // Optional: display a confirmation page here

    return actions.payment.execute()
      .then(function () {
        // Show a success page to the buyer
      });
    }
}, '#paypal-button');

Do a full-page redirect

Note: For a smooth buyer experience, PayPal recommends that rather than doing a full-page redirect, you show a success or failure message on the same page.

After a buyer authorizes or cancels a payment, you can redirect the buyer to your return or cancel URL. In the payment function, pass the redirect_urls object with a return and cancel URL. Once the onAuthorize() and onCancel() handlers are called respectively, you can use actions.redirect() to send the buyer to the respective site. The page overlay and loading spinner remain active until the buyer is redirected to PayPal.


paypal.Button.render({
  env: 'sandbox', // sandbox | production
    client: {
      sandbox:    'xxxxxxxxxx',
      production: 'xxxxxxxxxx'
    },

  // Show the buyer a 'Pay Now' button in the checkout flow
  commit: true,

  // payment() is called when the button is clicked
  payment: function(data, actions) {
    // Make a call to the REST API to set up the payment
    return actions.payment.create({
      payment: {
        transactions: [
          {
            amount: { total: '0.01', currency: 'USD' }        
          }
        ],
        redirect_urls: {
          return_url: 'https://example.com',
          cancel_url: 'https://example.com'
        }
      }
    });
  },

  // onAuthorize() is called when the buyer approves the payment
  onAuthorize: function(data, actions) {

    // Make a call to the REST API to execute the payment
    return actions.payment.execute().then(function() {
      actions.redirect();
      }
    );
  },

  onCancel: function(data, actions) {
    actions.redirect();
    }

}, '#paypal-button-container');

Use PayPal Checkout with acceptance marks

To use PayPal Checkout with acceptance marks, PayPal recommends that you render radio buttons on your page. These buttons enable the buyer to choose their payment method, which determines the user's checkout experience.

If the user selects PayPal, show the PayPal button. Otherwise, hide the PayPal button.

Tip: Try this in the interactive code demo.

<!-- Render the radio fields and button containers -->

<label>
  <input type="radio" name="payment-option" value="paypal" checked>
  <img src="/demo/checkout/static/img/paypal-mark.jpg" alt="Pay with Paypal">
</label>

<label>
  <input type="radio" name="payment-option" value="card">
  <img src="/demo/checkout/static/img/card-mark.png"
     alt="Accepting Visa, Mastercard, Discover and American Express">
</label>

<div id="paypal-button-container"></div>
<div id="card-button-container" class="hidden"><button>Continue</button></div>

<script>
  // Helper functions

  function getElements(el) {
    return Array.prototype.slice.call(document.querySelectorAll(el));
  }

  function hideElement(el) {
    document.body.querySelector(el).style.display = 'none';
  }

  function showElement(el) {
    document.body.querySelector(el).style.display = 'block';
  }

  // Listen for changes to the radio fields
  getElements('input[name=payment-option]').forEach(function (el) {
    el.addEventListener('change', function (event) {
      // If PayPal is selected, show the PayPal button
      if (event.target.value === 'paypal') {
        hideElement('#card-button-container');
        showElement('#paypal-button-container');
      }

      // If Card is selected, show the standard continue button
      if (event.target.value === 'card') {
        showElement('#card-button-container');
        hideElement('#paypal-button-container');
      }
    });
  });

  // Hide non-PayPal button by default
  hideElement('#card-button-container');

  // Render the PayPal button
  paypal.Button.render({
    env: 'production', // Optional: specify 'sandbox' environment
    client: {
      sandbox:    'xxxxxxxxx',
      production: 'xxxxxxxxx'
    },
    payment: function (data, actions) {
      return actions.payment.create({
        payment: {
          transactions: [
            {
              amount: {
                total: '1.00',
                currency: 'USD'
              }
            }
          ]
        }
      });
    },
    onAuthorize: function (data, actions) {
      return actions.payment.execute()
        .then(function () {
          document.querySelector('#paypal-button-container')
            .innerText = 'Payment Complete!';
        });
    }
  }, '#paypal-button-container');

</script>

Interactive code demo

PayPal Checkout Integration Demo

Try an interactive code demo of different PayPal Checkout flows. You can directly edit the demo code to see different integrations, custom button styles, and optional features. You can then copy the code directly to your HTML editor.

See also

Feedback