Overview
A merchandising rule can attach up to five banners as a consequence. When the rule matches a browse request, the response carries abanners array under that rule’s applied-rule entry — your theme is responsible for placing each banner into the grid.
A banner is either:
- A hero row that renders full-width above the first product cell, or
- An inline tile (1×1 or 2×2) that takes a specific position in the grid, either
overtake(replacing a product) orinject(inserting alongside products and optionally wrapped in a link).
fetch. For the SDK version, see Rendering banners with the SDK.
Prerequisites
- The Layers Shopify app installed and configured. See Liquid integration.
- A working browse implementation that reads from the Layers Browse API — for example, the patterns shown in Rendering facets in Liquid.
- At least one merchandising rule with banners attached. See Add a banner to a rule.
The banner payload
Banners ship under each entry inappliedRules:
- Per-device media and layout. Pick
web_media+web_layouton desktop andmobile_media+mobile_layouton mobile. They’re independent — a hero on web can be an inline tile on mobile. - Mode.
overtakereplaces the product card atposition.injectinserts the banner atpositionand shifts trailing products by one cell. - Link. Only
injectbanners can carry alink. Wrap inject banners in an anchor; render overtake banners as plain media.
Step 1 — Collect banners from the browse response
Flatten the banners across all applied rules in one pass. Sort bysort_index so the lowest index wins when two banners target the same cell.
Step 2 — Pick the right layout for the device
A banner only has a usable layout when both the media slot and the layout for the active device are present. Skip banners that don’t have both filled.Step 3 — Render hero banners above the grid
Hero banners (placement: "hero") render as a row above the first product cell. They never displace products.
host is the container that wraps the grid section — render hero banners on the outside, before the product grid.
Step 4 — Slot inline banners into the grid
Inline banners take aposition (row-major, 0-indexed) and span width × height grid cells. Walk the products and insert banners at their target index. For overtake, replace the product at position. For inject, splice the banner in at position and let trailing products shift.
--span-x / --span-y custom properties (or grid-column: span 2; grid-row: span 2) in your CSS so 2×2 inline banners actually cover four grid cells.
Putting it together
The end-to-end flow on a collection page:Fallback rules
Per Banner Injection:- A banner without both the device’s media slot and layout is treated as disabled —
layoutForDevicereturnsnulland you skip it. - A banner without
web_mediaormobile_mediafilled is never enabled by Layers, so it won’t appear in the payload in the first place. - Banners with
mode: "overtake"ignore anylinkvalue — onlyinjectbanners are clickable.
What the app embed handles for you
The Layers theme app extension does not render banners — that’s your theme’s responsibility. The embed does handle:- Authenticating the browse request (the embed forwards the storefront token and identity).
- Sending the storefront pixel events that track shopper engagement on the underlying collection grid.
block_view/product_click-style payload keyed on data-banner-id.
Troubleshooting
Banners never appear. Confirm the rule is active, bothweb_media and mobile_media are filled, and the rule’s contextual conditions match the request. In the dashboard rule preview, banners are shown regardless of contextual conditions — so a banner that appears in preview but not on the storefront usually means a condition didn’t match.
Inline banner is at the wrong cell. position is row-major and 0-indexed. Verify the device’s *_layout.position matches the cell index you expect when the grid has been flattened to a single array.
Overtake banner dropped a product. That’s by design — overtake replaces the product at position. Use inject if you want to keep all products and shift the trailing ones.
2×2 inline tile renders as a 1×1. Your CSS isn’t honoring width/height. Apply grid-column: span <width>; grid-row: span <height> (or the --span-x/--span-y properties from the snippet above) on banner cells.
See also
- Banner Injection — payload reference and dashboard model.
- Rendering banners with the SDK — SDK equivalent.
- Add a banner to a rule — merchandiser walkthrough.
- Browse API — request and response reference.