# Verify custom data is available in Liquid

Source: https://support.storeconnect.com/articles/verify-custom-data-in-liquid · Last modified 21 August 2026

A mapped custom field that renders as blank has two very different causes, and they look identical on screen:

- The value never reached the store, so there is nothing to render.
- The value is present, but the accessor in your template is wrong.

Guessing between them wastes time. Use this process to establish which one you have before changing any Liquid.

## Before you start

- You need edit access to the template you are debugging, so you can add a few temporary lines to it.
- To complete Step 3 or the POS setup below, you need a POS register you can open and resync, and permission to create **Custom Data Mappings** and **POS Layouts**.

## Step 1: List the keys the drop actually holds

Every Liquid drop that supports custom data exposes a `data` collection. Loop over it and print the key names, rather than testing one field at a time.

Add these lines to the template where the field renders blank, on the page you are debugging.


```liquid

KEYS: {% for pair in current_customer.data %}{{ pair[0] }},{% endfor %}
```


To see the values as well:


```liquid

{% for pair in current_customer.data %}
  {{ pair[0] }} = {{ pair[1] | default: '(blank)' }}
{% endfor %}
```


Swap `current_customer` for whichever drop you are working with, such as `product`, `cart`, or `current_order`.

Read the result as follows.

| Output | Meaning | What to do |
|--------|---------|------------|
| Your field name appears | The data is present | Fix the accessor, see Step 2 |
| Other keys appear, yours does not | That field is not mapped or has not synced | Check the Custom Data Mapping and field-level security |
| Only internal keys such as `_record` and `_keyMap` | The drop carries no custom data | Stop testing syntax, see Step 3 |
| Nothing at all | The drop is empty or unresolved | Confirm the record is loaded, for example that a customer is attached to the cart |

:::tip
Run this on the storefront and in the POS separately. They resolve custom data through different mechanisms, so a field can be present in one and absent in the other.
:::

## Step 2: Confirm the accessor

If the key is listed, the value is there and only the accessor is at fault. All three of these are valid:


```liquid

{{ current_customer.data['customer_since__c'] }}
{{ current_customer.data.customer_since__c }}
{% assign key = 'customer_since__c' %}{{ current_customer.data[key] }}
```


Use the lowercase Salesforce column name. Bracket notation is the safest form, and it is the only option when the key is held in a variable.

## Step 3: Check what reached the device (POS only)

The POS renders against a local copy of the data held in the browser's IndexedDB, not against Salesforce. Liquid cannot read that store, so check it from the browser console with the POS open.

```js

(async () => {
  const name = window.storageKey ? `storeconnect__${window.storageKey}` : 'storeconnect';
  const db = await new Promise((res, rej) => {
    const r = indexedDB.open(name);
    r.onsuccess = () => res(r.result);
    r.onerror = () => rej(r.error);
  });
  console.log('stores:', [...db.objectStoreNames]);
  const rows = await new Promise((res) => {
    const t = db.transaction('contact').objectStore('contact').getAll();
    t.onsuccess = () => res(t.result);
    t.onerror = () => res([]);
  });
  console.log('records:', rows.length);
  console.log('columns:', rows[0] && Object.keys(rows[0]).sort());
  console.log('sample:', rows[0]);
})()
```

Change `contact` to the object store you are testing. Store names are lowercase Salesforce table names, such as `product2`, `order`, or `s_c__cart__c`.

What the output tells you:

