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

# Displaying ads

> Where the ad slot goes, which message id to bind it to, and the common 'latest assistant message' pattern.

The ad component (`<InlineAd messageId="..." />` or its platform equivalent) is a **lookup**: it renders whatever ad the SDK has cached under the `messageId` you pass.

The SDK pairs each returned ad with the **latest assistant message** in your conversation — automatically. When you call `addMessage('assistant', { id: 'msg-42', ... })`, that's the id the next available ad is keyed under. So the rule for `<InlineAd>` is simply: **pass the id of the assistant message the ad should appear next to**. Timing is handled for you — whether the preload returns before or after the assistant message arrives, the ad shows up as soon as both are in place.

## The flow

<Steps>
  <Step title="User sends a message">
    Your app calls `session.addMessage({ role: 'user', ... })`. The SDK fires a debounced `POST /preload` in the background while the assistant is still composing its reply.
  </Step>

  <Step title="Assistant replies — with its own stable id (say &#x22;msg-42&#x22;)">
    Your app receives the assistant's message and calls `session.addMessage({ id: 'msg-42', role: 'assistant', ... })`. The SDK links the preloaded ad to this id.
  </Step>

  <Step title="Mount the ad against the assistant id">
    Render `<InlineAd messageId="msg-42" />` directly below the assistant turn in your UI. The SDK looks up the linked ad for `messageId="msg-42"` and renders it inside an iframe, written to continue the assistant's tone.
  </Step>
</Steps>

The ad is bound to the **assistant** message id, not the user message id — even though the preload was triggered when the user message was added. This is how the ad ends up positioned directly under the assistant turn that gave it context.

## The "latest assistant message" pattern

In the vast majority of chat UIs, the ad slot lives directly below the **most recent** assistant message. Render `<InlineAd>` against that message's id and you've covered the common case.

<CodeGroup>
  ```tsx React theme={null}
  {messages.map((m) => (
    <div key={m.id}>
      <Message message={m} />
      {m.role === 'assistant' && m.id === latestAssistantId && (
        <InlineAd messageId={m.id} />
      )}
    </div>
  ))}
  ```

  ```vue Vue theme={null}
  <template>
    <div v-for="m in messages" :key="m.id">
      <Message :message="m" />
      <InlineAd
        v-if="m.role === 'assistant' && m.id === latestAssistantId"
        :messageId="m.id"
      />
    </div>
  </template>
  ```

  ```swift Swift theme={null}
  // In your chat data source, after the latest assistant message:
  let ad = session.createAd(latestAssistantMessageId)
  let adView = InlineAdUIView(ad: ad)
  container.addSubview(adView)
  ```
</CodeGroup>

## Common mistakes

* **Using the user message id.** The user message is what triggers the preload, but the ad is linked to the assistant message that follows. Bind `<InlineAd>` to the assistant message id.
* **Recreating the component on every keystroke.** Use a stable Vue/React `key={messageId}` so the component is not torn down and remounted while content streams in.

## Where to next

<CardGroup cols={2}>
  <Card title="Messages" icon="message" href="/concepts/messages">
    What goes into `addMessage` and why stable ids matter.
  </Card>

  <Card title="Ad formats" icon="rectangle-ad" href="/concepts/ad-formats">
    Inline, interstitial, reward — what each format does and which fits your slot.
  </Card>

  <Card title="Ad lifecycle events" icon="bell" href="/concepts/events">
    What the SDK emits when the ad finally renders.
  </Card>
</CardGroup>
