Pricing

Programmatically calculate real-time checkout totals—plans, add-ons, coupons, taxes, adjustments, gift cards, multi-subscription carts, and more—using recurly.Pricing.Checkout in Recurly.js.

recurly.Pricing.Checkout is a client-side pricing engine that mirrors Recurly’s server logic. Attach it to a section of your checkout (or drive it purely through code) and it will keep subtotals, discounts, taxes, and grand totals in sync as customers pick plans, quantities, coupons, gift cards, or custom adjustments. The class emits events on every change, so you can update UI elements or trigger additional logic without extra API calls.

Prerequisites and limitations

  • Site configuration: The plans, add-ons, coupons, gift cards, and taxes referenced in your checkout must exist—and be active—on the Recurly site whose public key you’re using.
  • Currency: All items in a single CheckoutPricing instance must share the same currency code. Change the currency via the data-recurly="currency" input or the API before adding items.
  • One-way DOM binding: If you call the JavaScript API methods on a pricing instance that’s already attach-ed to DOM elements, those input/output elements will not auto-update; use API-only mode or re-render values yourself.

Key details

Recurly automates complicated subscriptions, with many factors influencing the total price at
checkout. With this in mind, Recurly.js provides a robust recurly.Pricing.Checkout class designed to make determining the actual checkout costs as simple and flexible as possible.

A Recurly.js checkout pricing instance can be attached to the form we created above, or to any other
section of your page meant to display pricing.

Reference

fn recurly.Pricing.Checkout

const checkoutPricing = recurly.Pricing.Checkout();

Creates a CheckoutPricing instance.

No Arguments
Returns

A new CheckoutPricing instance.

fn CheckoutPricing.attach

Given the following example HTML structure

<section id="my-checkout">
  <select data-recurly="plan">
    <option value="basic">Basic</option>
    <option value="notbasic">Not Basic</option>
  </select>
  <input type="text" data-recurly="coupon">
</section>

Use checkoutPricing.attach to bind the <section> to the checkout pricing calculator.

const checkoutPricing = recurly.Pricing.Checkout();

checkoutPricing.attach('#my-checkout');

This is the simplest way to use a CheckoutPricing instance. Simply pass a container element, and the
CheckoutPricing instance will use all elements with a valid data-recurly attribute to determine price. When a value changes, the CheckoutPricing instance will automatically update its calculations.

This allows your customers to manipulate your checkout form at will, and have your checkout page's
prices update automatically.

Arguments
ParamTypeDescription
containerHTMLElement or StringParent element containing all data-recurly elements. If a String is passed, it will be parsed with document.querySelector
Returns

Nothing.

HTMLElements

HTMLElements bound to a CheckoutPricing instance may be for either input or output.

Input HTMLElements

Input elements should be user-manipulable elements like input or select. If you want to input a
value but not let a customer manipulate it, use an <input type="hidden">.

Subscriptions

CheckoutPricing instances can calculate a checkout containing one or more subscriptions. The
table below lists all available input HTMLElement types.

data-recurly valueExample ValueDescription
planbasicPlan code.
plan_quantity1Plan quantity. Defaults to 1 if not specified
addon1Addon quantity. To identify the addon being modified, use the data-recurly-addon attribute to set the addon code.
tax_codedigitalProduct tax code.

If you would like to calculate multiple subscriptions on a single checkout, group the values for
each subscription using the data-recurly-subscription attribute. Simply set them to a unique id to group them. Here's an example:

<section id="my-checkout">
  Subscription 1
  <select data-recurly="plan" data-recurly-subscription="0">
    <option value="basic">Basic</option>
    <option value="notbasic">Not Basic</option>
  </select>

  Subscription 1 Add-ons
  <span data-recurly="addon_price" data-recurly-subscription="0" data-recurly-addon="my_addon_code_1"></span>
  <input type="text" data-recurly="addon" data-recurly-subscription="0" data-recurly-addon="my_addon_code_1" value="0">

  Subscription 2
  <select data-recurly="plan" data-recurly-subscription="1">
    <option value="basic">Basic</option>
    <option value="notbasic">Not Basic</option>
  </select>
  <input type="hidden" data-recurly="tax_code" data-recurly-subscription="1" value="my_tax_code_0">
