# Serve the Break Manifest from your CDN

By default, your player fetches your stream from your CDN, while the OptiView Ads SDK fetches the [Break Manifest](https://docs-preview.optiview.dolby.com/pr-912/ads/concepts/break-manifest.md) from the OptiView Ads domain of your region. This guide shows how to serve the Break Manifest from **your own domain** instead, by letting your CDN forward a path to OptiView Ads. Your app then fetches everything from one domain you control:

| Resource       | Default                                                                        | Served from your CDN                                                   |
| -------------- | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------- |
| Stream         | `https://example.com/channel-5/index.m3u8`                                     | `https://example.com/channel-5/index.m3u8`                             |
| Break Manifest | `https://us.markers.optiview.dolby.com/manifest/v1/ORG-ID/channels/CHANNEL-ID` | `https://example.com/channel-5/manifest/v1/ORG-ID/channels/CHANNEL-ID` |

No change is needed on the OptiView Ads side: the setup is a routing rule on your CDN and a different `manifestUrl` in your player.

> **Regional domains**
>
> The examples on this page use the US region (`https://us.markers.optiview.dolby.com`). For the EU region, replace `us.` with `eu.` (`https://eu.markers.optiview.dolby.com`).

## How it works

Your CDN gets one extra routing rule. Requests for the stream go to your origin as today; requests for the Break Manifest path are forwarded to OptiView Ads. Your app only sees your domain.

![Served from your CDN diagram](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOTAwIiBoZWlnaHQ9IjI4MCIgdmlld0JveD0iMCAwIDkwMCAyODAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgcm9sZT0iaW1nIiBhcmlhLWxhYmVsPSJTZXJ2ZWQgZnJvbSB5b3VyIENETjogeW91ciBDRE4gYXQgZXhhbXBsZS5jb20gZm9yd2FyZHMgdGhlIG1lZGlhIHN0cmVhbSBmcm9tIHlvdXIgb3JpZ2luIGFuZCB0aGUgQnJlYWsgTWFuaWZlc3QgZnJvbSB1cy5tYXJrZXJzLm9wdGl2aWV3LmRvbGJ5LmNvbSwgc28gdGhlIHBsYXllciBmZXRjaGVzIGJvdGggZnJvbSBleGFtcGxlLmNvbSI+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgcng9IjgiIGZpbGw9IiNmNGY0ZmIiLz4KICA8ZGVmcz4KICAgIDxtYXJrZXIgaWQ9ImFycm93IiBtYXJrZXJXaWR0aD0iOCIgbWFya2VySGVpZ2h0PSI4IiByZWZYPSI3IiByZWZZPSI0IiBvcmllbnQ9ImF1dG8iPgogICAgICA8cGF0aCBkPSJNMCwwIEw4LDQgTDAsOCB6IiBmaWxsPSIjNDgwMGM0Ii8+CiAgICA8L21hcmtlcj4KICA8L2RlZnM+CiAgPHJlY3QgeD0iMjAiIHk9IjQwIiB3aWR0aD0iMjMwIiBoZWlnaHQ9IjU2IiByeD0iNyIgZmlsbD0iI2NmZDBmZiIgc3Ryb2tlPSIjNDgwMGM0IiBzdHJva2Utd2lkdGg9IjIiLz4KICA8dGV4dCB4PSIxMzUiIHk9IjY0IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmb250LWZhbWlseT0iQXJpYWwsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTQiIGZvbnQtd2VpZ2h0PSJib2xkIiBmaWxsPSIjNDgwMGM0Ij5PcmlnaW48L3RleHQ+CiAgPHRleHQgeD0iMTM1IiB5PSI4MyIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZm9udC1mYW1pbHk9IkFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIiBmaWxsPSIjNDgwMGM0Ij5vcmlnaW4uZXhhbXBsZS5jb208L3RleHQ+CiAgPHJlY3QgeD0iMjAiIHk9IjE4NCIgd2lkdGg9IjIzMCIgaGVpZ2h0PSI1NiIgcng9IjciIGZpbGw9IiNjZmQwZmYiIHN0cm9rZT0iIzQ4MDBjNCIgc3Ryb2tlLXdpZHRoPSIyIi8+CiAgPHRleHQgeD0iMTM1IiB5PSIyMDgiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNCIgZm9udC13ZWlnaHQ9ImJvbGQiIGZpbGw9IiM0ODAwYzQiPk9wdGlWaWV3IEFkczwvdGV4dD4KICA8dGV4dCB4PSIxMzUiIHk9IjIyNyIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZm9udC1mYW1pbHk9IkFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIiBmaWxsPSIjNDgwMGM0Ij51cy5tYXJrZXJzLm9wdGl2aWV3LmRvbGJ5LmNvbTwvdGV4dD4KICA8cmVjdCB4PSIzNTAiIHk9IjEwOCIgd2lkdGg9IjE3MCIgaGVpZ2h0PSI2NCIgcng9IjciIGZpbGw9IiNjZmQwZmYiIHN0cm9rZT0iIzQ4MDBjNCIgc3Ryb2tlLXdpZHRoPSIyIi8+CiAgPHRleHQgeD0iNDM1IiB5PSIxMzYiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNCIgZm9udC13ZWlnaHQ9ImJvbGQiIGZpbGw9IiM0ODAwYzQiPllvdXIgQ0ROPC90ZXh0PgogIDx0ZXh0IHg9IjQzNSIgeT0iMTU2IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmb250LWZhbWlseT0iQXJpYWwsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTEiIGZpbGw9IiM0ODAwYzQiPmV4YW1wbGUuY29tPC90ZXh0PgogIDxyZWN0IHg9IjcwMCIgeT0iMTE2IiB3aWR0aD0iMTgwIiBoZWlnaHQ9IjQ4IiByeD0iNyIgZmlsbD0iIzZkMTlmZiIgc3Ryb2tlPSIjNDgwMGM0IiBzdHJva2Utd2lkdGg9IjIiLz4KICA8dGV4dCB4PSI3OTAiIHk9IjE0NSIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZm9udC1mYW1pbHk9IkFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjE0IiBmb250LXdlaWdodD0iYm9sZCIgZmlsbD0iI0ZGRkZGRiI+UGxheWVyICsgQWRzIFNESzwvdGV4dD4KICA8bGluZSB4MT0iMjUwIiB5MT0iNjgiIHgyPSIzNTAiIHkyPSIxMjIiIHN0cm9rZT0iIzQ4MDBjNCIgc3Ryb2tlLXdpZHRoPSIyIiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93KSIvPgogIDx0ZXh0IHg9IjMwMCIgeT0iODgiIHRleHQtYW5jaG9yPSJtaWRkbGUiIHRyYW5zZm9ybT0icm90YXRlKDI4LjM3IDMwMCA4OCkiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMSIgZmlsbD0iIzQ4MDBjNCI+bWVkaWEgc3RyZWFtPC90ZXh0PgogIDxsaW5lIHgxPSIyNTAiIHkxPSIyMTIiIHgyPSIzNTAiIHkyPSIxNTgiIHN0cm9rZT0iIzQ4MDBjNCIgc3Ryb2tlLXdpZHRoPSIyIiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93KSIvPgogIDx0ZXh0IHg9IjMwMCIgeT0iMTc4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB0cmFuc2Zvcm09InJvdGF0ZSgtMjguMzcgMzAwIDE3OCkiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMSIgZmlsbD0iIzQ4MDBjNCI+YnJlYWsgbWFuaWZlc3Q8L3RleHQ+CiAgPGxpbmUgeDE9IjUyMCIgeTE9IjE0MCIgeDI9IjcwMCIgeTI9IjE0MCIgc3Ryb2tlPSIjNDgwMGM0IiBzdHJva2Utd2lkdGg9IjIiIG1hcmtlci1lbmQ9InVybCgjYXJyb3cpIi8+CiAgPHRleHQgeD0iNjEwIiB5PSIxMjgiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMSIgZmlsbD0iIzQ4MDBjNCI+L2NoYW5uZWwtNS9pbmRleC5tM3U4PC90ZXh0PgogIDx0ZXh0IHg9IjYxMCIgeT0iMTU4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmb250LWZhbWlseT0iQXJpYWwsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTEiIGZpbGw9IiM0ODAwYzQiPi9jaGFubmVsLTUvbWFuaWZlc3Qv4oCmPC90ZXh0Pgo8L3N2Zz4K)

OptiView Ads keeps producing the Break Manifest exactly as before, including its caching headers and signature. Your CDN only needs to pass the response through unchanged.

## Before you start

You need:

* **Your organization ID and the channel ID.** They are part of the channel's Break Manifest URL; see [retrieving the required values](https://docs-preview.optiview.dolby.com/pr-912/ads/player-integration/optiview-ads-sdk.md#retrieving-the-required-values). On this page, `ORG-ID` and `CHANNEL-ID` are placeholders for these values.

* **The OptiView Ads domain of your organization's region.** Use the same region (`us.` or `eu.`) as the OptiView Ads API you work with today.

  | Region | OptiView Ads domain             |
  | ------ | ------------------------------- |
  | US     | `us.markers.optiview.dolby.com` |
  | EU     | `eu.markers.optiview.dolby.com` |

* **Access to your CDN's routing configuration.** Your CDN must be able to route a path to a different origin. For the recommended approach in step 1, it must also remove a path prefix on the way, which most CDNs support through path rewrite rules or edge functions.

## Step 1: Choose the Break Manifest URL

Pick the URL the SDK will use for the Break Manifest. In both approaches below, the URL ends with the OptiView Ads path (`/manifest/v1/ORG-ID/channels/CHANNEL-ID`). Your CDN forwards that path unchanged, so one rule serves every channel and future versions of the endpoint need no CDN change.

| Approach                                | Example                                                                | CDN rule                                                               |
| --------------------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| **Next to each stream** (recommended)   | `https://example.com/channel-5/manifest/v1/ORG-ID/channels/CHANNEL-ID` | Drop everything before `/manifest/`, forward the rest.                 |
| **One path for all channels** (simpler) | `https://example.com/manifest/v1/ORG-ID/channels/CHANNEL-ID`           | Forward every request under `/manifest/` unchanged, without a rewrite. |

* **Next to each stream** places the Break Manifest under the same path as the stream it belongs to, so both share your stream's routing and logging.
* **One path for all channels** keeps the CDN configuration to a single rule without any path rewrite.
* In both cases, make sure none of your own content is served under a `/manifest/` path on the same domain, so the rule only matches Break Manifest requests.

## Step 2: Forward the path to OptiView Ads

Add a rule on your CDN that sends the Break Manifest requests to OptiView Ads, with everything from `/manifest/v1` onwards forwarded unchanged:

| Approach                      | Incoming request                                                       | Forwarded to                                                                   |
| ----------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| **Next to each stream**       | `https://example.com/channel-5/manifest/v1/ORG-ID/channels/CHANNEL-ID` | `https://us.markers.optiview.dolby.com/manifest/v1/ORG-ID/channels/CHANNEL-ID` |
| **One path for all channels** | `https://example.com/manifest/v1/ORG-ID/channels/CHANNEL-ID`           | `https://us.markers.optiview.dolby.com/manifest/v1/ORG-ID/channels/CHANNEL-ID` |

Configure the OptiView Ads origin in your CDN as follows:

* **Protocol:** HTTPS on port 443.
* **Host header and TLS server name (SNI):** the OptiView Ads domain of your region, not your own domain. OptiView Ads routes requests by host name.
* **Methods:** `GET`, `HEAD`, and `OPTIONS`.
* **Forwarded request headers:** none are required. Do not forward cookies or authorization headers; the Break Manifest endpoint is public and ignores them.

## Step 3: Keep the response intact

Your CDN must deliver the Break Manifest response to the player as OptiView Ads sends it. Check each of the following, because a miss can stop ads silently while your stream keeps playing:

| Requirement                                   | Why                                                                                                                                                                                                                                                     | If it is missed                                                                         |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| **Forward the `X-Manifest-Signature` header** | Every Break Manifest response is signed. The SDK verifies the signature before it uses the manifest.                                                                                                                                                    | The SDK rejects the manifest and schedules no breaks.                                   |
| **Do not modify the body**                    | The signature covers the exact response body. Compression (gzip, Brotli) is fine; minifying, reformatting, or injecting content is not.                                                                                                                 | The signature no longer matches; the SDK rejects the manifest and schedules no breaks.  |
| **Respect the origin's `Cache-Control`**      | For live channels, the cache lifetime equals the channel's active polling interval (1 second by default), so players learn about new breaks and changes in time.                                                                                        | Players receive breaks late or miss them.                                               |
| **Keep the CORS headers** (web)               | Browsers need `Access-Control-Allow-Origin` to read the response, and `Access-Control-Expose-Headers: X-Manifest-Signature` to let the SDK read the signature. CDNs pass them through by default; if yours sets its own, expose `X-Manifest-Signature`. | The browser blocks the request, or hides the signature so the SDK rejects the manifest. |

## Step 4: Point the SDK at your URL

Pass your own URL as the `manifestUrl` when you start the session. Nothing else in your integration changes. See the [OptiView Ads SDK](https://docs-preview.optiview.dolby.com/pr-912/ads/player-integration/optiview-ads-sdk.md) documentation for the full integration.

**Web**

```typescript
await sdk.startSession({
  manifestUrl: 'https://example.com/channel-5/manifest/v1/ORG-ID/channels/CHANNEL-ID',
});
```

**Android**

```kotlin
sdk.startSession(
    SessionConfig(
        manifestUrl = "https://example.com/channel-5/manifest/v1/ORG-ID/channels/CHANNEL-ID",
    )
)
```

**iOS**

```swift
try await sdk.startSession(
    SessionConfig(
        manifestUrl: "https://example.com/channel-5/manifest/v1/ORG-ID/channels/CHANNEL-ID"
    )
)
```

**React Native**

```typescript
await ads.startSession({
  manifestUrl: 'https://example.com/channel-5/manifest/v1/ORG-ID/channels/CHANNEL-ID',
});
```

## Verify your setup

Request the Break Manifest through your CDN and check the response headers:

```bash
curl -s -D - -o /dev/null -H 'Origin: https://www.example.com' 'https://example.com/channel-5/manifest/v1/ORG-ID/channels/CHANNEL-ID'
```

A working setup returns:

```text
HTTP/2 200
content-type: application/json; charset=utf-8
cache-control: public, max-age=1
access-control-allow-origin: *
access-control-expose-headers: X-Manifest-Signature
x-manifest-signature: eyJhbGciOiJFZERTQSIs...
```

Check that:

* the status is `200` and the body is the channel's Break Manifest, with the expected `channelId`;
* `x-manifest-signature` is present;
* `cache-control` shows the same `max-age` as a request made directly to the OptiView Ads domain.

Then play the channel with the new `manifestUrl` and confirm that a break plays. If the SDK rejects the manifest, it reports the `DA-MANIFEST-SIGNATURE-INVALID` diagnostic.

## Troubleshooting

| Symptom                                                  | Likely cause                                                                                                                                |
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `404 Not found` from your URL                            | The rule forwards the wrong path (it must start at `/manifest/v1`), the IDs are wrong, or the CDN forwards to the domain of another region. |
| Error page from OptiView Ads, or a TLS error             | The `Host` header or TLS server name is set to your domain instead of the OptiView Ads domain.                                              |
| Stream plays, no breaks, `DA-MANIFEST-SIGNATURE-INVALID` | The `X-Manifest-Signature` header is stripped, the body is modified, or (on web) the header is not exposed through CORS.                    |
| Breaks start late or changes arrive late                 | Your CDN caches the Break Manifest longer than the origin's `Cache-Control` allows.                                                         |
| Works in the apps but not in the browser                 | CORS headers are missing or replaced on the way through your CDN.                                                                           |

## Related resources

| Resource                                                                                                         | Description                                                  |
| ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| [Break Manifest](https://docs-preview.optiview.dolby.com/pr-912/ads/concepts/break-manifest.md)                  | The side-loaded contract between the backend and the player. |
| [Workflow integration](https://docs-preview.optiview.dolby.com/pr-912/ads/how-to-guides/workflow-integration.md) | How OptiView Ads fits into your existing delivery workflow.  |
| [OptiView Ads SDK](https://docs-preview.optiview.dolby.com/pr-912/ads/player-integration/optiview-ads-sdk.md)    | Integrating the SDK with your player.                        |
