This documentation is currently under development. Certain sections are not yet complete and will be added shortly.
For the complete documentation index, see llms.txt. This page is also available as Markdown.
ReferenceWallet

Liquid templating

Render dynamic pass fields, format values, and build wallet pass content with Liquid.

Liquid templating

Liquid combines fixed text with dynamic values from a pass. The Wallet Crew uses the DotLiquid implementation, plus custom date filters and the minify tag.

Use this reference after confirming the required data paths on a real pass.

Real-world examples
  • A loyalty card displays a safe, whole-number points balance.

  • A gift card displays its identifier, amount, and expiry.

  • An event ticket turns seat data into venue directions.

Confirm available data

Each render receives a data context. It can contain pass data, additional data, and values returned by connected providers.

Inspect View data on a real pass before writing a template. This payload is the source of truth for variable paths.

Additional data is suitable for visible pass content. Metadata supports operations and segmentation. It should not be treated as a wallet display source.

For the complete update and validation flow, see Update pass data in templates.

Common paths include:

Data
Example paths

Customer

firstName, lastName, address.city

Pass

serialNumber, tenantId, publicUrl, authenticationToken

Loyalty

loyalty.points, pendingLoyaltyPoints, loyalty.amounts

Gift card

voucher.amount, voucher.currency, id.y2.giftCardId

Event ticket

ticket.name, ticket.startDate, ticket.seatNumber, ticket.entrance

Collections

y2.tickets, y2.bons.loyaltyCertificates

Custom values

additionalData.<key>

Missing values render as an empty string. Use default when a visible fallback is required.

Syntax basics

Use {{ ... }} to print a value. Use {% ... %} for logic that does not print on its own.

Filters run left to right. Dot notation follows the nested structure in the data payload.

Conditions and loops

Liquid treats only nil and false as falsy. The number 0 and the string "false" are truthy. Compare optional numbers explicitly.

Guard loops with a collection-size check. This prevents empty section headings.

Inside a loop, forloop.index, forloop.first, forloop.last, and forloop.length are available.

Assignments, branches, and whitespace

Use assign to reuse calculated values. Use case for code-to-label mappings.

Use {%- and -%} to trim surrounding whitespace. This keeps multi-line templates compact in narrow wallet fields.

YAML values

Quote Liquid values containing YAML special characters. Use |- for multi-line values.

Custom filters

Date filters

All date filters parse the input as a date or time value, apply the operation, and return a DateTimeOffset. Chain them with | date: "format" when a string output is needed.

add_minutes

Adds the specified number of minutes.

add_hours

Adds the specified number of hours.

add_seconds

Adds the specified number of seconds.

add_days

Adds the specified number of days.

add_timespan

Adds a timespan in hh:mm:ss format.

All date filters use invariant culture for parsing and formatting.

Format filter

format

Applies a format string to any IFormattable value such as numbers, dates, and enums.

This renders a grouped integer such as 1,234 in invariant culture.

This renders a currency-style value with two decimals.

Custom tag

minify

Generates a short redirect URL from a rendered pass link.

The tag first renders the nested expression, then creates a short URL through The Wallet Crew redirect service, and finally outputs the shortened URL string.

Validate and troubleshoot templates

A variable renders blank

A missing path does not fail the render. It resolves to an empty string. Inspect View data on a real pass, then use default where needed.

A date is shifted or formatted unexpectedly

Dates contain time-zone information. Format the intended output explicitly. Use add_hours only when a known offset is required.

format ignores the pass locale

This is expected. format uses invariant culture. Use date for locale-aware dates. Assemble locale-specific number or currency text in each locale file when needed.

A YAML file does not parse

