Customize the PayPal Checkout Flow
Important: PayPal supports these Checkout integrations:
- Smart Payment Buttons, which use the PayPal JavaScript SDK. Valid from February 2019 for new integrations.
- Checkout with
checkout.js
. Valid before February 2019. Customers who usecheckout.js
can access reference and support material in this Checkout guide. However, PayPal does not updatecheckout.js
with new features and enhancements.
For more complex integrations, you can add any of these options to the PayPal Checkout JavaScript, checkout.js
:
- Implement the Pay Now checkout flow
- Show a confirmation page
- Show a cancellation page
- Manage funding source failure
- Handle checkout flow errors
- Pass web experience profile options
- Do a full-page redirect
- Use PayPal Checkout with acceptance marks
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. To initialize the Pay Now checkout flow, set commit
to true
as shown in this example:
paypal.Button.render({
commit: true
});
The Pay Now checkout flow displays a review page for the buyer, but shipping address and cart total cannot be changed.
If you don't set the commit: true
parameter, the flow defaults to Continue, which sends the buyer back to the merchant site to complete the payment.
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()
andactions.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
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
- Customize the Checkout Button
- PayPal Checkout Best Practices
- Advanced
checkout.js
docs in the PayPal Checkout GitHub repo.