# Embedding & Clickjacking Protection

By default a deployed app **cannot be embedded in an `<iframe>` by any site**. The
platform sends `X-Frame-Options: DENY` and `Content-Security-Policy: frame-ancestors
'none'` on every response. This protects against clickjacking — including being framed
by *another* app, since every app lives under the shared `onvibe.run` parent domain.

You do not need to do anything to get this protection; it is on by default.

## Making an app embeddable

If your app is a widget, demo, or anything meant to be embedded in other sites, opt
out by adding `security.frame` to `onvibe.json`:

```json
{
  "security": {
    "frame": "allow"
  }
}
```

| `frame` value | Effect |
|---|---|
| *(omitted)* or `"deny"` / `"none"` | **Default.** The app cannot be framed by anyone. |
| `"sameorigin"` / `"self"` | The app can only be framed by pages on its own origin. |
| `"allow"` / `"any"` | The app can be embedded by **any** site (no anti-framing headers). |

The setting is applied automatically on the next `deploy` — no code change in
`main.ts` is needed.

Notes:
- An unrecognized `frame` value falls back to the safe default (`DENY`).
- If your handler already sets its own `Content-Security-Policy`, the platform does
  not overwrite it; it only adds `X-Frame-Options`. Manage `frame-ancestors` yourself
  in that case.
- Use `"sameorigin"` if your own app frames its own pages but no third party should.
