Data sources for lookup lets you create reusable lookup tables and reference them in your feed expressions with the lookup() function. This lets you inject external data (price sheets, category codes, translated labels, sales figures, and more) into each product when the feed is built, without entering values by hand.
Open the feature at Settings → Data sources (/settings/datasources).
Use a data source when you have a key → value table and need to look up that value for each product/variant while the feed is built. For example:
A dedicated price list per SKU or per product group.
A mapping from Shopify product codes to internal supplier IDs / GTINs.
A table for translating category names or custom labels.
Sales figures pulled from Shopify (ShopifyQL) to flag "best sellers".
In short: if you need to "look up a value by key" for every product, use a data source instead of hard-coding it into each rule.
You declare a data source with a Name, Type, Key column, Value column, and a data origin (a CSV URL, a Google Sheet URL, or a Shopify query).
When the feed is built, the app reads the origin and builds a lookup table named t#<Name> — for example, a data source named Pricing sheet produces the token t#Pricing sheet.
In a feed expression you call lookup("{token}", 't#<Name>') to fetch the matching value.
Key points:
In the expression editor (RuleEditor), these tables appear under the Lookup tables group, shown as Table "<Name>".
Only data sources that are actually referenced in a feed's expressions (via the t#<Name> string) are loaded and built. Unused data sources cost no build resources.
Data sources are not built for feeds with Type = API (only file-based feeds apply: CSV, TSV, XML, JSON, etc.).
Each data source must have a unique Name (case-insensitive).
Use a CSV/TSV file hosted at a public URL.
Field | Required | Notes |
|---|---|---|
CSV file URL | Yes | Must be an |
Key column | No | Defaults to |
Value column | No | Defaults to |
The delimiter is auto-detected from the URL: if the URL contains tqx=out:tsv, ends with .tsv, or includes format=tsv, a tab is used; otherwise a comma.
Use a publicly shared Google Sheet.
Field | Required | Notes |
|---|---|---|
Google sheet URL | Yes | Format: |
Sheet title | No | Leave blank to use the first sheet |
Key column | No | Defaults to |
Value column | No | Defaults to |
The sheet must be shared as "Anyone with the link".
Data is read through Google's CSV export endpoint (gviz/tq?tqx=out:csv), so the sheet should be a table with a clear header row.
Use a ShopifyQL query to pull figures from Shopify.
Field | Required | Notes |
|---|---|---|
Query string | Yes | Example: |
Key column | No | Defaults to |
Value column | No | Defaults to |
This type requires the read_reports scope. If it is missing, the UI shows an Additional permission required banner with a Grant access button.
The result's header row is used as column names; Key column and Value column are 1-based positions in the returned result.
Every data source has the following fields (in the top-right of each block):
Name — identifier, required and must be unique. This name is the part after t# in the reference token.
Type — CSV file, Google sheet, or Shopify query.
Key column — 1-based column used as the key.
Value column — 1-based column holding the returned value.
Status badges for each block:
Badge | Meaning |
|---|---|
New | Data source just added, not saved yet |
Modified | Has unsaved changes |
Free | Within the shop's free data source allowance |
Click Save on the save bar (ContextualSaveBar) to save; Discard to revert changes.
Syntax:
lookup(key, map, arrayOption?)
Parameter | Description |
|---|---|
| The value to look up. Usually a product token, e.g. |
| The table reference as a single-quoted string: |
| (Optional) How to handle a key that appears multiple times: |
Example:
lookup('{sku}', 't#Pricing sheet')
If a key appears on multiple rows, values are grouped; use arrayOption to choose:
lookup('{product_id}', 't#Best sellers', 'first')
Inserting the token quickly: in the RuleEditor, open the token list and pick under Lookup tables → Table "<Name>". The t#<Name> token is inserted into the expression.
Besides lookup(), you can reference a table as a variable using the t#<Name> token itself where supported (the table is added to the expression context during a build).
Each data source has a Test button that opens a dialog:
The app loads up to the first 1,000 rows from the origin (LIMIT_SAMPLE_DATA).
Enter a Key to test the lookup.
See the result and the matching expression sample:
lookup('{key}', 't#<Name>') → "value"
Below, the first 100 rows of the loaded data are shown (DISPLAY_SAMPLE_DATA) so you can verify the columns.
Result states:
Display | Meaning |
|---|---|
Not found | The key was not found in the data |
No data | The key was found but the Value column cell is empty |
A normal value | Lookup succeeded |
Note: the Test dialog only searches the first 1,000 loaded rows, not the entire origin.
Lookup tables are cached for 30 minutes under the key s#{shopOrigin}:{t#Name}. Within the cache window, the feed reuses the built table instead of re-fetching the origin.
To apply fresh data immediately, wait for the cache to expire or re-run the feed after the origin has been updated.
Only data sources used in a feed are built → use clear names and remove tables you no longer use.
The feature is a metered add-on: 1 credit per data source in use.
A shop may be granted a number of free data sources (freeDataSourceUnits). Data sources within this allowance show the Free badge.
When the number of data sources exceeds the free allowance, clicking Save triggers billing: the app moves to Shopify's subscription approval flow if the available credits are insufficient. After approval, the change is saved automatically.
There is no usage charge for data sources (credits only).
Symptom | Likely cause | Fix |
|---|---|---|
| The origin failed (bad URL, private sheet, invalid query) | Open Test to see the specific error; check the URL / sharing settings / query syntax |
Lookup always returns "Not found" | Wrong Key column, or the key does not match | Verify the key column in the data; check the value passed as the key |
Empty result even though the key exists | Wrong Value column, or the value cell is empty | Check Value column (1-based); the No data badge points to the value column |
Google Sheet cannot be read | The sheet is not shared publicly | Change sharing to "Anyone with the link" |
Shopify query is blocked | Missing the | Click Grant access on the banner to grant it |
Old data keeps appearing | The table is within the 30-minute cache | Wait for the cache to expire or re-run the feed |
Duplicate data source name error | Name must be unique (case-insensitive) | Use a different name |
Do I need the single quotes around 't#...'? Yes. The table is passed as a single-quoted string, e.g. lookup('{sku}', 't#Pricing sheet').
Will renaming a data source break expressions? Possibly. The t#<Name> token is tied to the data source name, so after renaming you must update any expressions that referenced the old name.
Is Key column / Value column 0-based or 1-based? 1-based (the first column is 1).
A key has multiple values — which one is returned? By default the raw value is returned (which may be an array when a key repeats). Use arrayOption 'first' / 'last' / 'array' to control this.
See also: Add-ons.