</section>
Adjustments

As with subscriptions, CheckoutPricing instances can calculate a checkout containing one or more
adjustments.

Using an item code

You may specify an item code from your Recurly catalog. This will automatically retrieve the pricing
information for your item.

data-recurly valueExample ValueDescription
adjustment0, 1Adjustment quantity. <br><br> Set a unique identifier using data-recurly-adjustment. <br><br> Set the item code using data-recurly-adjustment-item-code.

Example:

<section id="my-checkout">
  My product
  x
  <input type="text"
         data-recurly="adjustment"
         data-recurly-adjustment="my-adjustment-0"
         data-recurly-adjustment-item-code="my-item-code"
         value="0">
</section>

Specifying adjustment properties inline

It's also possible to specify all adjustment values inline.

data-recurly valueExample ValueDescription
adjustment0, 1Adjustment quantity. <br><br> Set a unique identifier using data-recurly-adjustment. <br><br> Set the amount using data-recurly-adjustment-amount, <br><br> currency with data-recurly-adjustment-currency, <br><br> tax code with data-recurly-adjustment-tax-code, <br><br> and tax exempt status with data-recurly-adjustment-tax-exempt.

Example:

<section id="my-checkout">
  $10 adjustment
  x
  <input type="text"
         data-recurly="adjustment"
         data-recurly-adjustment="my-adjustment-0"
         data-recurly-adjustment-amount="10"
         data-recurly-adjustment-currency="USD"
         data-recurly-adjustment-tax-code="my_tax_code_1"
         data-recurly-adjustment-tax-exempt="false"
         value="0">

  $2.99 adjustment
  <input type="checkbox"
         data-recurly="adjustment"
         data-recurly-adjustment="my-adjustment-1"
         data-recurly-adjustment-amount="2.99"
         data-recurly-adjustment-currency="USD"
         data-recurly-adjustment-tax-code="my_tax_code_2"
         data-recurly-adjustment-tax-exempt="true"
         value="1">
</section>
Other
data-recurly valueExample ValueDescription
coupon15_offCoupon code.
currencyUSD
Output HTMLElements

Output elements should be plain text elements like output, span, or div.

data-recurly valueExample ValueDescription
total_now100.00Total subscription cost due now.
subtotal_now90.00Subtotal of the following pricing components.
subscriptions_now80.00Total cost of all subscriptions. This is part of the subtotal.
adjustments_now10.00Total cost of all adjustments. This is part of the subtotal.
discount_now5.00Amount discounted with coupon use.
taxes_now15.00Total subscription taxation.
gift_card_now75.00The gift card amount that will be applied to the purchase today.
gift_card_next25.00The remainder gift card amount that will be applied to the next renewal.
currency_codeUSD, EURISO-4217 currency code.
currency_symbol$, Symbolic representation of currency_code.

Note: data-recurly values ending in _now like subtotal_now have counterparts ending in _next.
As you might expect, these correspond to the next billing cycle cost. These values are especially useful for subscriptions with trial periods.

events Emit

CheckoutPricing instances emit events when various values are set or the price changes. See
Events for usage.

