Paddle Billing

Build a pricing page

Get a step-by-step overview of how to build a pricing page that displays localized prices, including taxes and discount calculation. Open a checkout when a prospect wants to sign up.

Pricing pages show prospects the subscription plans, addons, or one-time charges that you sell and how much they cost. They're one of the most important pages on your website, and typically play a key part in customer conversion.

You can use Paddle.js to build pricing pages that show prospects prices that are relevant for their country, displayed in their local currency with estimated taxes. If you're running a sale or promo, you can calculate discounts too.

Grab the code and test using CodePen

CodePen is a platform for building and sharing frontend code. Explore the code for this tutorial and test right away using our pricing page pen.

How it works

Paddle Checkout automatically shows the correct prices for a customer using geolocation to estimate where a customer is buying from. Customers see prices in their local currency, with taxes estimated for their country or region.

You can use the Paddle.PricePreview() method in Paddle.js to get localized prices for pricing pages or other pages on your website. This means you can show the same information on your pricing page that a customer sees when they open checkout to subscribe.

You don't need to do any calculations yourself or manipulate returned data. Paddle returns totals formatted for the country or region you're working with, including the currency symbol.

What are we building?

In this tutorial, we'll create a simple, three-tier pricing page. It includes a toggle to switch between monthly and annual plans, and a country selector. Our page updates when customers switch billing cycle or change country.

Short animation showing switching between countries. There is a country selector and when a country is chosen, prices in the pricing table change. There are options for USA, United Kingdom, Spain, India, and other.

We'll learn how to:

  • Include and set up Paddle.js using a client-side token
  • Build an items list that we can send to Paddle.PricePreview()
  • Present and update prices on our page
  • Toggle between monthly and annual prices for products
  • Pass a location to Paddle.js to get prices for a country

If you like, you can copy-paste the sample code into your editor or view on CodePen and follow along.

Before you begin

Choose a pricing page

This tutorial walks through creating a simple pricing page. You can also create a cart-style pricing page for more advanced implementations using transaction previews.

Create products and prices

You'll need to create a product and at least one related price for the items that you'd like to include on your pricing page.

Localize prices

To show localized prices, turn on automatic currency conversion or add price overrides to your prices.

Get started

To build a pricing page:

  1. Include and initialize Paddle.js

    Add Paddle.js to your app or website, so you can securely work with your product catalog.

  2. Pass prices to Paddle.js

    Build a pricing preview request body and pass to Paddle.PricePreview().

  3. Update your page based on the response

    Present information returned by Paddle.js to your customer on your page.

  4. Extend by adding location information

    Capture location information and pass to Paddle.js to get localized prices for a country.

1. Include and initialize Paddle.js

Paddle.js 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 by adding this script to the <head>:

Set environment (optional)

We recommend signing up for a sandbox account 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, call Paddle.Environment.set() and set your environment to sandbox:

Pass a client-side token

Next, go to Paddle > Developer tools > Authentication and generate a client-side token. Client-side tokens 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() and pass your client-side token as token. For best performance, do this just after calling Paddle.Environment.set(), like this:

Client-side tokens are separate for your sandbox and live accounts. You'll need to generate a new client-side token for your live account. Sandbox tokens start with test_ to make them easy to distinguish.

2. Pass prices to Paddle.js

Next, we'll pass prices to Paddle.js so that we can get localized prices for them. When previewing prices, Paddle returns calculated totals for line items only — it doesn't include overall totals. This means that we can include prices with different billing cycles and trial periods in our request, unlike when opening a checkout or creating a transaction.

Define lists of prices

Our page includes four prices:


  • Starter (monthly)
  • Starter (yearly)


  • Pro (monthly)
  • Pro (yearly)

In Paddle, we've set these up as two products called 'Starter' and 'Pro', each with two prices for monthly and annual.

To define these, create variables for your products in your script section and set them to the Paddle IDs for your products. We'll use these later to determine which products returned prices are for.

Then, create arrays for your prices. Each array should contain an object that includes the Paddle ID for a price (priceId) and a quantity. We've created two arrays:

  • monthItems, which contains monthly prices for our products.
  • yearItems, which contains yearly prices for our products.

We'll present localized prices for monthItems when the monthly toggle is selected, and yearItems when the yearly toggle is selected.

Get prices

Next, we'll create a function to get prices. This should pass our list of monthly or yearly items to Paddle.js.

In our sample, we've created a function called getPrices() that takes a parameter called cycle. Here's how it works:

  1. We create a variable called billingCycle and set this to year. This is the billing cycle that we'd like to show when customers first visit our page.

  2. We check to see if cycle is month or year, then set a variable called itemsList to either monthItems or yearItems. We also set a variable called billingCycle to the value of cycle for later.

  3. We define a variable called request. This is what we're going to send to Paddle.js. It includes an object with an items key. The format of our request should match the request body for the pricing preview operation in the Paddle API, except with camelCase names for fields.

  4. We call Paddle.PricePreview(), passing in request as a parameter.

  5. Paddle.PricePreview() returns a promise that contains a pricing preview object. We use the .then() method to attach a callback that logs the resolved value to the console, and the .catch() method to log errors to the console.

Test your work

