> ## 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.

# Showing your first ad

> Wrap your app in <AdsProvider>, feed messages, mount <InlineAd>, observe events.

This is the 5-minute integration walkthrough. Before you start, make sure you've completed [Installation](/sdk/react/installation).

## 1. Wrap your app in `<AdsProvider>`

`<AdsProvider>` initializes a session that's available to every component inside it via the `useAds()` hook. Place it high enough in your tree so it can contain all ad placements.

```tsx theme={null}
import { AdsProvider } from '@kontextso/sdk-react'

function App() {
  return (
    <AdsProvider
      publisherToken="<your-publisher-token>"
      userId="user-1234"
      conversationId="conv-5678"
      character={{
        id: 'character-1234',
        name: 'John Doe',
        avatarUrl: 'https://example.com/avatar.png',
        greeting: 'Hello, how can I help you today?',
      }}
      onEvent={({ name, code, payload }) => {
        // process events
      }}
    >
      <TheRestOfYourApplication />
    </AdsProvider>
  )
}
```

## 2. Feed messages to the SDK

The SDK preloads ads in response to new chat messages. Call `addMessage()` from the `useAds()` hook whenever a user or assistant message is created.

```tsx theme={null}
import { useAds } from '@kontextso/sdk-react'

const { addMessage } = useAds()

// Call this on every user and assistant message in the conversation.
addMessage({
  id: '<unique-message-id>',
  role: '<user | assistant>',
  content: '<content of the message>',
  createdAt: new Date(),
})
```

## 3. Mount `<InlineAd>`

An ad slot is a designated area in your UI where an ad can be rendered. In most cases, it appears below an assistant message.

Place `<InlineAd />` wherever the ad should appear and pass the `messageId` of the assistant message it's associated with.

```tsx theme={null}
import { InlineAd } from '@kontextso/sdk-react'

function MessageList({ messages }: { messages: Message[] }) {
  return (
    <div>
      {messages.map((m) => (
        <div key={m.id}>
          <Message message={m} />
          {m.role === 'assistant' && <InlineAd messageId={m.id} />}
        </div>
      ))}
    </div>
  )
}
```

## Observing events

Subscribe to ad lifecycle events via the `<AdsProvider>` `onEvent` prop. Every event has a stable `name` and a typed `payload`:

```tsx theme={null}
<AdsProvider
  // ...
  onEvent={(event) => {
    switch (event.name) {
      case 'ad.filled':
        console.log('filled:', event.payload.id, 'revenue=', event.payload.revenue)
        break
      case 'ad.clicked':
        console.log('clicked:', event.payload.url)
        break
      case 'ad.no-fill':
        console.log('no fill, skipCode=', event.payload.skipCode)
        break
    }
  }}
>
```

Every placement-attributed event (`ad.filled`, `ad.viewed`, `ad.clicked`, `ad.render-*`, `video.*`, `reward.granted`) also carries a top-level `code` field naming the matched placement, so publishers with multiple `enabledPlacementCodes` can disambiguate. Session-wide events (`ad.no-fill`, `ad.error`) omit it.

For SDK-internal diagnostics during integration, also pass an `onDebugEvent` callback — it receives `(name, data?)` for every internal step.
