> For the complete documentation index, see [llms.txt](https://developer.paddle.com/llms.txt).

# Build an overlay checkout

Get a step-by-step overview of how to build a complete overlay checkout — including initializing Paddle.js, passing settings and items, prefilling customer information, and next steps.

---

The checkout is where customers make purchases. For SaaS businesses, it's the process where customers enter their details and payment information, and confirm that they'd like to sign up for a subscription with you.

You can use [Paddle.js](https://developer.paddle.com/paddlejs/overview.md) to quickly add an overlay checkout into your app. [Overlay checkout](https://developer.paddle.com/concepts/sell/overlay-checkout.md) lets you present customers with an overlay that handles all parts of the checkout process — minimal frontend coding required.

[Explore the code for this tutorial and test right away using our overlay checkout pen.](https://codepen.io/heymcgovern/pen/wvZMmGq)

## What are we building?

In this tutorial, we'll launch a multi-page overlay checkout for two items in our product catalog, then we'll extend it by passing customer information.

We'll learn how to:

- Include and set up Paddle.js using a client-side token
- Pass items to overlay checkout using `Paddle.Checkout.open()` or HTML data attributes
- Take a test payment
- Prefill customer information using `Paddle.Checkout.open()` or HTML data attributes

If you like, you can [view on CodePen](https://codepen.io/heymcgovern/pen/wvZMmGq) and follow along.

## Before you begin

### Choose a checkout implementation

This tutorial walks through creating an [overlay checkout](https://developer.paddle.com/concepts/sell/overlay-checkout.md). You can also create [inline checkouts](https://developer.paddle.com/concepts/sell/branded-integrated-inline-checkout.md), which lets you build Paddle Checkout right into your app or website.

We recommend building an overlay checkout if you're new to Paddle. Inline checkouts use the same JavaScript methods as overlay checkouts, so you can switch to an inline checkout later.

{% collapsible title="Types of checkout" %}

{% feature-comparison level=4 %}

{% feature-column title="Overlay checkout" %}

{% feature-item %}
Integrate Paddle in just a few lines of code. Launches an overlay to capture payment.
{% /feature-item %}

{% feature-item %}
Quick to set up: add Paddle.js to your site and call `Paddle.Checkout.open()` or use `data-*` HTML attributes to launch the checkout.
{% /feature-item %}

{% feature-item %}
Checkout opens as a modal overlay on top of your page, focusing the user on payment.
{% /feature-item %}

{% feature-item %}
Customize colors, logo, and branding in the Paddle dashboard. Structure and experience is managed by Paddle.
{% /feature-item %}

{% /feature-column %}

{% feature-column title="Inline checkout" %}

{% feature-item %}
Get complete control of the checkout experience. Captures payment directly in your app.
{% /feature-item %}

{% feature-item %}
Embed Paddle Checkout directly into your page layout. Use a container element and set `displayMode` to `inline`.
{% /feature-item %}

{% feature-item %}
Checkout form is part of your page flow—lets you create fully integrated or branded payment experiences.
{% /feature-item %}

{% feature-item %}
Full control over surrounding layout and styling; you can design the context and surrounding UX.
{% /feature-item %}

{% /feature-column %}

{% /feature-comparison %}

To learn more about the differences between overlay and inline checkouts, see [Paddle Checkout](https://developer.paddle.com/concepts/sell/self-serve-checkout.md)

{% /collapsible %}

### Create products and prices

Paddle Checkout works with products and prices to say what a customer is purchasing, so you'll need to [create a product and at least one related price](https://developer.paddle.com/build/checkout/build-branded-inline-checkout.md) to pass to your checkout.

### Set your default payment link

You'll also need to:

- [Set your default payment link](https://developer.paddle.com/build/transactions/default-payment-link.md) under **Paddle > Checkout > Checkout settings > Default payment link**.
- Get your default payment link domain approved, if you're working with the live environment.

## Overview

Add an overlay checkout to your website or app in four steps:

1. [**Include and initialize Paddle.js**](#include-paddle-js)  
   Add Paddle.js to your app or website, so you can securely capture payment information and build subscription billing experiences.
2. [**Add an overlay checkout button**](#add-checkout-launcher)  
   Set any element on your page as a launcher for Paddle Checkout.
3. [**Take a test payment**](#test-payment)  
   Make sure that your checkout loads successfully, then take a test payment.
4. [**Prefill customer information**](#prefill-customer) {% badge label="Optional" variant="outline" /%}  
   Extend your checkout by prefilling customer and address information.

## Include and initialize Paddle.js {% step=true %}

[Paddle.js](https://developer.paddle.com/paddlejs/overview.md) is a lightweight JavaScript library that lets you build rich, integrated subscription billing experiences using Paddle. We can use Paddle.js to securely work with products and prices in our Paddle system, as well as opening checkouts and capturing payment information.

### Include Paddle.js script

Start with a blank webpage, or an existing page on your website. Then, [include Paddle.js](https://developer.paddle.com/paddlejs/include-paddlejs.md) by adding this script to the `<head>`:

```html
<script src="https://cdn.paddle.com/paddle/v2/paddle.js"></script>
```

### Set environment {% badge label="Optional" /%}

We recommend [signing up for a sandbox account](https://sandbox-login.paddle.com/signup?utm_source=dx&utm_medium=dev-docs) to test and build your integration, then switching to a live account later when you're ready to go live.

If you're testing with the [sandbox](https://developer.paddle.com/sdks/sandbox.md), call [`Paddle.Environment.set()`](https://developer.paddle.com/paddlejs/methods/paddle-environment-set.md) and set your environment to `sandbox`:

```html {% highlightLines="3" %}
<script src="https://cdn.paddle.com/paddle/v2/paddle.js"></script>
<script type="text/javascript">
  Paddle.Environment.set("sandbox");
</script>
```

### Pass a client-side token

Next, go to **Paddle > Developer tools > Authentication** and create a client-side token. [Client-side tokens](https://developer.paddle.com/paddlejs/client-side-tokens.md) let you interact with the Paddle platform in frontend code, like webpages or mobile apps. They have limited access to the data in your system, so they're safe to publish.

In your page, call [`Paddle.Initialize()`](https://developer.paddle.com/paddlejs/methods/paddle-initialize.md) and pass your client-side token as `token`. For best performance, do this just after calling `Paddle.Environment.set()`, like this:

```html {% highlightLines="3-5" %}
<script src="https://cdn.paddle.com/paddle/v2/paddle.js"></script>
<script type="text/javascript">
  Paddle.Environment.set("sandbox");
  Paddle.Initialize({ 
    token: "test_7d279f61a3499fed520f7cd8c08" // replace with a client-side token
  });
</script>
```

## Add an overlay checkout button {% step=true %}

Next, we'll set an element on our page as a launcher for our overlay checkout. Overlay checkout works by presenting an overlay to handle the entire checkout process. When our button or other launcher element is clicked, Paddle.js launches a checkout for us.

### Create checkout button element

Any element can be a launcher for an overlay checkout. In our sample, we're using a link (`<a>`) that points to `#`. This means it doesn't open a new page.

```html
<a href='#'>Sign up now</a>
```

### Set as a checkout launcher

Next, we'll make our checkout element open an overlay checkout by making it a launcher.

Paddle.js comes with the [`Paddle.Checkout.open()`](https://developer.paddle.com/paddlejs/methods/paddle-checkout-open.md) method, which lets you open a checkout with [settings](https://developer.paddle.com/build/checkout/set-up-checkout-default-settings.md), [items](https://developer.paddle.com/build/checkout/pass-update-checkout-items.md), and [customer](https://developer.paddle.com/build/checkout/prefill-checkout-properties.md) information.

In our sample, we've created a function called `openCheckout()` to open a checkout. Here's how it works:

1. We create a variable called `itemsList` and pass an array of objects, where each object contains a `priceId` and `quantity`.
2. We create a function called `openCheckout()` that takes a parameter called `items`.
3. In our `openCheckout()` function, we call `Paddle.Checkout.open()`, passing the value of `items` as the items list for the checkout.
4. We add an `onclick` event to our checkout button to call `openCheckout()` when clicked, passing our `itemsList` variable as a parameter.

{% callout type="info" %}
Recurring items on a checkout must have the same billing interval. For example, you can't have a checkout with some prices that are billed monthly and some products that are billed annually.
{% /callout %}

```html {% highlightLines="7-32" collapse=true %}
<script type="text/javascript">
  Paddle.Environment.set("sandbox");
  Paddle.Initialize({
    token: "test_7d279f61a3499fed520f7cd8c08" // replace with a client-side token
  });
  
  // define items
  let itemsList = [
    {
      priceId: "pri_01gsz8ntc6z7npqqp6j4ys0w1w",
      quantity: 5
    },
    {
      priceId: "pri_01h1vjfevh5etwq3rb416a23h2",
      quantity: 1
    }
  ];
  
  // open checkout
  function openCheckout(items){
    Paddle.Checkout.open({
      items: items
    });
  }
</script>

<a href="#" onclick="openCheckout(itemsList)"><b>Sign up now</b></a>
```

## Take a test payment {% step=true %}

We're now ready to test. Save your page, then open it in your browser. Click on your "Sign up now" button and Paddle.js should open an overlay checkout for the items that we passed.

If you're using a sandbox account, you can take a test payment using [our test card details](https://developer.paddle.com/concepts/payment-methods/credit-debit-card.md):

{% definition-list %}
{% definition term="Email address" %}
An email address you own
{% /definition %}
{% definition term="Country" %}
Any valid country supported by Paddle
{% /definition %}
{% definition term="ZIP code (if required)" %}
Any valid ZIP or postal code
{% /definition %}
{% definition term="Card number" %}
`4242 4242 4242 4242`
{% /definition %}
{% definition term="Name on card" %}
Any name
{% /definition %}
{% definition term="Expiration date" %}
Any valid date in the future.
{% /definition %}
{% definition term="Security code" %}
`100`
{% /definition %}
{% /definition-list %}

{% collapsible title="Checkout not working?" %}

If the checkout doesn't appear, or you get a message saying "Something went wrong," you can open your browser console to see any specific error messages from Paddle.js to help you troubleshoot.

{% callout type="info" %}
Use `⌘ Command` + `⌥ Option` + `J` (Mac) or `Ctrl` + `⇧ Shift` + `J` (Windows) to quickly open your browser console in Google Chrome.
{% /callout %}

#### Common problems

Check that:

- You added a default payment link to your checkout under **Paddle > Checkout > Checkout settings > Default payment link**, and that this matches the domain where you're testing. You can use `localhost` if you're testing locally on sandbox.
- You included Paddle.js correctly. If you're moving from Paddle Classic, the CDN URL has changed.
- Your client-side token is correct and passed to `Paddle.Initialize()`.
- You set the correct environment.
- The Paddle IDs for price entities that you passed are correct. Sandbox and live systems are separate, so make sure you're passing price IDs for the environment that you're working in.
- If you're using HTML data attributes, you used single quotation marks around the value of `data-items`, and double quotation marks around the property names and string values inside it

{% /collapsible %}

## Prefill customer information {% step=true badge="Optional" %}

At this point, we've passed items to our checkout. When we click our launcher, Paddle opens a checkout for the items that we passed.

Paddle.js also lets you [pass customer information to a checkout](https://developer.paddle.com/build/checkout/prefill-checkout-properties.md). When we click our launcher, Paddle opens a checkout with the customer information prefilled. This means the first page of checkout is skipped entirely, so customers land on a screen where they can enter their payment information.

{% callout type="note" %}
You can present customers with a one-page checkout experience by passing `variant` with the value `one-page` [as a checkout setting](https://developer.paddle.com/build/checkout/set-up-checkout-default-settings.md). You don't need to prefill information.
{% /callout %}

[`Paddle.Checkout.open()`](https://developer.paddle.com/paddlejs/methods/paddle-checkout-open.md) takes a `customer` parameter, which lets you pass customer and address information.

In our sample, we've extended our `openCheckout()` function so that it passes customer and address information to our checkout. Here's what's going on:

1. We create a variable called `customerInfo`, with an `email` key and an object for `address`. You may also pass Paddle IDs for an existing customer or address here.
2. We update our `openCheckout()` function so it takes another parameter called `customer`.
3. In our `openCheckout()` function, we added the `customer` parameter and passing the value of `customer` to this.
4. We updated the `onClick` event on our checkout button to pass our `customerInfo` variable as the parameter for `customer`.

```html {% highlightLines="19-32" collapse=true %}
<script type="text/javascript">
  Paddle.Environment.set("sandbox");
  Paddle.Initialize({
    token: "test_7d279f61a3499fed520f7cd8c08" // replace with a client-side token
  });
  
  // define items
  let itemsList = [
    {
      priceId: "pri_01gsz8ntc6z7npqqp6j4ys0w1w",
      quantity: 5
    },
    {
      priceId: "pri_01h1vjfevh5etwq3rb416a23h2",
      quantity: 1
    }
  ];
  
  // define customer details
  let customerInfo = {
    email: "sam@example.com",
    address: {
      countryCode: "US", 
      postalCode: "10021"
    }
  }
  
  // open checkout
  function openCheckout(items, customer){
    Paddle.Checkout.open({
      items: items,
      customer: customer
    });
  }
</script>

<a href="#" onclick="openCheckout(itemsList, customerInfo)"><b>Sign up now</b></a>
```

### Test your work

Save your page, then open it in your browser. Click on your "Sign up now" button and Paddle.js should open an overlay checkout with the customer information prefilled. You should land on the second screen, ready to enter payment information.

{% collapsible title="Checkout not working?" %}

Where there's a problem passing optional information to a checkout, Paddle.js opens the checkout but emits a [`checkout.warning`](https://developer.paddle.com/paddlejs/general/checkout-warning.md) event. This means customers are always able to complete a purchase provided you've initialized Paddle.js and passed items successfully.

You can use the `eventCallback` parameter for [`Paddle.Initialize()`](https://developer.paddle.com/paddlejs/methods/paddle-initialize.md) to work with events emitted by Paddle.js. To print events emitted by Paddle.js to the console, update your `Paddle.Initialize()` function so it looks like this.

```javascript highlightLines="4-6"
Paddle.Initialize({
  token: "test_7d279f61a3499fed520f7cd8c08", // replace with a client-side token
  // prints events to console for debugging
  eventCallback: function(data) {
    console.log(data);
  }
});
```

Then, open your browser console and check for events with the name [`checkout.warning`](https://developer.paddle.com/paddlejs/general/checkout-warning.md). They should tell you what the problem is.

{% callout type="info" %}
Use `⌘ Command` + `⌥ Option` + `J` (Mac) or `Ctrl` + `⇧ Shift` + `J` (Windows) to quickly open your browser console in Google Chrome.
{% /callout %}

#### Common problems

Check that:

- The email address that you passed is formatted correctly. Email addresses must not include spaces or non-ASCII characters.
- If you passed an address country, you also passed a ZIP/postal code if the country requires it. Most countries don't require a ZIP/postal code, but it's [required in some places](https://developer.paddle.com/concepts/sell/supported-countries-locales.md) for tax calculation and fraud prevention.
- The Paddle IDs for customer, address, or business entities that you passed are correct. Sandbox and live systems are separate, so make sure you're passing Paddle IDs for the environment that you're working in.

{% /collapsible %}

## Next steps

That's it. Now you've built a checkout, you might like to extend Paddle Checkout by automatically applying a discount, passing optional checkout settings, or building a success workflow.

### Automatically apply a discount

Extend your checkout by passing a discount. When we click our launcher, Paddle opens a checkout with the discount automatically applied (where it's valid).

{% card-group cols=2 %}
{% card title="Prefill checkout properties" url="/build/checkout/prefill-checkout-properties" %}
Learn how to pass customer or business info (like email, name, or address) to Paddle Checkout.
{% /card %}
{% card title="Create or update a discount" url="/build/products/offer-discounts-promotions-coupons" %}
Set up and manage discount codes or time-limited promotions for your products.
{% /card %}
{% /card-group %}

### Pass checkout settings

You don't need to pass checkout settings when working with overlay checkout, but you can use them to give you more control over how opened checkouts work. For example, you can set the language that Paddle Checkout uses, hide the option to add a discount, or restrict payment methods shown to customers.

{% card-group cols=2 %}
{% card title="Pass checkout settings" url="/build/checkout/set-up-checkout-default-settings" %}
See all the settings you can pass to configure your overlay checkout.
{% /card %}
{% card title="Paddle.Checkout.open() method" url="/paddlejs/methods/paddle-checkout-open" %}
Full API documentation for opening and customizing checkouts.
{% /card %}
{% /card-group %}

### Build a success workflow

When customers complete checkout, Paddle Checkout has a final screen that lets customers know that their purchase was successful. If you like, you can redirect customers to your own page or use JavaScript event callbacks to build a more advanced success workflow.

{% card-group cols=2 %}
{% card title="Handle checkout success" url="/build/checkout/handle-success-post-checkout" %}
Redirect customers or add logic to handle post-checkout workflows.
{% /card %}
{% card title="Paddle.js events reference" url="/paddlejs/events/overview" %}
See all of the events you can listen to for customizing your checkout experience.
{% /card %}
{% /card-group %}