Client-Side Implementation
The examples in this guide require version 3.90.0 or higher of the Braintree JavaScript SDK.
If you use the Braintree JavaScript SDK with the deprecated PayPal checkout.js library, review this migration guide to upgrade your integration.
Before you can add a PayPal button, make sure you have a few prerequisites out of the way:
- Create, verify, and link your PayPal account in the Braintree Control Panel
- Generate a client token on your server
- See Hello, Server and Hello, Client for a walkthrough of creating and using a client token
- You will use the client token when you initialize your components
Browser support
Learn more about browser support for v3 of our JavaScript SDK.
Basic configuration
If you are using script tags to load files, be sure to at least include:
- HTML
<!-- Load the client component. -->
<script src="https://js.braintreegateway.com/web/3.139.0/js/client.min.js"></script>
<!-- Load the PayPal Checkout component. -->
<script src="https://js.braintreegateway.com/web/3.139.0/js/paypal-checkout.min.js"></script>Regardless of which method you use to load files, create a div element where your PayPal button will appear.
- HTML
<div id="paypal-button"></div>Initialize components
Integrating PayPal payments requires a client. After you've created a client, pass it to the PayPal Checkout component to accept your payments.
- Callback
- Promise
// Create a client.
braintree.client.create({
authorization: CLIENT_AUTHORIZATION
}, function (clientErr, clientInstance) {
// Stop if there was a problem creating the client.
// This could happen if there is a network error or if the authorization
// is invalid.
if (clientErr) {
console.error('Error creating client:', clientErr);
return;
}
// Create a PayPal Checkout component.
braintree.paypalCheckout.create({
client: clientInstance
}, function (paypalCheckoutErr, paypalCheckoutInstance) {
// Stop if there was a problem creating PayPal Checkout.
// This could happen if there was a network error or if it's incorrectly
// configured.
if (paypalCheckoutErr) {
console.error('Error creating PayPal Checkout:', paypalCheckoutErr);
return;
}
// Load the PayPal JS SDK (see Load the PayPal JS SDK section)
});
});Load the PayPal JavaScript v5 SDK
After you create the Braintree PayPal Checkout component, use the loadPayPalSDK method to load the PayPal JavaScript SDK script file onto the page.
- Callback
- Promise
paypalCheckoutInstance.loadPayPalSDK(function (loadSDKErr) {
// The PayPal script is now loaded on the page and
// window.paypal.Buttons is now available to use
// render the PayPal button (see Render the PayPal Button section)
});You can choose to load the script tag manually:
- HTML
<!-- Load the PayPal JS SDK with your PayPal Client ID-->
<script src="https://www.paypal.com/sdk/js?client-id=your-sandbox-or-prod-client-id"></script>
<!-- Load the Braintree components -->
<script src="https://js.braintreegateway.com/web/3.139.0/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.139.0/js/paypal-checkout.min.js"></script>Replace your-sandbox-or-prod-client-id with the PayPal client ID found in the Braintree Control Panel under Settings > Account Settings > PayPal > Options > PayPal Client ID.
This ID will be different for your sandbox account and your production account.
The loadPayPalSDK method also takes an optional configuration object. Each property corresponds to the query parameters available in the PayPal JavaScript SDK.
By default, the client-id is the merchant's PayPal Client ID for the current environment, such as sandbox or production.
The other configuration options depend on whether you choose the Vault or Checkout integration option. See those pages for more details.
- Callback
- Promise
paypalCheckoutInstance.loadPayPalSDK({
// Must be set to true when using the Vault flow
// vault: true
// Defaults to USD, but must match the value used in 'createPayment'
// currency: 'USD'
}, function (loadSDKErr) {
// Render the PayPal button (see Render the PayPal Button section)
});Render the PayPal button
Next, render the PayPal button. You will need to configure the button specifically for the One-Time Payments, Vaulted Payments, or Recurring Payments integration flow, depending on the type of integration you choose in the next section.
Review the integration links in the next section to learn how to finish rendering the PayPal button.
Load the PayPal JS v6 SDK
We now support integrating the PayPal JavaScript SDK v6 through the Braintree JavaScript SDK v3 so merchants can add PayPal checkout with a single, high-level integration.
Prerequisites
- Active Braintree account
- PayPal REST app with a client ID (sandbox or live) for the merchant or platform
- HTTPS web origin where you load the Braintree Web SDK and host your checkout
- A server environment where you already create and capture orders through Braintree's backend APIs (recommended pattern)
Minimum SDK Version
| SDK | Version |
|---|---|
| PayPal JavaScript Web SDK | v6 |
@paypal/paypal-js (npm) | 9.3.0 |
Common Setup(Required for all examples)
Load the Braintree client SDK and PayPal Checkout v6 JavaScript library. These scripts are required for all PayPal v6 integrations.
- Load
<script src="https://js.braintreegateway.com/web/3.x.x/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.x.x/js/paypal-checkout-v6.min.js"></script>Automatic Environment Detection
The Braintree PayPal Checkout v6 wrapper automatically loads the correct PayPal SDK based on your Braintree environment configuration:
- Live environment: Loads the PayPal SDK from
paypal.com - Sandbox environment: Loads the PayPal SDK from
sandbox.paypal.com
This happens automatically when you call paypal.loadPayPalSDK() — no additional configuration is required. The environment is determined by the client token or authorization you provide when creating the Braintree client instance.
One-Time Payment
Basic checkout for a single purchase.
Define the PayPal trigger button that the integration will use to display transaction status or messages..
- HTML
<paypal-button type="pay" id="paypal-one-time-payment-button"></paypal-button>Initialize through a Braintree client token and create a PayPal Checkout v6 instance that will manage the PayPal JavaScript SDK and checkout flow.
- Javascript
braintree.client
.create({
authorization: "CLIENT_TOKEN",
})
.then(function (client) {
return braintree.paypalCheckoutV6.create({ client: client });
})
.then(function (paypal) {
return paypal.loadPayPalSDK().then(function () {
return paypal;
});
})
.then(function (paypal) {
var session = paypal.createOneTimePaymentSession({
amount: "10.00",
currency: "USD",
intent: "capture",
onApprove: function (data) {
return paypal
.tokenizePayment({
payerID: data.payerId,
orderID: data.orderId,
})
.then(function (payload) {
console.log("Nonce:", payload.nonce);
});
},
});
document
.getElementById("paypal-one-time-payment-button")
.addEventListener("click", function () {
session.start();
});
});Vault Flow (Save PayPal Account)
Save a PayPal account for future transactions without charging.
Define the PayPal trigger button that the integration will use to display transaction status or messages, as shown in the One Time Checkout example.
Initialize the Braintree client and PayPal Checkout v6, load the PayPal SDK, and start a billing agreement session that vaults the buyer's PayPal account through createBillingAgreementSession and tokenizePayment.
- Javascript
braintree.client
.create({
authorization: "CLIENT_TOKEN",
})
.then(function(client) {
return braintree.paypalCheckoutV6.create({ client: client });
})
.then(function(paypal) {
return paypal.loadPayPalSDK().then(function() {
return paypal;
});
})
.then(function(paypal) {
var session = paypal.createBillingAgreementSession({
billingAgreementDescription: "Save for future payments",
onApprove: function(data) {
return paypal
.tokenizePayment({
billingToken: data.billingToken,
})
.then(function(payload) {
console.log("Vaulted nonce:", payload.nonce);
});
},
});
document
.getElementById("paypal-vault-button")
.addEventListener("click", function() {
session.start();
});
});Recurring Plan Type
Fixed repeating payments on a schedule (e.g., monthly subscription).
Define the PayPal trigger button that the integration will use to display transaction status or messages, as shown in the One Time Checkout example.
Create a PayPal billing agreement for a recurring payment type using planType: 'RECURRING', have the buyer approve the agreement, then tokenize the billing agreement to charge the customer on a recurring schedule.
- Javascript
braintree.client
.create({
authorization: "CLIENT_TOKEN",
})
.then(function (client) {
return braintree.paypalCheckoutV6.create({ client: client });
})
.then(function (paypal) {
return paypal.loadPayPalSDK().then(function () {
return paypal;
});
})
.then(function (paypal) {
var session = paypal.createBillingAgreementSession({
billingAgreementDescription: "Monthly recurring subscription",
planType: "RECURRING",
amount: "29.99",
currency: "USD",
planMetadata: {
billingCycles: [
{
billingFrequency: "1",
billingFrequencyUnit: "MONTH",
numberOfExecutions: "12",
sequence: "1",
startDate: new Date(Date.now() + 86400000)
.toISOString()
.split("T")[0],
trial: false,
pricingScheme: {
pricingModel: "VARIABLE",
price: "29.99",
},
},
],
currencyIsoCode: "USD",
name: "Monthly Recurring Plan",
productDescription: "Monthly recurring subscription service",
productQuantity: "1.0",
productPrice: "29.99",
totalAmount: "29.99",
},
onApprove: function (data) {
return paypal
.tokenizePayment({ billingToken: data.billingToken })
.then(function (payload) {
console.log("Recurring nonce:", payload.nonce);
});
},
});
document
.getElementById("paypal-recurring-button")
.addEventListener("click", function () {
session.start();
});
});Subscription Plan Type
Similar to recurring but specifically for subscriptions with configurable billing cycles.
Define the PayPal trigger button that the integration will use to display transaction status or messages, as shown in the One Time Checkout example.
Create a PayPal subscription flow using planType: 'SUBSCRIPTION' where the buyer clicks a Subscribe button; manage and bill the customer on an ongoing schedule from your backend.
- Javascript
braintree.client
.create({
authorization: "CLIENT_TOKEN",
})
.then(function (client) {
return braintree.paypalCheckoutV6.create({ client: client });
})
.then(function (paypal) {
return paypal.loadPayPalSDK().then(function () {
return paypal;
});
})
.then(function (paypal) {
var session = paypal.createBillingAgreementSession({
billingAgreementDescription: "Monthly subscription for premium service",
planType: "SUBSCRIPTION",
amount: "233.00",
currency: "USD",
planMetadata: {
billingCycles: [
{
billingFrequency: "1",
billingFrequencyUnit: "MONTH",
numberOfExecutions: "3",
sequence: "1",
startDate: new Date(Date.now() + 86400000)
.toISOString()
.split("T")[0],
trial: false,
pricingScheme: {
pricingModel: "FIXED",
price: "200.00",
},
},
],
currencyIsoCode: "USD",
name: "Premium Subscription",
productDescription: "Premium Service Plan",
productQuantity: "1.0",
oneTimeFeeAmount: "10",
shippingAmount: "3.0",
productPrice: "200",
taxAmount: "20",
totalAmount: "233.00",
},
onApprove: function (data) {
return paypal
.tokenizePayment({ billingToken: data.billingToken })
.then(function (payload) {
console.log("Subscription nonce:", payload.nonce);
});
},
});
document
.getElementById("paypal-subscription-button")
.addEventListener("click", function () {
session.start();
});
});Unscheduled Plan Type
Variable / on-demand payments (e.g., pay-as-you-go services).
Define the PayPal trigger button that the integration will use to display transaction status or messages, as shown in the One Time Checkout example.
Create a billing agreement session with planType: 'UNSCHEDULED' for variable/on-demand charges, then tokenize the returned billing token so you can bill the customer whenever usage occurs.
- Javascript
braintree.client
.create({
authorization: "CLIENT_TOKEN",
})
.then(function (client) {
return braintree.paypalCheckoutV6.create({ client: client });
})
.then(function (paypal) {
return paypal.loadPayPalSDK().then(function () {
return paypal;
});
})
.then(function (paypal) {
var session = paypal.createBillingAgreementSession({
billingAgreementDescription: "Pay-as-you-go service",
planType: "UNSCHEDULED",
onApprove: function (data) {
return paypal
.tokenizePayment({ billingToken: data.billingToken })
.then(function (payload) {
console.log("Unscheduled nonce:", payload.nonce);
});
},
});
document
.getElementById("paypal-unscheduled-plan-button")
.addEventListener("click", function () {
session.start();
});
});Checkout with Vault
Charge a customer and save their PayPal account in a single flow.
Define the PayPal trigger button that the integration will use to display transaction status or messages, as shown in the One Time Checkout example.
Initialize the Braintree client and PayPal Checkout v6 instance. Create a checkout session that both processes the payment and vaults the buyer's PayPal account for future use — so merchants can charge the customer again without requiring re-approval.
- Javascript
braintree.client
.create({
authorization: "CLIENT_TOKEN",
})
.then(function (client) {
return braintree.paypalCheckoutV6.create({ client: client });
})
.then(function (paypal) {
return paypal.loadPayPalSDK().then(function () {
return paypal;
});
})
.then(function (paypal) {
var session = paypal.createCheckoutWithVaultSession({
amount: "10.00",
currency: "USD",
intent: "capture",
billingAgreementDetails: {
description: "Monthly subscription to Totally Real Products!",
},
onApprove: function (data) {
return paypalCheckoutV6Instance
.tokenizePayment({
orderID: data.orderId,
payerID: data.payerId,
})
.then(function (payload) {
console.log("Checkout with vault nonce:", payload.nonce);
});
},
});
document
.getElementById("paypal-checkout-with-vault-button")
.addEventListener("click", function () {
session.start();
});
});Line Items & Shipping Options
Itemized checkout with shipping and tax breakdown.
Define the PayPal trigger button that the integration will use to display transaction status or messages, as shown in the One Time Checkout example.
Create a one-time payment session that includes detailed line items (including a discount) and multiple shipping options, so the PayPal checkout shows a full price breakdown before the buyer approves.
- Javascript
braintree.client
.create({
authorization: "CLIENT_TOKEN",
})
.then(function (client) {
return braintree.paypalCheckoutV6.create({ client: client });
})
.then(function (paypal) {
return paypal.loadPayPalSDK().then(function () {
return paypal;
});
})
.then(function (paypal) {
var session = paypal.createOneTimePaymentSession({
amount: "40.00",
currency: "USD",
intent: "capture",
lineItems: [
{ quantity: "2", unitAmount: "15.00", name: "Widget", kind: "debit" },
{ quantity: "1", unitAmount: "10.00", name: "Gadget", kind: "debit" },
{ quantity: "1", unitAmount: "5.00", name: "Discount", kind: "credit" },
],
shippingOptions: [
{
id: "standard",
label: "Standard (5-7 days)",
selected: true,
type: "SHIPPING",
amount: { currency: "USD", value: "5.00" },
},
{
id: "express",
label: "Express (2-3 days)",
selected: false,
type: "SHIPPING",
amount: { currency: "USD", value: "12.00" },
},
],
amountBreakdown: {
itemTotal: "40.00",
shipping: "5.00",
discount: "5.00",
},
onApprove: function (data) {
return paypal
.tokenizePayment({
payerID: data.payerId,
orderID: data.orderId,
})
.then(function (payload) {
console.log("Nonce:", payload.nonce);
});
},
});
document
.getElementById("paypal-one-time-payment-button")
.addEventListener("click", function () {
session.start();
});
});Dynamic Payment Updates
Update shipping/amount when the customer changes address during checkout.
Define the PayPal trigger button that the integration will use to display transaction status or messages, as shown in the One Time Checkout example.
Create a one-time payment session that listens for onShippingAddressChange, recalculates shipping based on the buyer's new address, calls updatePayment with the new totals (including an updated amount breakdown), and then tokenizes the approved payment once checkout is complete.
- Javascript
await braintree.client
.create({
authorization: "CLIENT_TOKEN",
})
.then(function (client) {
return braintree.paypalCheckoutV6.create({ client: client });
})
.then(function (paypal) {
return paypal.loadPayPalSDK().then(function () {
return paypal;
});
})
.then(function (paypal) {
var session = paypal.createOneTimePaymentSession({
amount: "10.00",
currency: "USD",
intent: "capture",
onApprove: function (data) {
return paypal
.tokenizePayment({
payerID: data.payerId,
orderID: data.orderId,
})
.then(function (payload) {
console.log("Nonce:", payload.nonce);
});
},
onShippingAddressChange: function (data) {
var newShipping =
data.shippingAddress.city === "Chicago" ? "10.00" : "5.00";
return paypal.updatePayment({
paymentId: data.orderId,
amount: (10 + parseFloat(newShipping)).toFixed(2),
currency: "USD",
});
},
});
document
.getElementById("paypal-one-time-payment-button")
.addEventListener("click", function () {
session.start();
});
});Next: Choose your integration
The rest of your configuration will be determined by how you'd like to use PayPal.
- Want a checkout from your cart or product page? Use One-Time Payments.
- Need a combination of features and Pay Later offers? Use Vaulted Payments.
- Want one-click payments for repeat customers? Have a subscription model? Use Recurring Payments.
See a detailed comparison of One-Time Payments, Vaulted Payments, and Recurring Payments.