# Upgrade to Pay Later v6 (/pay-later/upgrade)

Upgrade your Pay Later messaging integration from the PayPal JavaScript SDK v5 to v6 using the new modular architecture, custom web components, and flexible configuration options.



Use this guide to upgrade your existing Pay Later messaging integration to the JavaScript SDK v6 to use modular components, a custom `<paypal-message>` web component, and flexible configuration patterns.

> **Tip:** You can upgrade Pay Later messaging independently. You do not need to upgrade other PayPal components, such as PayPal Checkout, before you upgrade Pay Later messaging.

## What's changing [#whats-changing]

**This upgrade is recommended.** SDK v5 continues to receive security patches but no new features. PayPal has not announced a sunset date.

**What's new in v6:**

* **Modular component loading:** Load only the `paypal-messages` component instead of bundling all SDK features. This can result in smaller payloads and faster page rendering.
* **Custom web component:** The new `<paypal-message>` Lit-based element replaces the v5 `data-pp-message` div pattern, providing improved lifecycle visibility, encapsulation from the containing page, and auto-bootstrap support.
* **Flexible authentication:** Choose between a client ID passed directly to `createInstance()` (no server-side setup) or a server-generated client token, depending on your integration needs.
* **Built-in caching:** Support for local, CDN, and site caching can help deliver faster content visibility and distinguishes between cached and fresh content through separate `onTemplateReady` and `onContentReady` callbacks.
* **Additional configuration options:** Customize logo types, text sizes, logo positions, offer types, presentation modes, and caching types through HTML attributes, JavaScript, or both.

## Before you begin [#before-you-begin]

Review these prerequisites and compatibility notes before you start the migration.

### Am I affected? [#am-i-affected]

This upgrade applies to you if:

* Your page loads the PayPal SDK using a `<script>` tag with a `client-id` query parameter in the URL (for example, `sdk/js?client-id=CLIENT_ID&components=messages`).
* Your integration uses `paypal.Messages()` or a `div` with the `data-pp-message` attribute to render Pay Later messages.

This upgrade does **not** apply if:

* You already use `https://www.paypal.com/web-sdk/v6/core` as your SDK script source.
* You use a third-party platform or plugin that manages the SDK version for you (check with your platform provider).

**How to check your current version:** Open your browser DevTools, go to the **Network** tab, and look for the SDK script URL. If it contains `sdk/js?client-id=`, you are on v5.

### Prerequisites [#prerequisites]

