Skip to main content
Use JavaScript overrides when the standard Subscription Options block settings do not provide enough control for your storefront. You can customize displayed labels, descriptions, prices, per-item text, savings messages, and other presentation values for specific variants, selling plans, and quantities. When neither an overrides nor a translations object is configured, the customization engine remains inactive and the widget keeps its standard behavior.
JavaScript overrides only change what the Subscription Options widget displays. They do not change product prices, selling plan prices, or discounts in the Shopify cart or checkout. Configure actual prices and discounts in Shopify or Firmhouse, then keep the displayed override values in sync.

Before you start

This is an advanced theme customization intended for developers. You need the numeric Shopify variant and selling plan IDs that you want to target.

Add a Custom Liquid block to the product page

  1. In Shopify admin, go to Online Store > Themes.
  2. Click Customize for your active theme.
  3. Open the product detail page (PDP) template where you use the Subscription Options block.
  4. In the product information section, click Add block and select Custom Liquid.
  5. Move the Custom Liquid block above the Subscription Options block.
  6. Add your JavaScript configuration between <script> and </script> tags:
  1. Click Save.
The Custom Liquid block must appear before the Subscription Options block so the configuration is available when the widget initializes.

Add the configuration

The following example defines a fallback, a variant override, a selling plan override, a quantity override, and an exact variant, selling plan, and quantity combination:
Replace the example IDs with your Shopify IDs. Keep IDs in quotation marks so JavaScript treats them as exact string keys. For one-time purchases, use one-time-purchase as the selling plan key.

Understand override priority

The widget combines matching values in this order:
  1. default
  2. variants[variantId]
  3. sellingPlans[sellingPlanId]
  4. variantSellingPlans[variantId][sellingPlanId]
  5. quantities[quantity]
  6. variants[variantId].quantities[quantity]
  7. sellingPlans[sellingPlanId].quantities[quantity]
  8. variantSellingPlans[variantId][sellingPlanId].quantities[quantity]
More specific layers only need to contain the values they change. Values omitted from a combination continue to use the matching quantity, selling plan, variant, or default value. As an alternative to the nested variantSellingPlans structure, exact combinations can be written as:
An exact variant, selling plan, and quantity combination can also use the compact form:

Select the product quantity input

The widget listens for input, change, and Shopify theme quantity-selector:update events from the product page’s quantity input and reapplies matching overrides immediately. It recognizes quantity inputs inside these selectors by default:
If your theme uses different markup, set quantityInputSelector beside overrides. The selector can target the input itself or a wrapper containing an input[name="quantity"] or select[name="quantity"]:
If no matching quantity input is found, the widget uses quantity 1.

Available display values

Each display field has a plain-text key and a corresponding HTML key. Use the following keys in any override layer: When both versions of a field are provided, the HTML version takes precedence. The earlier aliases optionHtml, perUnitHtml, and savingsHtml remain supported for existing configurations. Native dropdown options cannot render formatted HTML consistently. For dropdowns, the widget converts optionTextHtml or optionNameHtml to plain text. The same HTML values remain formatted in card, pill, description, price, and savings elements. The frequency key is metadata used to associate the option with its delivery frequency rather than rendered content, so it accepts a plain string.

Customize only the frequency description

Use frequencyDescription when you want to replace text such as Billed and delivered every month without replacing the checkout price-per-item description. The following placeholders are available: Plural cadences include their count, for example 3 months or 3 maanden. Keeping every, elke, or other surrounding grammar outside the billing and delivery placeholders lets you control the complete sentence in each translation.
The default override applies to every selling plan that renders a frequency description. You can still place the same field under sellingPlans when only one selling plan needs different wording. For example, a monthly option keeps its dynamic checkout price and displays:
To show only the billing cadence, use frequencyDescription: "Billed every {billing_frequency}.". For Dutch storefronts, you can provide a translated override such as frequencyDescription: "Elke {billing_frequency} gefactureerd.". Use frequencyDescriptionHtml instead when the replacement needs trusted HTML formatting. Placeholder values are escaped before they are inserted into HTML. This override only applies when the widget has a built-in billing or delivery frequency description to replace. If both description and frequencyDescription resolve for the same option, frequencyDescription takes precedence so the checkout price remains visible.
HTML overrides are inserted into the storefront page. Only use hard-coded, trusted HTML. Do not insert customer-provided or other untrusted content.

Add translations

Add a translations object beside overrides. Each locale accepts the same default, variant, selling plan, quantity, and combination structure:
The widget determines the active locale from the first available source:
  1. window.firmhouse.subscriptionOptions.locale
  2. Shopify.locale
  3. The page’s <html lang> value
  4. The customer’s browser language
Language-level translations are applied before regional translations. For example, an nl-NL storefront uses the base overrides, then nl, then nl-NL. The normal default-to-quantity-combination priority still applies within those translations. To force a specific locale for testing, add it to the configuration:

Troubleshooting

Overrides do not appear

  • Confirm the configuration loads before subscription-options.js.
  • Confirm the variant and selling plan IDs are numeric Shopify IDs without the gid://shopify/... prefix.
  • Check that the configuration uses window.firmhouse.subscriptionOptions with the same capitalization shown in the examples.
  • Verify that another theme script does not replace window.firmhouse after your configuration runs.
  • If a quantity override does not appear, confirm quantityInputSelector matches the product’s visible quantity input or its wrapper.

The correct price appears in the widget but not at checkout

This is expected when the configured display value differs from Shopify. JavaScript overrides do not change checkout pricing. Update the product, selling plan, or discount configuration that controls the actual Shopify price.

A translation does not appear

  • Inspect Shopify.locale or the page’s <html lang> value to confirm the active locale.
  • Use language keys such as nl for shared translations and regional keys such as nl-NL only for regional differences.
  • Set window.firmhouse.subscriptionOptions.locale temporarily to test a locale directly.