# Banners and teasers

Put a campaign's banner or a teaser to another page on a category page, with the condition, window, order and trace of a rule.

A sofa sale belongs on top of the sofa page, and a pointer to the armchairs among the sofas.

A banner is a [rule's](/docs/reference/glossary#rule) effect `place`, not an [entity](/docs/reference/glossary#entity) of the [catalog](/docs/reference/glossary#catalog), so it gets the rule's condition, window, order, [draft](/docs/reference/glossary#draft) and [trace](/docs/reference/glossary#trace). The home store's rule `home/sofa-sale` places two on the sofa page `wohnen/sofas` (wohnen: living):

```json title="tests/fixtures/home/rules.json (trimmed)"
{
    "id": "home/sofa-sale",
    "when": { "category": { "is": "wohnen/sofas" } },
    "then": {
        "place": [
            {
                "slot": "top",
                "banner": {
                    "kind": "banner",
                    "title": { "de": "Sofas im Angebot", "en": "Sofas on sale" },
                    "link": { "to": "category:wohnen/sofas", "filters": { "on_sale": true } }
                }
            },
            {
                "slot": "grid",
                "position": 4,
                "banner": {
                    "kind": "teaser",
                    "title": {
                        "de": "Sessel aus Leder, Samt und Stoff",
                        "en": "Armchairs in leather, velvet and fabric"
                    },
                    "link": { "to": "category:wohnen/sessel" }
                }
            }
        ]
    }
}
```

The banner leads to the sofas on sale, the teaser before the fourth sofa to the armchairs (Sessel). Each also carries a line of text and an image with the words that stand for it. The answer brings them as `placements` ([Category pages](/docs/category-pages#banners-and-teasers)).

**Reference:** [`place`](/docs/reference/release-files/rules#then.place) · [`link`](/docs/reference/release-files/rules#then.place.banner.link) · [`image`](/docs/reference/release-files/rules#then.place.banner.image)

## Where a banner stands

`slot` says where a banner stands, and on which page of the results:

| Slot     | Stands                                | Shows on                      |
| -------- | ------------------------------------- | ----------------------------- |
| `top`    | Above the results                     | The first page                |
| `grid`   | Before the tile at `position`, from 1 | The page that holds that tile |
| `bottom` | After the results                     | The last page                 |

`kind` says how wide: a `banner` spans the results, a `teaser` is the size of a tile. A banner is not a hit, so it changes no total, [facet](/docs/reference/glossary#facet) or order, and paging stays as it is. The search box shows no banners, and neither does an answer that redirects or a `count_only` one.

**Reference:** [`slot`](/docs/reference/release-files/rules#then.place.slot) · [`position`](/docs/reference/release-files/rules#then.place.position) · [`kind`](/docs/reference/release-files/rules#then.place.banner.kind)

## When banners compete

The rule order decides between banners. A preview takes any [release](/docs/reference/glossary#release) files, so you can try a clash without a draft. Put a teaser for the sofa guide, "Welches Sofa passt?" (which sofa fits?), on top of the order, before the fourth sofa:

```sh title="Terminal"
jq '.rules |= [{id: "sofa-guide", description: "Sofa guide before the fourth sofa",
      when: {category: {is: "wohnen/sofas"}},
      then: {place: [{slot: "grid", position: 4, banner: {kind: "teaser", title: "Welches Sofa passt?"}}]}}] + .
    | {url: "/wohnen/sofas", files: {"rules.json": tojson}}' tests/fixtures/home/rules.json \
  | curl -s -H "Authorization: Bearer $key" -H 'Content-Type: application/json' -d @- $api/preview/page \
  | jq -r '.results.trace.steps[] | select(.step == "rules") | .rules[].effects[]? | select(.slot == "grid")
      | "\(.target): asked \(.position), placed \(.placed), \(.reason // .outcome)"'
```

```text title="Answer: 200 · 55 ms · release 5471dabe"
teaser "Welches Sofa passt?": asked 4, placed 4, applied
teaser "Sessel aus Leder, Samt und Stoff": asked 4, placed 5, position 5 is past the last of 4 tiles
```

The new rule is higher, so its teaser takes position 4. The armchair teaser moves to the next free position, 5, which lies past the last of the four sofas, so the page leaves it out.

Top and bottom banners of several rules stand in rule order. A page shows at most 8 banners, the first in rule order, and the trace says why it left any out. The [panel](/docs/reference/glossary#panel) marks a banner that lost its position **In conflict**.

**Reference:** [`placements_per_page`](/docs/reference/limits#placements_per_page) · [`placed`](/docs/reference/trace#rules.rules.effects.placed)

## Add a banner

A new banner is a new rule at the top of the order, and it waits in a draft until you publish it. A campaign's window is its rule's schedule ([Rules](/docs/rules)).

**In the panel:**

**Merchandising → Banners** lists every banner the rules place, in rule order, with where and when it shows and its state: **Live**, **Scheduled**, **Ended**, **Off** or **In conflict**.

Click **New banner**, and fill in the sheet:

1. **Category page:** Sofas. **Other pages or searches** opens the whole condition instead.
2. **Place:** **Among the products**, **Before product** 2.
3. **Kind:** **Teaser, the size of a product**, then its **Title** in each language. An image needs its **Image description**.
4. **Leads to:** **A content page**, the sofa guide.
5. **Save**, which starts a draft if none is open.

The sheet draws the banner as the storefront will, and **Starts** and **Ends** under **When** give it a window. The bar above the list then says how the draft goes live, and **Publish** takes it there. On **Rules**, a rule that places banners leads here with **Change its banners**.

**Through the API:**

Start a draft and add the rule with the fields the panel edits; the API writes `rules.json` from them. The teaser stands before the second sofa:

```sh title="Terminal"
draft=$(curl -s -X POST -H "Authorization: Bearer $key" -H 'Content-Type: application/x-ndjson' \
  --data-binary @tests/fixtures/home/catalog.jsonl "$api/imports?name=catalog.jsonl" | jq -r .import.id)
version=$(curl -s -H "Authorization: Bearer $key" $api/imports/$draft | jq -r .version)
jq -n --arg version "$version" '{version: $version, name: "Sofa guide among the sofas", fields: {
    when: {trigger: {kind: "category", category: "wohnen/sofas"}},
    then: {place: [{slot: "grid", position: 2, banner: {kind: "teaser",
      title: {de: "Welches Sofa passt?", en: "Which sofa fits?"}, link: {to: "content:guide-sofa-finden"}}}]}}}' \
  | curl -s -H "Authorization: Bearer $key" -H 'Content-Type: application/json' -d @- $api/imports/$draft/rules \
  | jq -r '.rules.rules[:2][] | "\(.position). \(.summary)"'
```

```text title="Answer: 201 · 70 ms"
1. Places teaser "Welches Sofa passt?" at 2 on "Sofas"
2. Places banner "Sofas im Angebot" on top, places teaser "Sessel aus Leder, Samt und Stoff" at 4 on "Sofas"
```

Preview the sofa page with the draft's files:

```sh title="Terminal"
curl -s -H "Authorization: Bearer $key" $api/imports/$draft \
  | jq '{url: "/wohnen/sofas", files}' \
  | curl -s -H "Authorization: Bearer $key" -H 'Content-Type: application/json' -d @- $api/preview/page \
  | jq -c '.results.placements[] | del(.text, .image, .link)'
```

```json title="Answer: 200 · 6.8 ms · release 6425cef5"
{"slot":"top","kind":"banner","title":"Sofas im Angebot","rule":"home/sofa-sale"}
{"slot":"grid","position":2,"kind":"teaser","title":"Welches Sofa passt?","rule":"sofa-guide-among-the-sofas"}
{"slot":"grid","position":4,"kind":"teaser","title":"Sessel aus Leder, Samt und Stoff","rule":"home/sofa-sale"}
```

Both teasers show now, the guide's before the second sofa. Publishing takes the draft live:

```sh title="Terminal"
curl -s -X POST -H "Authorization: Bearer $key" $api/imports/$draft/publish | jq -r .next
```

Here, discard it instead:

```sh title="Terminal"
curl -s -X DELETE -H "Authorization: Bearer $key" $api/imports/$draft | jq -r .state
```

```text title="Answer: 200 · 17 ms"
discarded
```

**Reference:** [`POST .../rules`](/docs/reference/management-api#create-rule) · [`POST /api/v1/preview/page`](/docs/reference/management-api#preview-page)

## Next

- [Category pages](/docs/category-pages): the placements an answer carries and where a storefront draws them.
- [Rules](/docs/rules): conditions, schedules and the rule order.
- [Pages and their filters](/docs/pages): the filters and sorting of the same sofa page.
