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

# Ad lifecycle

> Ask, load or reject, show, end. What the SDK holds for you, when it lets go, and the one callback you implement.

Every ad goes through the same stages, and each stage is one call. The SDK holds at most one unshown ad per format, so you can ask early, keep it, and show it when the moment comes.

![format(), load(), show(), didEnd in a row; reject() and ending before show as side exits](https://mintcdn.com/kontext/a1TZynXEvVvAGivH/images/video/lifecycle.svg?fit=max\&auto=format\&n=a1TZynXEvVvAGivH\&q=85\&s=19e668ed8881d1e0a1b397950be781d9)

## 1. Ask

`format()` asks the server for an ad and returns it. Its one parameter is the format you want: `.overlay`, `.pause` or `.linear`. Ask when the episode opens, not at the moment you want to show the ad.

* **One unshown ad per format.** Calling `format()` again for the same format returns the same ad until it is shown, rejected, or dropped.
* **No fill is normal.** `format()` throws `noFill(reason:)` when the server had nothing. The SDK never retries by itself; ask again at your next moment. The reasons are listed in the [API reference](https://docs.kontext.so/video/sdk/swift/api.md#videoaderror-nofillreason).

## 2. Load or reject

* `load()` renders the creative off screen and returns once it is ready to draw: an image ready to draw, a video with its first frame buffered. Loading fires nothing billable. Calling it again returns at once; two concurrent calls share one load.
* `reject()` tells the server you will not use the ad, loaded or not. The server tells the advertiser.

## 3. Show

`show()` either throws, and nothing happened, or the ad is on screen. From that moment the SDK retains the ad whatever you do with your reference, counts the impression, tracks every later event, and measures viewability.

* **One ad on screen** in the whole app. A second `show()` throws `anotherAdShowing` and leaves that ad ready.
* **An ad is shown only once.** Calling `show()` on the same ad again throws `alreadyShown`; ask for the next one.
* **The view matters.** Overlay and pause ads go into the view your content plays in; the SDK sizes them for it, and throws `containerTooSmall` rather than draw an illegible creative.

## 4. On screen

While the ad is on screen, the SDK runs it for you and tells your delegate what happens: the impression when it counts, each tap on the ad, and a failure if the creative breaks. Nothing arrives before `show()`, and there is nothing for you to do until the ad ends.

## 5. End

Exactly one `didEnd(reason)` per shown ad, whoever ended it. Put your resume logic there and nowhere else. For an overlay or pause ad it runs synchronously, even when the end came from your own `dismiss()` or `destroy()` call; for a linear ad it runs once the full-screen dismissal has finished, so presenting your next screen from it is safe. The reason says who ended it; every reason is in the [API reference](https://docs.kontext.so/video/sdk/swift/api.md#videoad-endreason).

## Expiry

Every ad has a lifetime set by the server. Once it expires, `load()` and `show()` throw `invalidated(.expired)` and the next `format()` returns a fresh ad; an ad already on screen is never affected.

## Destroy

Call `ads.destroy()` when the viewer leaves the video. Every held ad is dropped and the advertiser told it was not used, the ad on screen ends with `didEnd(.destroyed)`, WebViews are released, and a request or load in flight throws `destroyed`.

## Where to next

> **[Targeting](https://docs.kontext.so/video/concepts/targeting.md)**
>
> What to send so ads match the episode and the viewer.

> **[Showing your first ad](https://docs.kontext.so/video/sdk/swift/first-ad.md)**
>
> The lifecycle in code, in ten minutes.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.