> ## Documentation Index
> Fetch the complete documentation index at: https://docs.uselayers.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Banner Injection

> Inject promotional banners into collection grids as a merchandising-rule consequence — hero banners above the grid or inline tiles that overtake or sit alongside product cards.

Banner injection lets a merchandising rule embed promotional media directly into a collection grid. Banners are a rule **consequence** in the same family as [pins](/platform/merchandising/pins): the rule decides *when* a banner shows up (collection, contextual conditions, schedule), and the banner decides *what* shows up.

A banner can be a full-width **hero** above the grid or an inline tile (1×1 or 2×2) that sits inside the grid alongside products. Every rule can carry up to five banners, each with independent **Web** and **Mobile** media.

<Note>
  Banners are emitted as **configuration on the browse response** — they're a passthrough for your storefront to render. Layers does not render banners into your theme directly. See [What ships in the browse response](#what-ships-in-the-browse-response) for the payload shape.
</Note>

## Banner Anatomy

Every banner has:

* A **name** for internal organization (not shown to shoppers).
* **Web Media** and **Mobile Media** — independent images per device. A banner only goes live once both are set.
* A **Mode**:
  * `overtake` — the banner takes the place of a product card in the grid.
  * `inject` — the banner is inserted alongside product cards. Only `inject` banners can carry a click-through `link`.
* A **Per-Device Layout** controlling placement and size:
  * `placement`: `hero` (full-width row above the grid) or `inline` (a cell inside the grid).
  * `width` × `height`: cell span. Inline tiles support `1×1` and `2×2`.
  * `position`: row-major grid cell index (or `null` for unplaced).
* An optional **Schedule** (`schedule_start_at` / `schedule_end_at`) — open-ended on either side.
* Optional **Contextual Conditions** — the same shape as rule-level [contextual conditions](/platform/merchandising/contextual-conditions), evaluated per banner.
* A **Sort Index** that controls the order banners are applied when a rule has more than one.

Each banner has its own on/off state. Hero and inline placements can coexist inside the same rule.

## How Banners Combine With Pins and Expressions

A merchandising rule can carry any combination of pins, sort expressions, variant breakouts, and banners. Banners are layered on top of the underlying product order — they don't reorder products, they take grid space:

* **Hero banners** render before the first product row. They never push products out of the result.
* **Inline `overtake` banners** consume the grid cell at their `position`, displacing the product that would have appeared there.
* **Inline `inject` banners** insert themselves into the grid, shifting products after them by one cell.

Pin drag-and-drop and banner layout are independent — placing a banner doesn't reshuffle pinned products, and re-pinning a product doesn't move banners. A rule that carries banners but no pins, expressions, or variant breakouts is still considered to have an effective impact, so banner-only rules are never silently dropped.

## Scheduling and Targeting

Banners inherit the rule's own scheduling and contextual conditions implicitly — if the rule isn't active for the request, the banner isn't either. On top of that, each banner can carry its **own** schedule and contextual conditions:

* The banner's `schedule_start_at` / `schedule_end_at` window controls when the banner is enabled. Layers checks scheduled banners continuously and toggles the banner's enabled state to match — changes typically take effect within about a minute of the configured time. Browse responses ship whatever banners are currently enabled; the schedule window itself isn't re-checked per request.
* The banner's contextual conditions are evaluated per request and must evaluate `true` for the banner to ship.

This is the same scheduler-driven model used by [rule scheduling](/platform/merchandising/scheduling) and scheduled pins, so banner schedules behave consistently with the rest of merchandising.

In **rule preview**, every enabled banner is shown regardless of its contextual conditions so you can audit the full set you're editing. Live browse traffic always applies them.

## What Ships in the Browse Response

When at least one merchandising rule matches a request and has enabled banners that pass their own gates, the browse response carries a top-level `banners` array. The IDs of the rules that produced them are available on `_meta.appliedRules`. Layers does not render anything into your storefront — your theme is responsible for placing the banner into the grid based on its `placement` and `position`.

