> For the complete documentation index, see [llms.txt](https://series-1.gitbook.io/rundot-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://series-1.gitbook.io/rundot-docs/v5.21.0/readme/ads.md).

# Ads API

Monetize your game with rewarded videos and interstitials. The host manages presentation; your game just requests placements and reacts to the result.

{% hint style="warning" %}
All SDK methods can reject; unhandled rejections crash the app. Always wrap SDK calls in `try/catch` or attach a `.catch()` handler. See [Error Handling](/rundot-docs/v5.21.0/readme/error-handling.md) for details.
{% endhint %}

{% hint style="danger" %}
Ads are not currently supported on Desktop.\
Calling the Ads API on Desktop will show a universal link to the mobile app.
{% endhint %}

## Ad Types

### Rewarded Video Ads

Opt-in ads where players receive rewards for watching. Players choose to watch these ads in exchange for in-game benefits.

```typescript
const isReady = await RundotGameAPI.ads.isRewardedAdReadyAsync()
if (isReady) {
  const rewardEarned = await RundotGameAPI.ads.showRewardedAdAsync()
  if (rewardEarned) {
    grantReward() // Player earned the reward
  }
}
```

{% hint style="info" %}
`showRewardedAdAsync()` resolves `true` only when the reward was actually earned. A `false` result covers both "the ad was never shown" and "the ad was shown but the player closed it early". Treat the boolean as your grant gate, not as a "the ad played" signal. The host does not surface a separate "shown" flag for rewarded ads.
{% endhint %}

**Use cases:**

* Extra lives or continues
* Bonus currency
* Speed up timers
* Unlock temporary power-ups

### Interstitial Ads

Forced ads that interrupt gameplay at natural break points. These ads are automatically hidden for platform subscribers.

```typescript
const isReady = await RundotGameAPI.ads.isInterstitialAdReadyAsync()
if (isReady) {
  // Show interstitial at level transition
  await RundotGameAPI.ads.showInterstitialAd()
  // Gameplay resumes after ad completes or is skipped
}
```

**Use cases:**

* Between levels
* After game over
* After completing a session
* On menu transitions

> **Note**: Interstitial ads are hidden for users with platform subscriptions. Your code can safely call `showInterstitialAd()` for all users: subscribers simply won't see the ad.

## Quick Start

```typescript
import RundotGameAPI from '@series-inc/rundot-game-sdk/api'

const isReady = await RundotGameAPI.ads.isRewardedAdReadyAsync()
if (isReady) {
  const rewardEarned = await RundotGameAPI.ads.showRewardedAdAsync()
  if (rewardEarned) {
    grantReward()
  }
}
```

## Complete Example

```typescript
// Rewarded ad button handler
async function onWatchAdForReward() {
  const isReady = await RundotGameAPI.ads.isRewardedAdReadyAsync()
  
  if (!isReady) {
    showMessage('No ad available right now')
    return
  }
  
  try {
    // Pass placement metadata so the reward shows up correctly in attribution/analytics
    const rewardEarned = await RundotGameAPI.ads.showRewardedAdAsync({
      adDisplayId: 'extra_life',
      adDisplayName: 'Extra Life Reward',
    })
    if (rewardEarned) {
      grantBonus(100) // Give the reward
      await RundotGameAPI.analytics.recordCustomEvent('rewarded_ad_complete', {
        reward: 'bonus_100',
      })
    }
  } catch (error) {
    console.error('Ad failed:', error)
  }
}

// Interstitial between levels
async function onLevelComplete(level: number) {
  saveProgress(level)
  
  // Show interstitial every 3 levels
  if (level % 3 === 0) {
    await RundotGameAPI.ads.showInterstitialAd({
      adDisplayId: 'level_transition',
      adDisplayName: 'Level Transition',
    })
  }
  
  loadNextLevel(level + 1)
}
```

## API Reference

| Method                          | Returns            | Description                                                                                                              |
| ------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------ |
| `isRewardedAdReadyAsync()`      | `Promise<boolean>` | Check if a rewarded ad is available                                                                                      |
| `isInterstitialAdReadyAsync()`  | `Promise<boolean>` | Check if an interstitial ad is available                                                                                 |
| `showRewardedAdAsync(options?)` | `Promise<boolean>` | Show rewarded ad; resolves `true` when the reward was earned                                                             |
| `showInterstitialAd(options?)`  | `Promise<boolean>` | Show interstitial ad; resolves `true` if the ad was displayed (e.g. `false` for subscribers or when no ad was available) |

### Display Options

Both `showRewardedAdAsync(options?)` and `showInterstitialAd(options?)` accept an optional options object. Every field is optional; the object is forwarded to the host for placement attribution and analytics. Omit it and the host uses its defaults.

| Field           | Type     | Required | Default | Description                                                                                                     |
| --------------- | -------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------- |
| `adDisplayId`   | `string` | No       | -       | Identifier for this ad placement (e.g. `'extra_life'`, `'level_transition'`). Used by the host for attribution. |
| `adDisplayName` | `string` | No       | -       | Human-readable name for the placement, surfaced alongside `adDisplayId` in analytics.                           |

```typescript
const rewardEarned = await RundotGameAPI.ads.showRewardedAdAsync({
  adDisplayId: 'extra_life',
  adDisplayName: 'Extra Life Reward',
})
```

### Deprecated top-level aliases

Older code may call `RundotGameAPI.isRewardedAdReadyAsync()` and `RundotGameAPI.showRewardedAdAsync()` directly on the root object. Both still work and forward to the `ads` namespace, but they are marked `@deprecated`; use the `ads` namespace in new code.

The top-level `RundotGameAPI.showRewardedAdAsync()` takes no arguments: it cannot pass `adDisplayId` / `adDisplayName`, so you lose placement attribution. Use `RundotGameAPI.ads.showRewardedAdAsync(options?)` to keep it.

| Deprecated                               | Use instead                                       |
| ---------------------------------------- | ------------------------------------------------- |
| `RundotGameAPI.isRewardedAdReadyAsync()` | `RundotGameAPI.ads.isRewardedAdReadyAsync()`      |
| `RundotGameAPI.showRewardedAdAsync()`    | `RundotGameAPI.ads.showRewardedAdAsync(options?)` |

## Best Practices

* Preflight with `isRewardedAdReadyAsync()` / `isInterstitialAdReadyAsync()` before calling display methods: hosts may throttle requests during campaigns.
* Disable reward buttons when `isRewardedAdReadyAsync()` returns `false` to avoid extra clicks.
* Guard reward logic so you only grant the prize when the call resolves `true`.
* Wrap ad calls in try/catch and fail silently; players might deny permissions or lose connectivity.
* Show interstitials at natural break points (level transitions, game over) not mid-gameplay.
* Don't show interstitials too frequently: player experience matters.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://series-1.gitbook.io/rundot-docs/v5.21.0/readme/ads.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