Save your page, then open your browser console and type getPrices('year') or getPrices('month'). You should see a promise that contains a pricing preview object from Paddle returned the console.

Use ⌘ Command + ⌥ Option + J (Mac) or Ctrl + ⇧ Shift + J (Windows) to quickly open your browser console in Google Chrome.

Short animation showing Google Chrome with the browser console open. "getPrices('year')" is typed into the console, which returns a line saying "data" and "meta". This section is expanded to show the full object.

3. Update page

Our function doesn't do anything to our page yet. We'll update getPrices() so that it displays pricing information returned by Paddle.js on our page.

Create HTML for pricing table

First, we need to add some HTML for a simple pricing table with options for monthly and yearly. We'll add some CSS to the <head> of the page, too.

Add this to the <body> of your page.

In this sample, we have radio buttons for our pricing toggle, then a <div> with three <div> elements for each product that we offer. The radio buttons have an onclick attribute that runs our getPrices() function when clicked, passing either month or year as the parameter for cycle.

There are ids set on the <p> elements that contain prices. We'll use these IDs to replace the contents of these elements with returned prices from Paddle.js later.

Update elements using JavaScript

Next, we'll change our script to update the starter-price and pro-price elements so they return pricing from Paddle.

First, we'll get elements in our pricing table using their id and assign them to variables that we can use later.

Then, we'll update our getPrices() function to iterate through This array contains calculated totals for the prices that we passed to Paddle.js.

To make sure we show the correct prices for our products, we check to see if the Paddle ID of the related product of a price matches the product IDs we defined earlier:

  • If the product for a returned price is starterProduct, we replace the contents of the starter-price element with item.formattedTotals.subtotal
  • If the product for a returned price is proProduct, we replace the contents of the pro-price element with item.formattedTotals.subtotal.

For this sample, we also log item.formattedTotals.subtotal to console. This can be useful for debugging.

Set getPrices() to run on page load

Right now, our function only runs when the monthly or annual radio buttons are clicked.

We can add onLoad to our <body> tag to run our getPrices() function immediately after the page has loaded:

Test your work

Save your page, then open it in your browser. You should see prices from Paddle.js in your pricing table. Selecting the monthly or annual toggle should change the prices that you see.

Short animation showing toggling between monthly and annual pricing. The prices change when the monthly and annual radio buttons are clicked.

4. Extend by adding location information

Paddle lets you sell in 30 currencies across more than 200 countries, automatically handling tax and price localization for you.

At the moment, our page shows the base price for our prices. We can pass location information to Paddle.js to present customers with prices in their local currency with estimated tax calculations.

There are three ways we can pass location information to Paddle.js:

  • Country code and (optionally) ZIP/postal code

    We can include an address object containing countryCode and (optionally) postalCode. Paddle uses the supplied country and ZIP/postal code (where included) to estimate tax and localized pricing.

  • IP address

    Capture a visitor IP address, then include customerIpAddress. Services like ipify can return an IP address as text, JSON, or JSONP. Paddle fetches location using the IP address to estimate tax and localized pricing.

  • Pass existing Paddle IDs

    Pass customerId, addressId, and businessId for existing entities. This is generally used for logged-in customers who may be considering other subscriptions, or as part of an upgrade workflow. Paddle uses existing customer entities to estimate tax and localized pricing.

For this tutorial, we'll send a country code.

Create HTML for country drop-down

First, let's add some HTML for a drop-down box under our pricing table. This sample includes a selection of countries, but you can add options for any country that Paddle supports. The value for each option corresponds to the two-letter country code for that country.

Pass location to getPrices()

Next, we need to pass the value of the chosen option in the drop-down box to Paddle. To do this:

  1. We create a variable called billingCountry and set this to US. This is the billing cycle that we'll show customers when the page loads initially.

  2. We add an event listener that occurs when the value of the dropdown is changed. It updates our billingCountry variable to the value of the dropdown, then runs our getPrices() function.

  3. We update our request to include an address object that contains countryCode, set to the value of billingCountry.

Test your work

Save your page, then open it in your browser. You should see prices from Paddle.js in your pricing table. Selecting the monthly or annual toggle should change the prices that you see. Choosing a country from the drop-down menu should change the currency and prices that you see.

Short animation showing switching between countries. There is a country selector and when a country is chosen, prices in the pricing table change. There are options for USA, United Kingdom, Spain, India, and other.

Not seeing localized prices? Add price overrides to your prices, or turn on automatic currency conversion in Paddle > Business account > Currencies. See: Localize prices

Next steps

That's it! Now we've built a simple pricing page, you might like to add other fields to your page, pass a discount, or open a checkout.

Add other fields to your pricing page

Paddle.PricePreview() returns a pricing preview object for the prices and location passed. We show details.lineItems.formattedTotals.subtotal in our sample. This is the calculated total for an item before estimated taxes and discounts, formatted for a particular currency.

You might like to use another value for the price you show on your page, or include other values.

Pass a discount

Extend your pricing page by passing discountId in your request to Paddle.PricePreview(). The response includes a discount array that has information about the discount applied. Calculated totals in details.lineItems include discounts, where applicable.

Open a checkout

Pass items to or use HTML data attributes to open a checkout.