- **`columns` includes your field** — the data is on the device, so the problem is in the template.
- **`columns` shows only core fields** — the POS was never told to fetch the field, so it was left out of the sync. Follow [Make a custom field available in the POS](#make-a-custom-field-available-in-the-pos) below.
- **`records: 0`** — the store exists but holds no records for this device, so nothing will render from a layout over that object. Check the sync settings and whether records exist for the register's outlet.
- **The store is missing from `stores`** — that object is not synced to the POS at all.

## Make a custom field available in the POS

The storefront and the POS resolve custom data differently. On the storefront a **Custom Data Mapping** is enough on its own. The POS holds a defined set of columns per object and fetches an extra column only when a **POS Layout** references it, so a mapping alone is not enough.

1. Open the **POS Layouts** list and create a layout for the object. Any **Type** works, and the layout does not need to be mounted anywhere. It can exist purely to register the fields.
2. Add a **POS Layout Field** to that layout for each field you want, setting **Field Name** to the field's API name in all lowercase, for example `customer_since__c`. This works for fields on both standard and custom objects. A **POS Layout Filter**, or a field named in the layout's **Sort**, registers a field the same way.
3. Create the **Custom Data Mapping** for each field, setting **Object API Name** and **Field API Name** to match the Salesforce field, for example `Contact` and `Customer_Since__c`. Adding a mapping triggers a full repoll from Salesforce, so the POS fetches the new columns as part of it.
4. Resync the POS.

If the mapping already existed before you added the layout field, the repoll has already run and the field will be blank on the device. Resync all POS data to pick it up.

:::warning
Adding fields to a POS **list** layout replaces its default columns rather than adding to them. Create a separate unmounted layout to register fields, rather than adding them to a layout that drives a live screen such as `customer_list`.
:::

To correct a mapping, delete it and create a new one. Editing an existing **Custom Data Mapping** does not trigger a repoll, so the corrected field is never backfilled.

Once synced, read the field the same way as anywhere else.


```liquid

{{ current_customer.data['customer_since__c'] }}
```


Run Step 1 again to confirm the outcome: the key now appears in the drop's `data` collection, and the console check in Step 3 lists it under `columns` on the device.

### Which objects can reach the POS

**Order**, **Order Item**, and **Shipment** are supported in POS Layouts, but they are not part of the POS's default data set. Each one reaches the device only once a layout references it, so they follow the same steps above.

**Payment** is never downloaded to the POS, so its mapped fields cannot be read in a POS template however they are mapped. Referencing **Payment** in a POS Layout does not make it available, and no records arrive for it. Read payment data on the storefront instead.

---

## Follow StoreConnect

- [Email Newsletter](https://getstoreconnect.com/c/lp-newsletter)
- [LinkedIn Newsletter](https://www.linkedin.com/build-relation/newsletter-follow?entityUrn=7444956928444862464)
- [YouTube](https://www.youtube.com/channel/UCngKdP2x8l1wcbAKW3tvU8g)
- [LinkedIn](https://www.linkedin.com/company/storeconnect)
- [X / Twitter](https://x.com/storeconnecthq)

## Popular Links

- [Partners](https://getstoreconnect.com/partners)
- [News](https://getstoreconnect.com/articles/news)
- [Events](https://getstoreconnect.com/articles/events)
- [Feature Comparison](https://getstoreconnect.com/how-we-compare)
- [Download a free trial](https://appexchange.salesforce.com/appxListingDetail?listingId=a0N3A00000FMkeKUAT)
- [Book a Demo](https://getstoreconnect.com/contact)

## Documentation

- [Help documentation](https://support.storeconnect.com/help-documentation)
- [AI agents](https://support.storeconnect.com/ai)
- [Videos & tutorials](https://support.storeconnect.com/videos-tutorials)
- [Developer reference](https://support.storeconnect.com/developer-reference)
- [Release notes](https://support.storeconnect.com/release-notes)
- [Troubleshooting](https://support.storeconnect.com/troubleshooting)
- [Trust Center](https://trust.getstoreconnect.com/)
- [Status Page](https://status.storeconnect.com/)

## Contact

- info@getstoreconnect.com
- US +1 415 745 3230
- AUS +61 2 8365 2308

100 S Ashley Dr, Suite 600-2461
Tampa FL 33602-600 USA

Level 22, Sydney Place
180 George Street
Sydney, NSW, 2000, AUS

---

StoreConnect Support — https://support.storeconnect.com/articles/verify-custom-data-in-liquid