Shopify Markets Fix & Performance Optimization

Everly® — Shopify Markets Currency Fix & FOUC Elimination

Fixed broken multi-currency pricing and eliminated visible page flash on a custom Shopify landing page with Loop Subscriptions — CLS dropped from 0.11 to 0.00 across 236 international regions.

0.11 → 0.00 CLS (Layout Shift)
38 → 0 Hardcoded Prices
90 Lines Dead JS Removed
236 Regions Now Converting

The Problem

Everly® is a DTC health and wellness brand selling pumpkin seed oil supplements through a custom-coded Shopify landing page with Loop Subscriptions integration. The store had Shopify Markets enabled with two markets — United States (USD) and International (236 regions with local currencies) — but prices were stuck in USD for every visitor regardless of location.

On top of the broken currency conversion, the page had a visible flash of unstyled content (FOUC) on every load: prices would appear in USD, disappear briefly, then reappear with reformatted values. The Cumulative Layout Shift score was 0.11 — above Google’s 0.1 threshold, meaning the page was failing Core Web Vitals.

Both issues traced back to the same root: the page was built with hardcoded price strings and client-side JavaScript price rewriting instead of server-side Liquid rendering.

The Audit: What I Found

I audited two custom section files (custom-lander-1.liquid and custom-lander-2.liquid) totalling ~8,400 lines of code.

38 Hardcoded USD Prices

Every price on the page was a static string — $29.99, $179.97, $299.95 — with zero usage of Shopify’s | money Liquid filter anywhere in either file. This meant Shopify Markets had no dynamic values to convert. International visitors saw USD prices regardless of their locale, currency, or market assignment.

Hardcoded prices appeared in:

  • Sale prices and subscription per-delivery prices
  • Compare-at (strikethrough) prices
  • Bundle tier pricing across 3 offer levels
  • Savings badge amounts
  • data-* attributes used by JavaScript

Async JavaScript Price Rewriter Causing FOUC

An async IIFE (Immediately Invoked Function Expression) at the bottom of each file was the primary cause of the page flash:

  1. Server renders hardcoded USD prices → visitor sees static $29.99
  2. Async fetch fires → JavaScript calls /products/...loop.js to get variant data
  3. Prices rewrittenIntl.NumberFormat reformats values and overwrites DOM via .textContent
  4. Visible flash → the rewrite happens after paint, causing a CLS event of 0.11

This ~45-line script per file was also redundant — it was reformatting USD back to USD for US visitors, and didn’t handle international currencies at all.

Stale Variant IDs

The variant IDs hardcoded in both files (49997999079730, 49997999112498, 49997999145266) didn’t match the live product variants (50942654120242, 50942654153010, 50942654185778). The product had been recreated at some point, leaving the landing page pointing at non-existent variants.

The Fix

1. Liquid Variable Block for Dynamic Pricing

Added a server-side Liquid block to both files that maps variants by ID and looks up Loop Subscriptions selling plan allocations:

{% for v in product.variants %}
  {% if v.id == 50942654120242 %}{% assign v1 = v %}
  {% elsif v.id == 50942654153010 %}{% assign v2 = v %}
  {% elsif v.id == 50942654185778 %}{% assign v3 = v %}
  {% endif %}
{% endfor %}

{% comment %} Loop Subscriptions per-delivery price {% endcomment %}
{% for spa in v1.selling_plan_allocations %}
  {% if spa.selling_plan.id == 6810501426 %}
    {% assign v1_sp_price = spa.per_delivery_price %}
  {% endif %}
{% endfor %}

{% comment %} Save amounts {% endcomment %}
{% assign v1_save = v1.compare_at_price | minus: v1.price %}

2. Replaced All 38 Hardcoded Prices with Liquid Money Filters

Every static price string became a dynamic Liquid expression piped through Shopify’s | money filter:

<!-- BEFORE: Hardcoded, invisible to Shopify Markets -->
<span class="offer-price">$29.99</span>
<span class="compare-price">$59.99</span>
<span data-price="$39.99">

<!-- AFTER: Dynamic, converts automatically per locale -->
<span class="offer-price">{{ v1_sp_price | money }}</span>
<span class="compare-price">{{ v1.compare_at_price | money }}</span>
<span data-price="{{ v1.price | money }}">

The | money filter is the key — it hooks into Shopify Markets’ currency conversion layer. When a visitor from the UK loads the page, {{ v1.price | money }} outputs £30.00 instead of $39.99. No JavaScript required.

3. Pre-Filled Add to Cart Button

The Add to Cart button was rendering empty on first paint, then JavaScript populated it on DOMContentLoaded — causing a visible flash. Fixed by pre-filling with Liquid:

<!-- BEFORE: Empty, filled by JS after load -->
<span class="main-price"></span>

<!-- AFTER: Server-rendered, no flash -->
<span class="main-price">{{ v2_sp_price | money }}</span>

4. Removed the Async IIFE Price Rewriter

