Skip to main content

Overview

A recommendation block in a Shopify theme is a Liquid section with a single setting: which Layers block to render. Your section fetches the products. The Layers app embed handles the cross-cutting work on that request: adding shopper identity and cart context, excluding products already shown on the page so blocks don’t repeat each other, and tracking clicks on the results. You only need to:
  1. Add a metaobject section setting so merchandisers pick a Layers block by name, not by typing an ID.
  2. Render a placeholder element with the selected block’s ID.
  3. Call the Blocks API to fill it with products.
A block metaobject’s system handle is not the block ID the Blocks API expects. Layers generates handles as layers-<lowercase block ID> (for example, layers-01j8abcd1234xyz), and the raw block ID is not stored in any metaobject field. Derive the ID in Liquid:
Passing the raw system.handle as blockId silently returns no products. layers-01j... never matches a block ID, so the request misses the block without an error you can trace to it.
Use this version when you’re scripting against the storefront API directly with fetch. For the SDK version, see Rendering blocks with the SDK.

Prerequisites

  • The Layers Shopify app installed with the app embed enabled. The app embed adds cart context, cross-block deduplication, and click attribution to your requests automatically. Your section only needs to fetch products.
  • A storefront token. The app embed emits it on every page as a <script id="layers-config" type="application/json"> tag in the theme <head>. Parse it from JavaScript rather than reading metafields. See Liquid integration.

The section

Create sections/layers-recommendations.liquid. The recommended block picker is a native Shopify metaobject setting that points at the Layers block metaobject definition. The theme editor then lists every Layers block by name, with no option list to maintain.
metaobject_type takes the Layers block definition’s type, app--<app-id>--block. For the Layers app that’s app--278936322049--block, the same type you read with shop.metaobjects['app--278936322049--block']. Use the full string in a theme schema, not the app-scoped $app:block shorthand. The setting returns the selected metaobject, not a block ID. Derive the ID from its system handle with remove_first: 'layers-' | upcase, as in the section above. When no block is selected, the setting is blank and the section renders nothing.

Generating block options in the theme editor

Use one of these alternatives only if your theme can’t use a metaobject setting. Both generate options from the same block metaobjects. select setting. Shopify schema is static JSON, so a select setting can’t list blocks inline. Most themes that use one update the section schema through the Shopify Admin API when the app is installed, with option values already converted to block IDs:
datalist with a text setting. For a Liquid-only path, render a <datalist> from the metaobjects and use a text setting with id block_id. The value is already a block ID, so read it with {% assign selected_block_id = section.settings.block_id %} instead of the handle transform:
With any of the three, the merchandiser selects from the live list of Layers blocks instead of pasting a ULID.

Fetching products

The section renders an empty placeholder with the block ID and the current page’s anchor. A small script fetches products for each placeholder and hydrates it.

Anchors

The section reads the right anchor automatically based on template: The Layers theme app extension supplies cart context and shopper identity to every Blocks request on the storefront, so cart-anchored blocks work without your section reading /cart.js or wiring up productsInCart.

What the app embed handles for you

Once the Layers theme app extension is installed and enabled, you do not need to:
  • Send context.productsInCart for cart-anchored blocks. The embed injects it.
  • Pass excludeProductIds between blocks. The embed adds its IDs to any excludeProductIds you send on every Blocks request, keeping your IDs and including products already on the page: results from other blocks, items in the cart, the product being viewed, and products from the search or collection grid. To turn this off, check Disable block deduplication in the Layers app embed settings in the theme editor.
  • Wire up click attribution or feedback. The embed listens for clicks on rendered cards and submits feedback automatically.
  • Provide identity (deviceId, sessionId). The storefront pixel manages it.
Your section only renders the placeholder and issues the products request.

Empty blocks and fallbacks

The Blocks API runs the block’s fallback chain server-side. If the chain doesn’t produce results, the response is { results: [] }. Hide the section (as the hydrate function in Fetching products does) rather than rendering an empty heading.

Troubleshooting

The section is empty in the theme editor. Make sure the merchandiser has selected a block in the section’s settings. The section hides itself when no block is selected. The block fetches but renders nothing. The block fell through its fallback chain. Review configuration in the dashboard. Cart recommendations look stale after /cart updates. The app embed keeps its cart context up to date when the Shopify cart changes, but it doesn’t re-request blocks that are already on the page. Call your hydrate function again after a cart change (for example, when your cart drawer updates) so the block is fetched with the new cart. If the new request still shows old cart contents, confirm the Layers theme app extension is enabled in Online Store → Themes → Customize → App embeds.

See also