Quote Liquid values containing :, {, #, or &. Use |- for multi-line values.

A condition behaves unexpectedly

The number 0 and string "false" are truthy. Compare optional numeric values explicitly.

Output has blank lines

Use whitespace-control hyphens around the tags.

Literal Liquid syntax is required

Use raw and endraw.

The template contains a syntax error

Invalid Liquid can render an error message instead of the intended value. Treat parse errors as template defects and fix them before publication.

Use the pass preview in the back-office to test Liquid expressions against real pass data before deploying a template change to production.

For render timing and failure handling outside Liquid itself, see How a pass is rendered.

Standard filters

Standard DotLiquid filters transform strings, numbers, dates, and collections.

Strings

Filter
Example

default

{{ loyalty.points | default: 0 }}

upcase, downcase, capitalize

{{ firstName | capitalize }}

strip, lstrip, rstrip

{{ ticket.name | strip }}

append, prepend

{{ publicUrl | append: tenantId }}

replace, remove

{{ ticket.name | replace: "VIP", "Premium" }}

truncate, truncatewords, slice

{{ id.y2.customerId | slice: 0, 4 }}

split

{{ "a,b,c" | split: "," }}

Use an empty truncation suffix to create an initial:

Numbers and collections

Filter
Example

floor, ceil, round

{{ loyalty.points | default: 0 | floor }}

plus, minus, times, divided_by, modulo

{{ loyalty.points | divided_by: 100 | floor }}

abs, at_least, at_most

{{ balance | at_least: 0 }}

size, first, last, join

{{ tags | join: ", " }}

sort, reverse, uniq, compact

{{ items | sort | reverse }}

map, where

{{ y2.tickets | map: "ticketNumber" | join: ", " }}

Dates, URLs, and HTML

The date filter formats date values for the pass locale.

Expression
Typical output

{{ ticket.startDate | date: "D" }}

Monday, 27 May 2026

{{ ticket.startDate | date: "d" }}

27/05/2026

{{ ticket.startDate | date: "M" }}

27 May

{{ ticket.startDate | date: "t" }}

20:00

{{ ticket.startDate | date: "yyyy-MM-dd HH:mm" }}

2026-05-27 20:00

Use url_encode and url_decode for URL values. Use escape, escape_once, or strip_html for HTML email values.

For the complete filter list, see the DotLiquid reference.

Recipes

The following patterns solve common loyalty, gift-card, and event-ticket needs. Confirm all data paths before use.

Loyalty cards

Display points safely

default prevents a blank balance. floor prevents unwanted decimal points.

Show pending points separately

Only render the pending line when points await validation.

Create a repeating stamp counter

modulo resets the visible counter after each reward.

The same pattern can select a matching image:

Show progress to the next reward

Calculate the remaining points from an editable threshold.

Derive a tier name

This pattern works when the source provides only a points balance.

List available vouchers

Render vouchers on the back of the card. An else branch makes the empty state clear.

Gift cards

Reuse one identifier

Use the same value for the barcode and manual-entry fields.

Display a variable amount

This uses an optional gift amount and a safe fallback.

Keep amount and currency separate

Dedicated fields let wallet platforms apply local currency formatting.

Set the validity window

Use the source dates for expiry and relevance.

Event tickets

Expire after the event

Expiry on the following day avoids time-zone and late-arrival issues.

Set a relevance window

This helps wallet platforms surface the ticket at the right time.

Display the event date and time

Separate fields allow the wallet layout to prioritise date or time.

Map category codes

case converts source codes into readable, locale-specific labels.

Build venue directions

Clean optional fields before concatenating them. Whitespace control keeps the output compact.

List tickets on a multi-ticket pass

This is useful for grouped purchases and multi-event passes.

Create an authenticated deep link

Only use this pattern where the destination supports the pass authentication flow.

FAQ

Is Shopify Liquid fully supported?

No. The Wallet Crew uses DotLiquid plus the custom extensions documented on this page. Shopify-specific extensions should not be assumed to work unless they are documented here.

How can the correct variable path be found?

Use a real pass, inspect View data, then validate the expression in preview. This avoids guessing field names from memory.

Why does a field render blank instead of failing?

Missing variables usually resolve to an empty string. Liquid syntax errors behave differently and should be treated as template defects.

Last updated