Skip to main content
This page is aimed at a merchant’s app developers: the people building a native mobile app or a custom (headless) storefront that should show the same merchandised collection pages as the web storefront.
The Depict app publishes everything it produces into your own Shopify store:
  • The product order of each collection is written to the collection itself as a manual sort order. A plain Storefront API query for the collection’s products, in default order, returns the merchandised order.
  • Content blocks (banners, images, videos, text tiles), image settings (per-collection product image overrides), product duplicates (a product shown a second time with its own imagery) and per-market product orders are stored as Shopify metaobjects, referenced from metafields, all with storefront access PUBLIC_READ.
There is no Depict API in the read path. Everything below is served by Shopify, with Shopify’s availability, caching and CDN. Depict resolves drafts, versions and scheduled publishes server side at publish time, so the references you read through the paths on this page always point at the published state. For how to lay the data out on screen, see the collection grid rendering specification.

Prerequisites

  • A Storefront API access token for the shop. Any token works; the data is public read. Use a recent API version (the examples use 2026-07).

Namespaces

Depict creates its metafield definitions under Shopify’s app-reserved namespaces ($app:content-blocks and so on). To every other API client, including your storefront token, an app-reserved namespace appears in the concrete form app--{app-id}--{namespace}. The Depict app’s ID is 93504864257 on every store, so the namespaces are: Metaobject types (depict_content_block, depict_image_setting, depict_product_duplicate, depict_market_products, depict_multi_market_collection) are not app-prefixed and are the same on every store. You may also come across sibling metafields whose namespaces end in -versions (for example app--93504864257--content-blocks-versions). They hold Depict’s internal draft and version bookkeeping, which includes unpublished state. Ignore them; the paths on this page only ever reference the published state.

The data model at a glance

Product order

The Depict app sets the collection’s sort order to manual and writes the merchandised order into the collection with the Admin API. That means the default Storefront API product listing is already the merchandised order, no extra work needed:
Notes:
  • Do not pass a sortKey. The default sort is the collection’s own order, which is the merchandised order.
  • Page through with after until hasNextPage is false; 250 is the maximum page size.
  • @inContext(country: ...) scopes prices and product availability to the buyer’s market. It does not change the ordering. Market-specific orderings come from the per-market metaobjects described below.

Content blocks

Content blocks are depict_content_block metaobjects, referenced in display order metadata from the collection metafield. Each block carries placement fields (where it sits in the grid) and content fields (what it shows).
An illustrative response for a collection with one image block:
A list metafield can reference more entries than one request returns: real stores exceed 100 image settings or duplicates on a single collection. first is capped at 250, so page through references with after: endCursor until hasNextPage is false, exactly like the products connection. This applies to the content block, image setting and product duplicate queries alike.

Block fields

Fields the merchandiser left unset read as empty strings (the app writes empty strings to clear previous values) or, on blocks created before a field was added to the definition, come back as null or are absent. Treat empty, null and absent identically: a field counts as set only when it has a non-empty value. The text JSON has this shape (all fields optional unless noted):
html_tag is required inside header/body; alignments default to center; text color defaults to white. Ignore JSON keys you do not recognize: the default-language value can contain internal bookkeeping (such as a translations map) that you should not render. Use @inContext(language: ...) to get localized text instead, see Translations.
Forward compatibility: a block may in the future carry a content field (a metaobject reference). When it is set, read the media, link and text fields from the referenced metaobject and keep reading the placement fields (index, span_rows, span_columns, aspect_ratio, visibility) from the block itself. Blocks without content work as described above.

Media URLs

Image URLs are standard Shopify CDN URLs. Request appropriately sized variants with query parameters, for example ...campaign.jpg?width=1024 or, to match a container of known aspect ratio, ...?width=1024&crop=center&height=683. The web renderer requests widths from 128 to 4096 depending on the rendered size; native apps should do the equivalent for their screen densities. For video, the web renderer prefers the HLS playlist on mobile (adaptive bitrate) and the largest MP4 on desktop, and plays it muted, looped, inline, only while visible.

Image settings

Image settings override which images represent a product inside one specific collection (they do not affect the product elsewhere).
Semantics: for the referenced product, render default_image as the product card’s primary image in this collection. If your card design shows a hover or second image and hover_image is set, use it for that. default_image is always set; hover_image is optional.

Product duplicates

