For merchants who need full control over the HTML layout or want to build a completely custom loyalty page, JeriCommerce provides standalone Liquid section templates that load the loyalty page engine directly from the CDN. This guide is aimed at developers building custom storefront experiences for their merchants.
When to Use CDN Mode¶
Choosing Between the Default Block and CDN Templates¶
-
The merchant wants a completely custom layout that goes beyond what the theme editor settings allow.
-
The development team prefers to own the HTML directly in the theme code.
-
You need to integrate the loyalty page into an existing page template alongside other sections.
If the merchant is happy with the default look and just wants to tweak colors and copy, use the default template guide instead.
Setup Steps¶
Step 1: Get the Template¶
JeriCommerce provides two ready-made CDN templates. Copy the one that best fits your needs:
-
Visual template (templates/visual.liquid) — Full-featured: hero with CTA, how-it-works steps, earning rows with per-network SVG icons, tier cards, and loading skeleton. Same look as the theme block.
-
Minimal template (templates/minimal.liquid) — Compact list layout: title, earnings as a simple list, tiers as rows. Inline CSS, no external stylesheet needed.
You can obtain these from the JeriCommerce admin under Loyalty Page → Get template code, or copy directly from the repository files.
Step 2: Add to Your Theme¶
-
Go to Shopify Admin → Online Store → Themes → Edit code.
-
In the sections/ directory, click Add a new section.
-
Name it (e.g., jeri-loyalty) and paste the template code.
Step 3: Create a Page Template¶
Create a JSON page template that references your section:
// templates/page.loyalty.json { "sections": { "loyalty": { "type": "jeri-loyalty" } }, "order": ["loyalty"] } Alternatively, add the section to an existing page template via the theme editor: Customize → Add section.
Step 4: Create the Page¶
Go to Shopify Admin → Pages → Add page → Select the "loyalty" template.
How CDN Mode Works¶
Loading the Engine¶
CDN templates load the same JavaScript that powers the theme app extension block — bundled, minified, and always up to date:
The engine auto-detects the shop domain from the data-shop attribute on the root element, or falls back to window.Shopify.shop.
Template System: How Data Binding Works¶
Two Complementary Mechanisms¶
The template engine uses two systems to bind API data to your HTML:
1. Variable Interpolation — {varName}
Write {varName} tokens anywhere in your HTML text content. The JS engine walks all text nodes and replaces them with API data. This is the primary way to display data.
{tier.name}
{tier.requiredPoints} {earning.points} Inside repeating templates (tiers, earnings), variables are scoped to the template data. Syntax uses single curly braces {key} — no conflict with Liquid ({{ }}), JS template literals (${ }), or CSS.
There are also global variables (like {programName}, {currencySymbol}) that work in any text node across the entire template — not just inside repeating templates. See the Global Template Variables section below for the full list.
2. Data Attributes — data-jeri
Used for non-text operations that can’t be expressed as text interpolation:
AttributePurposeExampledata-jeri="name" on Defines a repeating row templatedata-jeri="name" on containerReceives cloned template rows data-jeri-group="name"Group container (hidden when empty)data-jeri-group="purchases" NeedUseDisplay text/numbers{varName} in text contentMix variables with custom copyEarn {earning.points} with {earning.title}Set image srcdata-jeri="key" on These 7 global variables can be used in any text node inside VariableTypeDescriptionExample{programName}stringName of the loyalty program"My Rewards"{currencySymbol}stringCurrency symbol for the program’s currency, resolved via the browser’s Earn {balanceName} with every {currencySymbol} you spend Prices are in {currencyCode} Global variables work alongside scoped variables ( Note: The The variable Used inside the template. FieldTypeDescriptionearning.typestringFlow type: purchase, social, referral, profile, verify, wallet, scan, linkearning.titlestringHuman-readable title for the earning ruleearning.descriptionstringDetailed description of how to earnearning.pointsstringCompact points display: "+100" for fixed points, "10%" for purchase return rate < 1, "x2" for purchase multiplier ≥ 1earning.iconUrlstringIcon URL (set via data-jeri on Used inside the template. FieldTypeDescriptiontier.namestringTier name (e.g., "Gold", "VIP")tier.contentstringTier description/benefits — may contain HTML, use data-jeri-html="tier.content"tier.imagestringTier image URL (set via data-jeri on Every custom template must include this root element with the required attributes: AttributeRequiredPurposeid="jeri-loyalty-page-root"YesJS entry point — the engine looks for this IDclass="jeri-loyalty-page"YesCSS scoping + CSS variablesdata-shopYesShop domain for API callsdata-icon-baseRecommendedURL prefix for earning iconsdata-localeRecommendedStore locale for i18n (falls back to "en")
The jeri-loyalty-page--loading class shows a skeleton and hides content until data loads. JS removes it after data is fetched. Important: The CSS stylesheet must be loaded before the HTML content (inside the root element) to prevent a flash of unstyled content on first load. Keep id="jeri-loyalty-page-root" on the root element — JS needs it to initialize. Keep class="jeri-loyalty-page" on root — CSS variables are defined here. Keep data-shop — required for API calls. Keep template/container pairs — A needs a matching Use {varName} freely in any text node — the engine replaces all tokens it recognizes. Use data-jeri-html="key" for HTML content (not {var}, which would be escaped). The default template is fully customizable from the Liquid file. You can: Change copy — Edit any text, mix {variables} with your own wording Reorder sections — Move tiers above earnings, etc. Remove sections — Delete any Change HTML structure — Use tables, grids, lists, whatever fits your design Add your own CSS — Use the Custom CSS setting or add Sets src attribute (hides if empty)
data-jeri-hide-if="value"Hide element when data matches valuedata-jeri-hide-if="1"data-jeri-html="key"Inject raw HTML content
Quick Reference: When to Use Which¶
Hide based on valuedata-jeri-hide-ifInject rich HTML contentdata-jeri-html="key"Define a repeating row +
Global Template Variables¶
Variables Available Anywhere in the Template¶
#jeri-loyalty-page-root. Write them with {variableName} syntax — the engine replaces them automatically with data from the program configuration.Intl.NumberFormat"$", "€", "£"{currencyCode}stringISO currency code for the program"USD", "EUR", "GBP"{balanceName}stringPlural name for points"Points", "Stars"{singularBalanceName}stringSingular name for points"Point", "Star"{tierBalanceName}stringPlural name for tier points"Points"{singularTierBalanceName}stringSingular name for tier points"Point"Usage Example¶
Welcome to {programName}!
{earning.*}, {tier.*}). Inside repeating templates, both global and scoped variables are resolved.{currencySymbol} variable uses the browser’s native Intl.NumberFormat to resolve the correct symbol for the program’s currency code. This means the symbol adapts to the actual program currency — $ for USD, € for EUR, £ for GBP, and so on.Migration Note¶
{hero.programName} has been removed. Use {programName} instead — it works everywhere in the template, not just in the hero section.Available Data Fields¶
Earning Fields (earning.*)¶
, empty if no icon). Social networks use per-network icons (facebook.svg, instagram.svg, etc.)
Tier Fields (tier.*)¶
)tier.requiredPointsstringPoints needed (e.g., "1,000 tier points"). Uses tierBalanceName with singular/pluraltier.factorstringPoints multiplier (e.g., "2"). Auto-hidden when "1" via data-jeri-hide-iftier.idstringInternal tier ID
Required Root Element¶
The Foundation of Every Custom Template¶
Template Rules¶
The 6 Rules for Custom Templates¶
Customizing the Default Template¶
What You Can Customize¶