Skip to content
Log in

Display dynamic content using Liquid queries

On this page

The Liquid query tag fetches records from a Salesforce object directly inside a Liquid template, so you can present dynamic content powered by real-time data without custom code.

This article covers the patterns you reach for most often. For the full technical reference — every operator, ordering, distance calculations, error messages, and limitations — see Liquid query (full reference).

:::tip Reach for the standard global drops first (current_store, current_account, current_cart, product, current_account.orders …). They are pre-computed, scoped to the current store, and far cheaper than running a query. Use query when no global already exposes what you need. :::

Common use cases

  • Render a custom landing page from a slug by querying Product2 with s_c__slug__c.
  • Personalise content for an account or store by querying account/store-related records via sfid or s_c__store__c.
  • Display only currently active records by filtering on date, time, or numeric ranges (e.g. promotion windows, availability periods).
  • Build curated or related-item lists by querying multiple records at once with an IN (array) condition.
  • Sort by distance from a point (e.g. nearest collection points) using a distance struct — see Liquid query (full reference).

How Liquid queries work

  • Query a Salesforce object using its API name (e.g. Product2, Account, s_c__Promotion__c).
  • Filter records using one or more conditions — all conditions are joined with AND.
  • Conditions support strings, numbers, dates, times, datetimes, and booleans.
  • The result is a list of records you can iterate with a Liquid for loop.
  • Field names are the column names on the experience-site database, including the s_c__ prefix and __c suffix on StoreConnect-managed fields.

Basic query syntax

liquid {%- query 'ObjectName' as variable_name, field1: 'value1', field2: 'value2' -%}

Component Description
ObjectName Salesforce object API name (e.g. Product2, Account, s_c__Tag__c).
as variable_name Name of the Liquid variable that will hold the result set.
Conditions Field/value pairs used to filter records — field names are API/column names.

Examples

Fetch every record (no conditions)

liquid {%- query 'Product2' as records -%}

Filter by a field value

liquid {%- query 'Account' as records, s_c__sc_id__c: '9876' -%}

Multiple conditions (AND)

liquid {%- query 'Contact' as records, firstname: 'John', lastname: 'Doe' -%}

Filtering patterns

String equality is case-insensitive

String equality is case-insensitive automatically — both sides are lowercased before comparison. You don’t need any prefix or special syntax.

liquid {%- query 'Product2' as records, s_c__slug__c: 'PRODUCT-SLUG' -%} {# matches 'product-slug', 'Product-Slug', etc. #}

LIKE / wildcard matches

Use % as a wildcard. LIKE patterns are also case-insensitive.

liquid {%- query 'Product2' as records, name: 'My%' -%} {# starts with "My" #} {%- query 'Product2' as records, name: '%Product' -%} {# ends with "Product" #} {%- query 'Product2' as records, name: '%My%' -%} {# contains "My" #}

IN queries (match any of a list)

liquid {%- query 'Product2' as records, s_c__slug__c: ['product-1', 'product-2'] -%}

Build the list dynamically:

liquid {%- new List slugs = ['product-1', 'product-2'] -%} {%- query 'Product2' as records, s_c__slug__c: slugs -%}

liquid {%- assign slug2 = 'product-2' -%} {%- query 'Product2' as records, s_c__slug__c: ['product-1', slug2] -%}

Comparison queries (numbers, dates, times, datetimes)

Use >, >=, <, <= inside a string for ranges:

liquid {%- query 's_c__Promotion__c' as records, s_c__usage_limit__c: '>10' -%} {%- query 's_c__Availability__c' as records, s_c__start_date__c: '<2026-01-01' -%} {%- query 's_c__Availability__c' as records, s_c__start_time__c: '>=14:30' -%} {%- query 'Order' as records, s_c__submitted_date__c: '>=2026-01-01T00:00:00Z' -%}

:::warning An invalid date or time value (e.g. '>2023-21-02') returns zero results silently — it does not raise. Validate user-supplied dates before using them in a query. :::

Custom data fields

Salesforce custom fields surfaced through Custom Data Mappings are stored in a custom_data jsonb column. Filter them with the data. prefix:

liquid {%- query 'Product2' as records, data.color__c: 'blue', data.material__c: 'suede' -%}

A Custom Data Mapping must exist for each field you reference. Without one, the tag raises Invalid liquid query field.

Ordering

Add an order by clause at the end of the tag — the clause must be quoted:

liquid {%- query 'Product2' as records order by 'createddate desc' -%} {%- query 's_c__Availability__c' as records order by 's_c__end_date__c, name desc' -%}

Limiting results

There is no native limit keyword. Use the standard Liquid for ... limit: modifier on the loop, or wrap the loop in paginate for full pagination — see Paginate tag reference:

liquid {%- query 'Product2' as records order by 'createddate desc' -%} {%- for record in records limit: 10 -%} {{ record.name }} {%- endfor -%}

Access query results

Iterate the result with a for loop:

```liquid {%- query ‘Product2’ as records -%}

{%- for record in records -%} {{ record.name }} {{ record.sfid }} {{ record[‘s_c__slug__c’] }} {%- endfor -%}

{# total count #} {{ records.size }} ```

Helpful record filters

```liquid {# all attribute names available on the record #} {{ record | record_fields | join: ‘, ‘ }}

{# the record’s table name #} {{ record | record_name }}

{# cast the generic record into its full StoreConnect drop #} {%- assign product = record | cast: ‘Product’ -%} {{ product.images.first.url }}

{# inverse: drop -> generic record #} {%- assign record = product | recordize -%} ```

Things to keep in mind

  • Queries are not store-scoped. Records from every store in the org are returned. If you only want the current store, filter explicitly (e.g. s_c__store__c: current_store.sfid).
  • All conditions are joined with AND, never OR. To union results, run two queries and merge them with | concat | uniq.
  • No joins, no aggregation, no SELECT projection. Each query loads every column on a single object.
  • Each query tag is a database call. Don’t run a query inside a hot loop — fetch once into a variable and iterate that.
  • Object and field names are the API/column names. Standard Salesforce columns use their plain names (name, sfid, firstname); StoreConnect-managed fields use s_c__…__c.

For the full operator matrix, ordering rules, distance calculations, error messages, and the complete limitations list, see Liquid query (full reference).

Was this article helpful?

Was this article helpful?