# Iframe embedding

Configure your launch URL, embedding headers, and local development environment.

Source: https://zetapad.com/developers/docs/embedding

## Allow the Zetapad parent

Send an HTTP CSP header that allows both production parent origins:

```http
Content-Security-Policy: frame-ancestors https://zetapad.com https://www.zetapad.com;
```

Merge `frame-ancestors` into any existing CSP rather than replacing unrelated directives. Apply it to every app HTML response, including error pages and nested routes. The directive must be sent in an HTTP header; a meta tag cannot enforce `frame-ancestors`.

Do not send `X-Frame-Options: DENY` or `SAMEORIGIN` on those responses. Both prevent the intended cross-origin embedding. If your host sets either header automatically, override it for your app documents.

`frame-ancestors` controls which pages may embed your app. It does not block top-level navigation or authenticate callers. Follow [restrict app access](https://zetapad.com/developers/docs/access-control) when the direct URL must be unusable.

## Iframe capabilities

The iframe permits scripts, forms, and its own origin. Zetapad does not delegate top navigation, popups, camera, or microphone.

Register the final launch origin. An iframe redirected to another origin cannot use the bridge. Keep navigation within the registered origin, send `ready` when the app loads, and reopen the Zetapad room after iframe navigation.

Rooms and previews fill the browser viewport. Your app controls its interface. A small transparent Zetapad logo bubble sits above it; members can drag it to an edge and open controls to reload or exit. Consent dialogs appear above the room when needed.

## Validate messages

Install your message listener before sending `ready`. Accept only replies from `window.parent` with either `https://zetapad.com` or `https://www.zetapad.com` as their exact origin. After a valid readiness reply, pin all further messages to that responding origin.

Use an exact origin as the `postMessage` target. The [browser example](https://zetapad.com/developers/docs/examples/browser) supports both production origins without using a wildcard target.

## Hosted call tiles

Apps using [campus calls](https://zetapad.com/developers/docs/calls) embed Zetapad-hosted video tiles inside their registered app iframe. Merge a `frame-src` directive into your app's CSP:

```http
Content-Security-Policy: frame-ancestors https://zetapad.com https://www.zetapad.com; frame-src https://zetapad.com https://www.zetapad.com;
```

Resolve each relative tile URL against the exact origin pinned by `ready`, including any local port. Tile and campus origins must match even though production REST requests use `https://zetapad.com`. Mount tile iframes directly inside the registered app document. Ordinary child iframes work; an extra sandbox must preserve scripts and `allow-same-origin` so the owning campus can attach its existing video.

Keep the tile on its campus origin, use each returned URL once, and request fresh URLs after reload. Tile documents permit only the registered app and their own campus origin as ancestors. They capture no devices and render muted video; Zetapad retains incoming audio and native camera/microphone controls. See the [hosted call example](https://zetapad.com/developers/docs/examples/calls) for mounting, commit, heartbeat, and release.

## Local development

Unpublished previews may use HTTP on `localhost`, `127.0.0.1`, or `[::1]`, on an origin separate from Zetapad. Publishing always requires HTTPS.

When running Zetapad locally at `http://localhost:3000`, configure the app document's header as:

```http
Content-Security-Policy: frame-ancestors http://localhost:3000;
```

Replace the browser example's trusted origins with `["http://localhost:3000"]` and the server example's API origin with `http://localhost:3000`. These changes are for local integration testing. Production uses the fixed Zetapad origins above.

For local hosted tiles, also allow `http://localhost:3000` in `frame-src` and in the call example's tile-origin allowlist. Set its REST helper base URL to `http://localhost:3000/v1/apps/calls`. Keep the registered app on a different origin or port.

An HTTPS tunnel can help if your browser restricts an HTTP local iframe inside an HTTPS parent.

## App session cookies

Zetapad authentication itself does not require third-party cookies. Your own app's session storage still needs to work in an embedded browser context.

Use HttpOnly, Secure cookies on HTTPS. Cross-site iframe cookies generally need `SameSite=None`; browser privacy settings may still restrict them. Configure a supported session strategy for your app and test it in the intended browsers. The server must resolve the visitor session itself, never accept a session identity from the request body.
