On this page
No Headings
Last updated: June 4, 2026
The PayPal JavaScript SDK is a client-side library that adds PayPal payment buttons and checkout to your website. Version 6 introduces a new component-based design, server-side authentication, and improved payment session management.
If you currently use v5 (or the older checkout.js), upgrading to v6 provides better performance, security, and access to PayPal's latest payment features.
You're on JavaScript SDK v5 if your website loads PayPal through a script tag with a client-id query parameter:
<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID"></script>| Feature | v5 | v6 |
|---|---|---|
| SDK script URL | https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID | https://www.sandbox.paypal.com/web-sdk/v6/core |
Global paypal object | All features are available from the global object | Call createInstance to set up the SDK |
| Authentication | Client ID in the script URL | Client ID or client token passed to createInstance |
| Button rendering | paypal.Buttons({ ... }).render() | <paypal-button> custom elements with event listeners |
| Eligibility checks | Run implicitly before each render | Call findEligibleMethods explicitly |
| Callbacks | Passed into paypal.Buttons({ ... }) | Passed into a checkout session (for example, createPayPalOneTimePaymentSession) |
| Components | All features loaded automatically | Load only the components you need |
| Venmo support | Included in smart stack automatically | Enable explicitly with the venmo-payments component |
The following steps walk you through upgrading from v5 to v6.
v5 used a script URL with client-id in the query string. v6 loads a core script with no configuration in the URL. You initialize the SDK with JavaScript after the script loads.
<!-- v5 (deprecated) -->
<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID"></script>
<!-- v6 -->
<script
async
src="https://www.sandbox.paypal.com/web-sdk/v6/core"
onload="onPayPalLoaded()"
></script>v5 included configuration in the script URL. v6 requires you to authenticate when you create the SDK instance.
Most integrations authenticate with a client ID. Authenticate with a client token if your integration includes Fastlane.
For most integrations, pass your client ID directly to createInstance:
const sdkInstance = await window.paypal.createInstance({
clientId: "YOUR_CLIENT_ID",
components: ["paypal-payments", "venmo-payments"],
pageType: "checkout",
});For Fastlane integrations only, create a server endpoint that returns a browser-safe client token.
/paypal-api/auth/browser-safe-client-token.async function getBrowserSafeClientToken() {
const response = await fetch("/paypal-api/auth/browser-safe-client-token");
const { accessToken } = await response.json(); // or { clientToken }
return accessToken; // or clientToken
}Call createInstance with the client token:
const clientToken = await getBrowserSafeClientToken();
const sdkInstance = await window.paypal.createInstance({
clientToken,
components: ["fastlane"], // or other components requiring client token
pageType: "checkout",
});v5 rendered buttons by calling paypal.Buttons({ ... }).render('#container'). In v6, you add custom HTML elements to your page and control visibility with JavaScript.
<div id="buttons">
<paypal-button id="paypal-btn" type="pay" hidden></paypal-button>
<venmo-button id="venmo-btn" type="pay" hidden></venmo-button>
</div>v5 ran eligibility checks implicitly before each render. In v6, you explicitly call findEligibleMethods to decide which buttons to show.
const methods = await sdkInstance.findEligibleMethods({ currencyCode: "USD" });
if (methods.isEligible("paypal")) {
document.getElementById("paypal-btn").hidden = false;
}
if (methods.isEligible("venmo")) {
document.getElementById("venmo-btn").hidden = false;
}In v5, createOrder and onApprove were inside paypal.Buttons({ ... }). In v6, you define them when you create a session.
const paypalSession = sdkInstance.createPayPalOneTimePaymentSession({
onApprove: async ({ orderId }) => {
// Call your server to capture the order
const response = await fetch(`/api/orders/${orderId}/capture`, {
method: "POST",
});
return response.json();
},
});
const paypalButton = document.getElementById("paypal-btn");
paypalButton.addEventListener("click", async () => {
// Create the order and get the order ID
const orderPromise = fetch("/api/orders", { method: "POST" })
.then((res) => res.json())
.then((data) => data.orderId);
// Start the checkout with the order
await paypalSession.start({ presentationMode: "auto" }, orderPromise);
});The following example shows a complete PayPal and Venmo button integration using the JavaScript SDK v6. It covers loading the SDK, checking payment method eligibility, and wiring up a one-time payment session
Load the SDK script and add custom button elements to your page. Buttons are hidden by default until eligibility checks pass.
<script
async
src="https://www.paypal.com/web-sdk/v6/core"
onload="onPayPalLoaded()"
></script>
<div id="buttons">
<paypal-button id="paypal-btn" type="pay" hidden></paypal-button>
<venmo-button id="venmo-btn" type="pay" hidden></venmo-button>
</div>Initialize the SDK, check which payment methods are eligible, and create a payment session that handles order creation and capture.
async function onPayPalLoaded() {
const clientToken = await getBrowserSafeClientToken();
const sdk = await window.paypal.createInstance({
clientToken,
components: ["paypal-payments", "venmo-payments"],
pageType: "checkout",
});
const methods = await sdk.findEligibleMethods({ currencyCode: "USD" });
if (methods.isEligible("paypal"))
document.getElementById("paypal-btn").hidden = false;
if (methods.isEligible("venmo"))
document.getElementById("venmo-btn").hidden = false;
async function createOrder() {
// call your server, return order id
}
async function captureOrder({ orderId }) {
// call your server to capture
}
const paypalSession = sdk.createPayPalOneTimePaymentSession({
onApprove: captureOrder,
onCancel: () => {},
onError: (e) => console.error(e),
});
document.getElementById("paypal-btn").addEventListener("click", async () => {
await paypalSession.start({ presentationMode: "auto" }, createOrder());
});
}
async function getBrowserSafeClientToken() {
const res = await fetch("/paypal-api/auth/browser-safe-client-token");
const { accessToken } = await res.json(); // or { clientToken }
return accessToken; // or clientToken
}Before going live, test your integration in the sandbox environment.
See Move your app to production for more details.
Troubleshoot common errors that you might encounter when upgrading from v5 to v6.
If window.paypal.createInstance is undefined, the core script has not finished loading. Make sure your initialization code runs inside the onload callback on the script tag. Do not run it inline or in a DOMContentLoaded handler.
v6 buttons are hidden by default. If nothing shows on your page, check these items:
findEligibleMethods returns the expected payment methods.hidden attribute from the button.findEligibleMethods after the SDK instance is fully initialized.If your /paypal-api/auth/browser-safe-client-token endpoint returns a 401 error, check your server credentials. Common causes:
createOrder does not return an order IDIn v5, createOrder returned a value directly to the button config. In v6, the order ID Promise is passed to session.start() as the second argument; it's not returned from createOrder itself. Pass createOrder() (the invoked function, returning a Promise) as the second argument to start(), not createOrder (a bare function reference).