```json theme={null}
{
  "resultsPerPage": 24,
  "totalResults": 41,
  "results": [ /* ... */ ],
  "page": 1,
  "totalPages": 2,
  "facets": { /* ... */ },
  "facetRanges": [],
  "banners": [
    {
      "id": "01KWD5S5R50690NXFW32PXM0V2",
      "name": "Willie Nelson Flannel",
      "mode": "inject",
      "link": null,
      "sort_index": 0,
      "web_media": {
        "id": "gid://shopify/MediaImage/30292299612213",
        "alt": null,
        "src": "https://cdn.shopify.com/.../banner-web.jpg",
        "width": 750,
        "height": 1100,
        "source": "store_file",
        "mediaContentType": "IMAGE"
      },
      "mobile_media": {
        "id": "gid://shopify/MediaImage/30292299612213",
        "alt": null,
        "src": "https://cdn.shopify.com/.../banner-mobile.jpg",
        "width": 750,
        "height": 1100,
        "source": "store_file",
        "mediaContentType": "IMAGE"
      },
      "web_layout":    { "placement": "inline", "width": 1, "height": 1, "position": 1 },
      "mobile_layout": { "placement": "inline", "width": 1, "height": 1, "position": 1 }
    }
  ],
  "attributionToken": "01KWYNX0JWTXY4CM0A7D9GDZCT",
  "_meta": {
    "appliedRules": ["bd2d34eb-0d87-4299-90ee-ffeb572a12f6"],
    "appliedSearchRules": []
  }
}
```

Each banner entry carries the following fields:

| Field                         | Type                       | Description                                                                                                                    |
| :---------------------------- | :------------------------- | :----------------------------------------------------------------------------------------------------------------------------- |
| `id`                          | string                     | Banner ULID.                                                                                                                   |
| `name`                        | string                     | Internal name (not shown to shoppers).                                                                                         |
| `mode`                        | `"inject"` \| `"overtake"` | How the banner sits in the grid. `inject` inserts and shifts trailing products; `overtake` replaces the product at `position`. |
| `link`                        | string \| null             | Click-through URL. Only honored on `inject` banners.                                                                           |
| `sort_index`                  | number                     | Application order when a rule has multiple banners. Lower wins on conflicting cells.                                           |
| `web_media`, `mobile_media`   | object                     | Independent per-device media. Both must be present for the banner to ship.                                                     |
| `web_layout`, `mobile_layout` | object                     | Independent per-device layout — see [Layout shape](#layout-shape) below.                                                       |

Each `*_media` object contains `id`, `src`, `alt`, `width`, `height`, `source` (`"store_file"` today), and `mediaContentType` (`"IMAGE"` today).

### Layout shape

Each `*_layout` object is:

| Field       | Type                   | Description                                                                                                                           |
| :---------- | :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------ |
| `placement` | `"hero"` \| `"inline"` | `hero` renders as a full-width row above the grid; `inline` slots into a grid cell.                                                   |
| `width`     | number                 | Cell width. Inline supports `1` or `2`.                                                                                               |
| `height`    | number                 | Cell height. Inline supports `1` or `2`.                                                                                              |
| `position`  | number                 | Row-major grid cell index. For `hero` placement, `position` is not meaningful — render heroes above the grid regardless of the value. |

Pick the layout for the current device (`web_layout` or `mobile_layout`), then:

* For `placement: "hero"`, render above the grid before the first product cell.
* For `placement: "inline"`, place at `position` (row-major) with the banner spanning `width × height` cells. If multiple banners target the same cell, the lower `sort_index` wins.
* If a banner's `mode` is `inject` and a `link` is set, wrap the banner in an anchor.

### Mirrored Metaobjects

Each enabled banner is also mirrored to a `$app:banner` metaobject in your Shopify store, linked back to the rule. Storefront code that prefers reading from metaobjects (e.g. a fully Liquid-rendered grid) can use those alongside the browse-response payload. See [Metaobjects](/shopify-integration/metaobjects-metafields/metaobjects).

## Limits and Behavior

* **Max 5 banners per rule.**
* **Both Web and Mobile media required to go live.** A banner without both slots filled is treated as disabled, even if it's toggled on.
* **Per-device layout is independent.** A hero on web can be an inline tile on mobile, or vice versa.
* **Config history covers banners.** Banner add/edit/remove/reorder is captured in rule [config history](/help/configuration/config-history) snapshots and restored when you roll a rule back.
* **Cache invalidation** runs on any banner change (not just pin/expression changes), so a banners-only edit goes live immediately.

## See Also

* [Rendering banners in Liquid](/developers/rendering-banners-in-liquid) — theme-side render guide for the browse payload.
* [Rendering banners with the SDK](/developers/rendering-banners-with-the-sdk) — SDK equivalent.
* [Pins](/platform/merchandising/pins) — the other per-rule consequence banners are modeled on.
* [Contextual conditions](/platform/merchandising/contextual-conditions) — same shape used for per-banner targeting.
* [Scheduling](/platform/merchandising/scheduling) — same model used for per-banner serve windows.
* [Create a merchandising rule](/help/merchandising/create-merchandising-rule) — dashboard walkthrough.