Deleted ~90 lines of JavaScript across both files (45 per file). This script was:

  • The primary cause of the FOUC / layout shift
  • Completely redundant now that Liquid handles all price rendering server-side
  • Not handling international currencies anyway

5. Updated Stale Variant IDs

Corrected all variant ID references in Liquid lookups, data-variant-id attributes, and JavaScript cart submission logic to match the live product.

Results

Shopify Markets Currency Conversion — Working

Tested with Shopify Markets country preview (United Kingdom / GBP):

Element Before (Broken) After (Fixed)
Sale prices $29.99 (USD always) £23.00 (GBP)
Compare-at prices $59.99 (USD always) £46.00 (GBP)
Bundle tier prices $179.97 (USD always) £69.00 (GBP)
Savings badges Save $20.00 Save £159.00
Add to Cart button $29.99 (USD always) £45.75 (GBP)

All 236 international regions now receive correctly converted local currency prices.

FOUC & Core Web Vitals — Eliminated

Metric Before After
Cumulative Layout Shift (CLS) 0.11 (failing) 0.00 (perfect)
Lighthouse CLS 0.017 (green)
Visible price flash Yes, on every load None
Empty button flash Yes, on every load None

CLS dropped from above the 0.1 failing threshold to absolute zero. No visible reflow, no DOM mutation after first paint.

Code Impact

Metric Value
Files changed 2
Insertions +122 lines
Deletions -148 lines
Net -26 lines (smaller codebase)
Hardcoded prices eliminated 38
JavaScript removed ~90 lines

What Was Not Touched

  • Add-to-cart JavaScript logic (fetch to /cart/add.js)
  • Loop Subscriptions selling plan configuration
  • Auto-refill checkbox behavior
  • CSS, layout, or visual design
  • Slick carousel initialization
  • jQuery or Slick loading order
  • Any files outside the two scoped section files

Key Takeaway

Shopify Markets currency conversion only works when prices flow through Liquid’s | money filter. Hardcoded price strings — whether in HTML, data attributes, or JavaScript-rendered DOM — are invisible to the Markets currency layer. The same JavaScript that was “fixing” price formatting was actually the source of both the currency bug and the layout shift.

The fix was architectural, not cosmetic: move all price rendering from client-side JavaScript to server-side Liquid. The result is faster first paint, zero layout shift, correct international pricing, and 90 fewer lines of code to maintain.


Need Shopify Markets currency conversion fixed, or dealing with FOUC and layout shift on your custom Shopify pages? Book a free strategy call and I’ll diagnose the root cause.

Frequently Asked Questions

Why are Shopify Markets prices not converting to local currency?

Shopify Markets relies on Liquid money filters like {{ price | money }} to dynamically convert prices based on the visitor's locale. If your theme or custom sections use hardcoded price strings like $29.99 instead of pulling from variant.price and piping through the money filter, Shopify's currency conversion layer has nothing to act on. The fix is replacing every static price output with dynamic Liquid expressions using the money filter, and removing any JavaScript that overwrites prices after page load.

How do you fix FOUC (Flash of Unstyled Content) on a Shopify product page?

FOUC on Shopify product pages is usually caused by JavaScript rewriting DOM content after the initial server-rendered HTML has already painted. Common culprits include async fetch calls to the Product JSON endpoint that reformat prices, subscription app widgets injecting after DOMContentLoaded, and empty elements that get filled by JS on load. The fix is moving price rendering to server-side Liquid so the first paint is already correct, removing client-side price rewriting scripts, and pre-filling dynamic elements like Add to Cart button text with Liquid output instead of leaving them empty for JS to populate.

How do you make Loop Subscriptions prices work with Shopify Markets?

Loop Subscriptions stores per-delivery prices in Shopify's selling_plan_allocations object on each variant. To make these prices convert correctly with Shopify Markets, access the subscription price through variant.selling_plan_allocations, find the matching selling plan, and output the per_delivery_price through Liquid's money filter. This ensures Shopify's currency conversion layer processes the subscription price the same way it handles regular variant prices.

What causes Cumulative Layout Shift (CLS) on Shopify custom landing pages?

High CLS on Shopify custom landing pages is commonly caused by JavaScript that rewrites price elements after initial render, subscription widgets injecting into the DOM after page load, images without explicit dimensions, and Add to Cart buttons that render empty then get populated by JS. A CLS score above 0.1 fails Core Web Vitals. The fix involves moving all dynamic content to server-side Liquid rendering so the first paint matches the final layout, eliminating the reflow that causes visible layout shift.

How do you replace hardcoded Shopify prices with dynamic Liquid output?

First, create a Liquid variable block that maps each variant by ID and looks up selling plan allocations for subscription pricing. Then replace every hardcoded price string and data attribute with dynamic expressions: data-price becomes {{ variant.price | money }}, compare-at prices become {{ variant.compare_at_price | money }}, and save amounts are calculated with the minus filter then piped through money. This approach works with Shopify Markets because the money filter automatically converts to the visitor's local currency.