> ## Documentation Index
> Fetch the complete documentation index at: https://enterprise-docs.crewai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Embed Crew Studio

> Embed CrewAI Studio inside your own application using a cross-origin iframe.

<Note>
  This is a pilot-stage integration. Sign-in inside the iframe currently uses a username and password. Once the automatic login API is finalized, this becomes silent SSO with no credentials prompt.
</Note>

Studio can render inside a cross-origin iframe — no sidebar, no app header, just the Canvas, Chat, and toolbar. A small embed script (one `<script>` tag) builds and mounts that iframe into a container you provide, so the host application never hand-constructs or manages an iframe URL directly.

Access is authorized per organization by a token CrewAI generates for you — not a public ID or a flag flipped on the CrewAI side.

## Who does what

<Steps>
  <Step title="CrewAI generates your token">
    CrewAI mints an encrypted token for your organization and sends it out of band. On the CrewAI side, it's generated at **Settings → Default Settings** (`/crewai_plus/settings/defaults`), which shows both snippets below pre-filled with the real token. Nothing to configure on your end here — let CrewAI know when you're ready to test and they'll share the value.
  </Step>

  <Step title="Set the allowed origin in your deployment">
    In your deployment's `values.yaml`, set `EMBEDDED_STUDIO_ALLOWED_ORIGINS` under `envVars` to the exact domain(s) the embed page will run on (e.g. `https://app.yourcompany.com`). This is what allows your domain specifically to frame Studio — it's your deployment, so it's your setting to make.

    ```yaml theme={null}
    envVars:
      EMBEDDED_STUDIO_ALLOWED_ORIGINS: "https://app.yourcompany.com"
    ```

    Until this is set, embedding is blocked entirely, regardless of token validity — secure by default.
  </Step>

  <Step title="Add the embed snippet">
    Drop an empty container `<div>` and one `<script>` tag on the host page. The script reads its own attributes, builds the Studio URL, and mounts the iframe inside your container — sized to whatever CSS you give that container.
  </Step>

  <Step title="Allow the CrewAI domain in your CSP, if you have one">
    If the host page sets its own Content-Security-Policy, it needs the CrewAI deployment's domain in two directives: `script-src` (to load the embed script) and `frame-src` (or `child-src`, for the iframe the script mounts). Missing either blocks the browser before the request ever reaches CrewAI, regardless of anything on the CrewAI side.
  </Step>

  <Step title="Test in a standard browser window">
    See the [known limitations](#known-limitations-pilot-period) below on Incognito / Private windows and strict cookie policies.
  </Step>
</Steps>

## The embed snippet

Place the container and the script anywhere on the page — order doesn't matter, the script waits for the page to finish loading if it runs before the container exists.

```html Project list theme={null}
<div id="crewai-studio"></div>
<script
  src="https://<studio-host>/studio-embed.js"
  data-target-id="crewai-studio"
  data-embedded-ui-token="<YOUR_TOKEN>"
></script>
```

```html A specific project's editor theme={null}
<div id="crewai-studio"></div>
<script
  src="https://<studio-host>/studio-embed.js"
  data-target-id="crewai-studio"
  data-embedded-ui-token="<YOUR_TOKEN>"
  data-project="<PROJECT_ID>"
></script>
```

| Attribute                | Required | Purpose                                                                                                                                                                         |
| ------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data-target-id`         | Yes      | ID of the container the iframe mounts into. The iframe fills it at 100% width and height — size the container with your own CSS.                                                |
| `data-embedded-ui-token` | Yes      | The token CrewAI generates for your organization. It identifies which org to embed — treat it like a secret, since anyone holding it could point their own page at your Studio. |
| `data-project`           | No       | Opens a specific project's editor directly, instead of the project list.                                                                                                        |

CrewAI generates the `<YOUR_TOKEN>` value and sends it to you — it isn't something you create yourselves. The container ID doesn't grant access to anything, and the token alone doesn't either — it only identifies which organization to render; a user still has to sign in normally inside the frame.

## What to expect

* Signing in happens inside the iframe with a username and password — there's no separate top-level login step. This is a pilot-only stand-in (see the note above).
* Studio renders without the CrewAI app's sidebar or header — just Canvas, Chat, and the toolbar.
* Clicking anything outside Studio's own scope (a link to a different part of the CrewAI app) opens in a new browser tab instead of navigating inside the iframe, with a short heads-up first — so a user never loses the embedded context by accident.

## Known limitations, pilot period

<Warning>
  **Third-party cookies:** Login relies on a cookie that has to travel inside a cross-origin iframe. CrewAI has relaxed its side of that (`SameSite=None`), but some browser contexts block third-party cookies outright regardless — most notably **Incognito / Private windows**, and some managed corporate browser policies. In those cases sign-in will appear to loop back to the login screen. A standard (non-private) browser window works.
</Warning>

<Warning>
  **Framing is deny-by-default:** Without `EMBEDDED_STUDIO_ALLOWED_ORIGINS` set in your `values.yaml` (see [Set the allowed origin in your deployment](#who-does-what) above), the deployment refuses to be framed by any origin — even with a valid token. There's no insecure fallback: if the embed doesn't render, this is the first thing to check.
</Warning>
