---
title: Set up iframe protection
description: >-
  Set the Content Security Policy frame-ancestors directive so that your app can
  be framed only by the authenticated shop's admin, or not at all. App Store
  review checks for it.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/security/app-server/set-up-iframe-protection
  md: >-
    https://shopify.dev/docs/apps/build/security/app-server/set-up-iframe-protection.md
---

# Set up iframe protection

Set the Content Security Policy `frame-ancestors` directive on every route that renders HTML, so that your app can be framed only by the authenticated shop's admin, or by no one if your app isn't embedded.

***

## Why

Without a `frame-ancestors` directive, any site can load your app in a frame and overlay it to trick a user into clicking, which is [clickjacking](https://owasp.org/www-community/attacks/Clickjacking). Shopify rejects an app during App Store review if the directive is missing or set incorrectly, and you have to fix it before you resubmit.

***

## How

### Apps rendered in the Shopify admin

If your app is [rendered in the Shopify admin](https://shopify.dev/docs/apps/build/admin), then set `frame-ancestors` to the authenticated shop's domain and `https://admin.shopify.com`. The value is different for every shop, and the header must be present on every route that renders HTML. For example, when the shop `shopify-dev.myshopify.com` renders your app, your response includes:

```text
Content-Security-Policy: frame-ancestors https://shopify-dev.myshopify.com https://admin.shopify.com;
```

You can include other declarations in your `Content-Security-Policy` header besides `frame-ancestors`. Apps built from the React Router app template set these headers through `shopify.addDocumentResponseHeaders` in `entry.server.tsx`.

### Standalone apps

If your app isn't rendered in the Shopify admin, then set `frame-ancestors` to `'none'` to disallow framing:

```text
Content-Security-Policy: frame-ancestors 'none';
```

### Fix an app that's configured as embedded but isn't

If your app isn't rendered in the Shopify admin, then its configuration must say so.

With Shopify CLI, set `embedded = false` in your `shopify.app.toml` file and release a new version with [`shopify app deploy`](https://shopify.dev/docs/api/shopify-cli/app/app-deploy):

```toml
embedded = false
```

In the [Dev Dashboard](https://dev.shopify.com/dashboard), open your app, click **Versions**, then **Create a version**. In the **URLs** section, clear **Embed app in Shopify admin**, then click **Release** and confirm.

### Confirm the header on a live store

1. Log in to a store that has your app installed, and click **Apps**.
2. Open your browser's developer tools and select the **Network** tab.
3. Open your app. In the **Network** tab, click **Doc** to filter for document requests, and select the last document in the list.
4. Confirm that the **Request URL** is on your app's domain, and that the response's `Content-Security-Policy` header includes a `frame-ancestors` directive for that store's domain.

***

## Verify

The app security checks report an embedded app that omits `frame-ancestors` ([`MISSING_EMBEDDED_CSP`](https://shopify.dev/docs/apps/build/security/app-security-checks/missing-embedded-csp)) or sets it to a wildcard ([`STATIC_FRAME_ANCESTORS`](https://shopify.dev/docs/apps/build/security/app-security-checks/static-frame-ancestors)). The live-store check above confirms the per-shop value.

***