* A PayPal **client ID** from the [PayPal Developer Dashboard](https://developer.paypal.com/dashboard/applications). If you already have one from your v5 integration, you can reuse it.
* Access to your website's HTML and JavaScript source files.
* A staging or development environment to test the upgrade before you go live.

### Compatibility notes [#compatibility-notes]

**Unchanged:**

* Pay Later eligibility rules and offer types remain the same across SDK versions.
* Sandbox and live environments work with the same client ID you already use.
* All currently supported Pay Later offer types are available in v6.

**Deprecated but still works:**

* The `paypal.Messages()` JavaScript interface from v5 is not available in v6. Replace it with `createPayPalMessages()` and `fetchContent()`. No grace period has been announced.

**Removed:**

* The `data-pp-message` attribute on `div` elements is removed in v6. Use the `<paypal-message>` custom element instead.
* The query-parameter-based script URL (`sdk/js?client-id=...&components=messages`) is replaced by the modular v6 core script (`/web-sdk/v6/core`).

## Upgrade steps [#upgrade-steps]

Complete the following steps to update your Pay Later messaging integration from v5 to v6.

### Step 1. Replace the SDK script tag and initialize the SDK [#step-1-replace-the-sdk-script-tag-and-initialize-the-sdk]

The v5 SDK loads through a single script tag with your client ID and component list as URL query parameters. In v6, the SDK uses a separate core script and initializes components through JavaScript.

**What changes:**

* Script URL changes from `sdk/js?client-id=CLIENT_ID&components=messages` to `/web-sdk/v6/core`.
* Component loading moves from URL query parameters to the `components` array in `createInstance()`.
* Authentication moves from the script URL to the `createInstance()` configuration object.

Old (v5)

New (v6)

New (v6) - Initialize

```html
<script
  src="https://www.sandbox.paypal.com/sdk/js?client-id=CLIENT_ID&components=messages,buttons"
  data-namespace="PayPalSDK">
</script>
```

```html
<head>
  <script
    async
    src="https://www.sandbox.paypal.com/web-sdk/v6/core"
    onload="onPayPalWebSdkLoaded()">
  </script>
</head>
```

```javascript
async function onPayPalWebSdkLoaded() {
  try {
    const sdkInstance = await window.paypal.createInstance({
      clientId: "YOUR_CLIENT_ID",
      components: ["paypal-messages"],
    });
  } catch (error) {
    console.error(error);
  }
}
```

If you use a server-generated client token instead of a client ID, pass `clientToken` in place of `clientId`:

```javascript
const sdkInstance = await window.paypal.createInstance({
  clientToken: "YOUR_SERVER_GENERATED_TOKEN",
  components: ["paypal-messages"],
});
```

> **Note:** If you already upgraded the core SDK using the 
>
> [general SDK v5-to-v6 upgrade guide](/v5-v6)
>
> , you only need to add 
>
> `"paypal-messages"`
>
>  to your existing 
>
> `components`
>
>  array.

### Step 2. Replace the message container element [#step-2-replace-the-message-container-element]

In v5, you rendered Pay Later messages using a `div` with the `data-pp-message` attribute, or by calling `paypal.Messages().render()` in JavaScript. In v6, you use the `<paypal-message>` custom HTML element.

**What changes:**

* The `div` with `data-pp-message` attribute is replaced by the `<paypal-message>` custom element.
* Configuration attributes use new names (for example, `logo-type` instead of the v5 style object).
* The `auto-bootstrap` attribute simplifies initialization by handling content fetching automatically.

Old (v5)

New (v6)

```html
<div data-pp-message
  data-pp-amount="300.00"
  data-pp-style-logo-type="primary"
  data-pp-style-text-color="black">
</div>
```

```html
<paypal-message
  auto-bootstrap
  amount="300.00"
  currency-code="USD"
  logo-type="MONOGRAM"
  text-color="BLACK">
</paypal-message>
```

The `<paypal-message>` element renders as invisible until the SDK fills it with content. If you set `auto-bootstrap`, PayPal's data layer automatically picks up the component and fetches content without additional JavaScript. If you omit `auto-bootstrap`, call `fetchContent()` manually in Step 3.

### Step 3. Replace the message rendering logic [#step-3-replace-the-message-rendering-logic]

In v5, you called `paypal.Messages().render()` to render the message into a target element. In v6, you create a `PayPalMessages` instance and either rely on `auto-bootstrap` or call `fetchContent()` to retrieve and show message content.

**What changes:**

* `paypal.Messages({...}).render('#container')` is replaced by `sdkInstance.createPayPalMessages()` and `fetchContent()`.
* Rendering callbacks change from v5's render promise to v6's `onReady`, `onTemplateReady`, and `onContentReady` callbacks.
* Dynamic amount updates change from re-rendering to `content.update()` or `setAttribute()`.

Old (v5)

```javascript
paypal.Messages({
  amount: 300.00,
  placement: 'product',
  style: {
    layout: 'text',
    logo: { type: 'primary', position: 'left' },
    text: { color: 'black', size: 12 }
  }
}).render('#pay-later-message');
```

#### New (v6) - HTML config (auto-bootstrap)

```html
<paypal-message
  auto-bootstrap
  amount="300.00"
  logo-type="MONOGRAM"
  text-color="BLACK">
</paypal-message>
```

```javascript
// After SDK initialization from Step 1
const messagesInstance = sdkInstance.createPayPalMessages({
  currencyCode: "USD",
});
```

With `auto-bootstrap`, no additional `fetchContent()` call is required. The SDK handles content fetching automatically.

#### New (v6) - JS config (no auto-bootstrap)

```html
<paypal-message></paypal-message>
```

```javascript
const messagesInstance = sdkInstance.createPayPalMessages({
  currencyCode: "USD",
});

const messageElement = document.querySelector('paypal-message');

const content = await messagesInstance.fetchContent({
  amount: "300.00",
  logoType: "MONOGRAM",
  textColor: "BLACK",
  onReady: (content) => messageElement.setContent(content),
});
```

#### New (v6) - Hybrid config

If you prefer to set some options in HTML and others in JavaScript, use `getFetchContentOptions()` to bridge the two:

```html
<paypal-message amount="300.00"></paypal-message>
```

```javascript
const messageElement = document.querySelector('paypal-message');

const content = await messagesInstance.fetchContent({
  ...messageElement.getFetchContentOptions(),
  logoType: "MONOGRAM",
  textColor: "BLACK",
  onReady: (content) => messageElement.setContent(content),
});
```

### Step 4. Update dynamic amount handling [#step-4-update-dynamic-amount-handling]

If your v5 integration updates the message when the cart total changes, update your amount-change logic to use the v6 pattern.

**What changes:**

* v5 required re-rendering the entire message component to update the amount.
* v6 uses `setAttribute()` (HTML configuration) or `content.update()` (JavaScript configuration) for in-place updates without full re-renders.

Old (v5)

```javascript
// Re-render the entire message with a new amount
paypal.Messages({
  amount: newAmount,
  placement: 'product',
  style: { layout: 'text', logo: { type: 'primary' } }
}).render('#pay-later-message');
```

#### New (v6) - HTML config

```javascript
function updateMessageAmount(newAmount) {
  const messageElement = document.querySelector('paypal-message');
  messageElement.setAttribute('amount', newAmount);
}

quantityInput.addEventListener('change', (event) => {
  const newAmount = calculateTotal(event.target.value);
  updateMessageAmount(newAmount);
});
```

#### New (v6) - JS config

```javascript
function updateMessageAmount(newAmount) {
  content.update({ amount: newAmount });
}

quantityInput.addEventListener('change', (event) => {
  const newAmount = calculateTotal(event.target.value);
  updateMessageAmount(newAmount);
});
```

### Step 5. Update Learn More handling (if applicable) [#step-5-update-learn-more-handling-if-applicable]

If your v5 integration includes a Learn More modal, update it to use the v6 `createLearnMore()` method.

**What changes:**

* v5 handled Learn More automatically through `paypal.Messages()`. No separate setup was needed.
* v6 requires explicit `createLearnMore()` initialization and an event listener on the `<paypal-message>` element.

Old (v5)

New (v6)

```javascript
// In v5, Learn More was built into paypal.Messages() -- no separate code needed
paypal.Messages({
  amount: 300.00,
  style: { layout: 'text' }
}).render('#pay-later-message');
// Clicking the message automatically opened the Learn More modal
```

```javascript
// Create the Learn More instance with a presentation mode
const learnMore = await messagesInstance.createLearnMore({
  presentationMode: "MODAL", // Options: AUTO, MODAL, POPUP, REDIRECT
});

// Listen for message clicks and open Learn More
const messageElement = document.querySelector('paypal-message');
messageElement.addEventListener('paypal-message-click', (event) => {
  event.preventDefault();
  learnMore.open(event.detail.config);
});
```

If you use `auto-bootstrap`, Learn More opens automatically when a shopper selects the message. You only need explicit `createLearnMore()` if you want to customize the presentation mode or add callbacks like `onShow`, `onApply`, or `onClose`.

## End-to-end example [#end-to-end-example]

After you complete all the steps, a fully upgraded integration using the HTML configuration pattern looks like this:

```html
<head>
  <script
    async
    src="https://www.sandbox.paypal.com/web-sdk/v6/core"
    onload="onPayPalWebSdkLoaded()">
  </script>
</head>
<body>
  <paypal-message
    auto-bootstrap
    amount="300.00"
    logo-type="MONOGRAM"
    text-color="MONOCHROME">
  </paypal-message>

  <script>
    async function onPayPalWebSdkLoaded() {
      try {
        const sdkInstance = await window.paypal.createInstance({
          clientId: "YOUR_CLIENT_ID",
          components: ["paypal-messages"],
        });

        const messagesInstance = sdkInstance.createPayPalMessages({
          currencyCode: "USD",
        });

        // Update amount when cart changes
        function triggerAmountUpdate(amount) {
          const messageElement = document.querySelector('paypal-message');
          messageElement.setAttribute('amount', amount);
        }

        // Optional: customize Learn More presentation
        const learnMore = await messagesInstance.createLearnMore({
          presentationMode: "POPUP",
        });

        const messageElement = document.querySelector('paypal-message');
        messageElement.addEventListener('paypal-message-click', (event) => {
          event.preventDefault();
          learnMore.open(event.detail.config);
        });

      } catch (error) {
        console.error(error);
      }
    }
  </script>
</body>
```

## Verify the upgrade [#verify-the-upgrade]

After you complete the steps, run these scenarios in the PayPal sandbox to confirm the upgrade works.

### Message renders with correct content [#message-renders-with-correct-content]

1. Open your page in a browser and navigate to a product or cart page where the Pay Later message should appear.
2. Open DevTools (**F12**) and check the **Network** tab for requests to `https://www.sandbox.paypal.com/web-sdk/v6/core` and `https://www.sandbox.paypal.com/web-sdk/v6/paypal-messages`.
3. Verify that the `<paypal-message>` element is visible on the page with a financing message (for example, "Pay in 4 payments of $75.00"). Actual messaging and terms depend on buyer eligibility and approval.
4. Change the cart amount and confirm the message updates to reflect the new installment calculation.

**Expected outcome:** The Pay Later message shows the correct installment amount. Changing the cart total updates the message without a full page reload. Both SDK network requests return HTTP `200 OK` status codes.

### SDK version is v6, not v5 [#sdk-version-is-v6-not-v5]

1. Open DevTools and go to the **Network** tab.
2. Search for `sdk/js` in the network request list.
3. Confirm there are **no** requests to the v5 URL pattern `sdk/js?client-id=`.
4. Confirm there **is** a request to `web-sdk/v6/core`.
5. In the **Console** tab, type `window.paypal` and verify `createInstance` is a function (this method only exists in v6).

**Expected outcome:** No v5 SDK script loads. The v6 core script loads successfully. `window.paypal.createInstance` is defined as a function.

### Learn More opens from the message [#learn-more-opens-from-the-message]

1. Select the Pay Later message text on the page.
2. Verify that a Learn More overlay (modal, popup, or redirect based on your `presentationMode` setting) opens with financing details.
3. Close the overlay and confirm the page state is unchanged.

**Expected outcome:** Selecting the message opens a Learn More presentation showing financing options. The presentation mode matches your configuration (`MODAL`, `POPUP`, or `REDIRECT`). Closing the overlay returns focus to the page without errors in the console.

## Troubleshooting and rollback [#troubleshooting-and-rollback]

If you encounter issues after upgrading, use the solutions in this section to diagnose and resolve them, or roll back to v5.

### Common issues [#common-issues]

**The Pay Later message does not appear on the page**

**Cause:** The SDK script failed to load, the `<paypal-message>` element is missing, or the client ID is invalid.

**Fix:**

1. Open DevTools and check the **Network** tab for failed requests to `web-sdk/v6/core`.
2. Check the **Console** tab for JavaScript errors.
3. Verify the `<paypal-message>` element exists in the DOM.
4. Confirm your `clientId` is correct in `createInstance()`.
5. Confirm the page is served over HTTPS. Messages do not render on HTTP pages.

**The message renders but does not update when the cart amount changes**

**Cause:** The amount update method does not match the configuration pattern.

**Fix:** If you use `auto-bootstrap`, update the amount using `messageElement.setAttribute('amount', newAmount)`. If you use the JavaScript configuration, update using `content.update({ amount: newAmount })`. Do not mix the two approaches.

**The Learn More modal does not open when the message is clicked**

**Cause:** The `createLearnMore()` instance was not created, or the click event listener is missing.

**Fix:**

1. Verify you called `messagesInstance.createLearnMore()` after creating the messages instance.
2. Verify the event listener is attached: `messageElement.addEventListener('paypal-message-click', ...)`.
3. Verify `event.preventDefault()` is called inside the listener. Without it, the browser may navigate instead of opening Learn More.

**Console error: window.paypal.createInstance is not a function**

**Cause:** The v5 SDK script is loading instead of v6, or the v6 core script has not finished loading.

**Fix:** Check your HTML for any remaining v5 `<script>` tags that reference `sdk/js?client-id=`. Remove them and verify only the v6 core script (`/web-sdk/v6/core`) is present. Ensure your initialization code runs inside the `onload` callback.

**Console error: paypal-messages component not found**

**Cause:** The `"paypal-messages"` string is missing from the `components` array in `createInstance()`.

**Fix:** Add `"paypal-messages"` to your components list:

```javascript
const sdkInstance = await window.paypal.createInstance({
  clientId: "YOUR_CLIENT_ID",
  components: ["paypal-messages"],
});
```

### Rollback [#rollback]

You can typically roll back to v5 while v5 remains supported. If you need to revert:

1. Replace the v6 core script tag with your original v5 script tag:
   ```html
   <script src="https://www.sandbox.paypal.com/sdk/js?client-id=CLIENT_ID&components=messages"></script>
   ```
2. Replace the `<paypal-message>` element with your original `div` using the `data-pp-message` attribute.
3. Replace the v6 JavaScript initialization (`createInstance`, `createPayPalMessages`, `fetchContent`) with your original `paypal.Messages().render()` calls.
4. Deploy and verify the v5 messages render correctly.

> **Warning:** Both SDK versions can coexist during a staged rollout if they use different pages, but do not load both v5 and v6 scripts on the same page.

## Next steps [#next-steps]

* [Go-live checklist](./reference#checklist-before-going-live). Verify your deployment before launch.
* [Pay Later integration guide](./integrate). Full v6 integration reference with all configuration options, styling examples, and analytics setup.

## See also [#see-also]

* [Pay Later integration guide](./integrate). Complete v6 integration documentation.
* [JavaScript SDK v5 to v6 upgrade guide](/v5-v6). Upgrade all SDK components, not only Pay Later messaging.
* [PayPal Developer Dashboard](https://developer.paypal.com/dashboard/applications). Manage your client ID and credentials.
* [PayPal User Agreement](https://www.paypal.com/us/legalhub/useragreement-full). Review the terms that apply to your PayPal account and integrations.
* [PayPal Privacy Statement](https://www.paypal.com/us/legalhub/privacy-full). Learn how PayPal handles personal data.
