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.
  • Personalize 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.

:::note Custom fields like these sync automatically with the record they sit on. A whole custom object you defined yourself is different: it only has rows to query after you set up a record-triggered Flow to sync it. See Sync custom objects using flows. :::

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?