Event namePayloadOccurs When
changePricingStateThe price changes for any reason.
set.subscriptionSubscription objectA subscription is added to the checkout.
set.planPlan objectA plan is set on any subscription.
set.addonAddon objectAn addon is set on any subscription.
set.adjustmentAdjustment objectAn adjustment is added to the checkout.
set.addressAddress objectThe user's address is changed on the checkout. This is limited to country, postalCode, and vatNumber.
set.shippingAddressAddress objectThe user's shipping address is changed on the checkout. This is limited to country, postalCode, and vatNumber.
set.taxTax properties objectTax properties are changed on the checkout.
set.currencyCurrency codeThe currency is set on the checkout.
set.couponCoupon objectA valid coupon is set on the checkout.
unset.couponCoupon objectAn existing valid coupon is removed from the checkout.
error.couponRecurlyErrorA requested coupon code is invalid.
set.gift_cardGift card objectA gift card is set on the checkout.
unset.gift_cardNothingA gift card is removed from the checkout.

CheckoutPricing API

A CheckoutPricing instance can be manipulated with a set of direct method calls. This is useful
if you would like to set up a complex pricing schema for your customers, or would just like to use a more programmatic method of determining checkout price. Events fire just as they normally would when using CheckoutPricing.attach.

Note that Recurly.js's DOM binding is one-way. Thus if you use the CheckoutPricing API on a pricing
instance already attached to a container, the elements within will not update with your CheckoutPricing API calls. If you would like two-way DOM binding, we suggest using the CheckoutPricing API without attaching it to a container. If using React , consider using our react-recurly library, which contains a custom hook for interacting with the CheckoutPricing API.

The example below demonstrates all the ways that a CheckoutPricing instance can be manipulated
directly.

const checkoutPricing = recurly.Pricing.Checkout();

// Add a $10 adjustment
checkoutPricing
  .adjustment({
    id: '0',
    itemCode: 'my-item-code',
    quantity: 1,
  })
  .adjustment({
    id: '1',
    amount: 10.0,
    quantity: 1,
    taxExempt: true,
    taxCode: 'my-tax-code'
  })
  .coupon('my-coupon-code')
  .giftCard('my-gift-card-code')
  .address({
    country: 'US',
    postal_code: '90210'
  })
  .tax({
    tax_code: 'digital',
    vat_number: '',
    amounts: {
      now: '0.99',
      next: '1.99'
    }
  })
  .subscription(recurly.Pricing.Subscription()
    .plan('basic', { quantity: 1 })
    .addon('addon1', { quantity: 2 })
    .catch(function (err) {
      // err.code
    })
    .done()
  )
  .catch(function (err) {
    // err.code
  })
  .done(function (price) {
    // price object as emitted by 'change' event
  });

PricingPromise

Each CheckoutPricing method will return a PricingPromise. This allows you to chain many
asynchronous calls together without having to manage a complex series of callbacks.

You don't need to worry much about the internals of a PricingPromise, as it is designed to stay
out of your way and facilitate asynchronous calls for you.

The catch method, as shown in the example, is used to handle error scenarios, such as when an
addon cannot be applied to the selected plan.

Note: At the end of a chain of pricing method calls, be sure to call .done() as this tells the Pricing
instance to begin calculating, and gives you the subscription price.

Example PricingState Object

Emitted by the change event

{
  currency: {
    code: 'USD',
    symbol: '$'
  },
  now: {
    adjustments: '20.00',
    discount: '0.00',
    giftCard: '0.00',
    items: [
      {
        addons: '0.00',
        amount: '10.00',
        id: '0',
        plan: '10.00',
        setupFee: '0.00',
        type: 'subscription'
      },
      {
        amount: '20.00',
        id: 'adj-0',
        quantity: '2.00',
        type: 'adjustment',
        unitAmount: '10.00'
      }
    ],
    subscriptions: '10.00',
    subtotal: '30.00',
    taxes: '0.00',
    total: '30.00'
  },
  next: {
    adjustments: '0.00',
    discount: '0.00',
    giftCard: '0.00',
    items: [
      {
        addons: '0.00',
        amount: '10.00',
        id: '0',
        plan: '10.00',
        setupFee: '0.00',
        type: 'subscription'
      }
    ],
    subscriptions: '10.00',
    subtotal: '10.00',
    taxes: '0.00',
    total: '10.00'
  },
  taxes: []
}