A duplicate shows a product an extra time in the grid, with its own imagery, at a chosen position.
Semantics:
  • Render the referenced product a second time, using the duplicate’s default_image (and hover_image if set) instead of the product’s images. Everything else on the card (title, price, link) is the product’s own.
  • index, when set, is the target position in the combined products-plus-duplicates list. When index is null, the duplicate goes directly after its original product. created_at (a Unix timestamp in milliseconds) orders multiple duplicates of the same product.
  • Image settings do not apply to duplicates; a duplicate always uses its own imagery, even when its original product has an image setting.
  • The metaobject handle is a stable identifier for the duplicate, useful as a list key.
The exact insertion algorithm, including edge cases, is in the rendering spec.

Markets

When a collection has market-specific merchandising, Depict publishes a depict_multi_market_collection metaobject per (collection, market). Its handle is deterministic:
where both IDs are the numeric parts of the Shopify GIDs (for example collection gid://shopify/Collection/402462310713 and market gid://shopify/Market/37750866085 give collection_402462310713_market_37750866085). Get the buyer’s market ID from the Storefront API itself:
Then fetch the market’s overrides by handle:
(Select the same inner fields on the referenced block, duplicate and image setting metaobjects as in the per-piece queries above; they are the same metaobject types. The metaobject also carries required collection_reference and market_id fields, which back the handle scheme; you do not need them for reads.)

Fallback rules

For each of the four pieces, resolve the market’s data like the web storefront does:
  1. If the depict_multi_market_collection metaobject for (collection, current market) exists and the piece’s field is set, use it.
  2. Otherwise use the default: the collection metafield for blocks, duplicates and image settings, and the collection’s own product order for ordering.
Fallback is per piece: a market can override just the product order while inheriting the default blocks, or the other way around.

Per-market product order

The product_order field references a depict_market_products metaobject holding the full ordered product list, split across 40 fields products_0 through products_39, each a list.product_reference of up to 128 products (5120 products maximum). Concatenate the chunks in field order, skipping empty ones; check all 40 fields rather than stopping at the first empty chunk (chunks are written contiguously, but scanning all 40 matches the web storefront and is robust). Products that are not published to the current country resolve to null in the references; skip them.

Translations

Content block text is localized through Shopify’s native translations. Add @inContext(language: ...) to your query and the text field’s value comes back in that locale (with the header and body text swapped to the translation and all styling preserved):
Only the text field is translated. Other fields, including alt_text, are deliberately kept identical across locales.

Publishing model and freshness

  • Merchandisers work with drafts and versions inside Depict. None of that is part of your read path: publishing (immediate or scheduled) updates the collection sort order, the collection metafields and the per-market metaobjects to the published state, and those are the only things the queries on this page read.
  • Collection reordering is applied by Shopify as an asynchronous job, so a fresh publish can take a short moment to be fully visible.
  • Scheduled publishes are applied by Depict on a schedule; expect a scheduled version to be live within about 30 minutes of its scheduled time.
  • Cache freely. All of this data changes only when the merchant publishes. Re-fetching per screen view, or on a minutes-level TTL, is plenty.

Matching the web storefront

A few behaviors worth mirroring for a consistent experience:
  • Content blocks and duplicates are positional. The web storefront hides both whenever the shopper applies a different sort order or filters (except a pure in-stock availability filter). Do the same when your app re-sorts or filters a collection. Image settings still apply in sorted and filtered views.
  • Column counts come from the shop metafield column_settings ([desktopColumns, mobileColumns], defaults 4 and 2). Using the merchant’s configured counts makes block placement match what the merchandiser designed. Block indexes are authored against the desktop count; the rendering spec’s remapping algorithm keeps blocks anchored to the same products when you render fewer columns. The shop metafield grid_settings (JSON) additionally carries the web grid’s spacing values, for example {"desktop": {"columnSpacing": "8px", "rowSpacing": "8px", "margin": ""}, "mobile": {...}}, plus web-renderer options (customCss, removeProductCardPadding, alignBlocksToImage), if you want visual parity.
  • During a Depict collection A/B test, the collection carries an ab_test_v3 metafield (namespace app--93504864257--ab-test) referencing depict_ab_test_v3 metaobjects that hold the test window. While a test is running, web sessions randomly assigned to the control group hide content blocks, duplicates and image settings. A native app that ignores this always shows the treatment, which skews the merchant’s test results; if a test is active, consider splitting sessions the same way or agreeing with the merchant on how app traffic should count.
For the full, testable layout algorithm, continue to the collection grid rendering specification.