Skip to main content
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.

Overview

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 an embed token your deployment generates automatically — not a public ID, and not something you request from CrewAI.

Prerequisites

  • CrewAI Platform is running and accessible at its configured hostname
  • Admin access to the web UI
  • The ability to update your Helm values and upgrade the deployment
  • The exact origin(s) of the host page that will frame Studio (e.g. https://app.yourcompany.com)

Step 1: Allow Your Embed Origin

In your values.yaml, set EMBEDDED_STUDIO_ALLOWED_ORIGINS under envVars to the exact domain(s) the embed page will run on:
Apply the change:
Verify the variable is set in the web pod:
Framing is deny-by-default. Until EMBEDDED_STUDIO_ALLOWED_ORIGINS is set, the deployment refuses to be framed by any origin — even with a valid token. There is no insecure fallback.

Step 2: Copy the Embed Token

  1. In the web UI, navigate to Settings → Default Settings (/crewai_plus/settings/defaults)
  2. Locate the embed token for your organization — it is generated automatically, with nothing to request from CrewAI
  3. Copy the ready-made snippet shown on that page, or copy the token alone and use the snippets in Step 3
Treat the embed token like a secret. Anyone holding it could point their own page at your Studio, subject to the origins you allowed in Step 1.

Step 3: 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. 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.
Project list
A specific project's editor
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.

Pass Environment Variables

Use data-env to hand context from the host application — a team, tenant, or region identifier — to the automations built inside the frame:
  • The variables are saved as project environment variables each time a project’s editor opens in the frame — a newly created project, or an existing one opened with data-project. The project list alone saves nothing.
  • Each open overwrites the previous value, so the host page is the source of truth.
  • Values must be strings: {"TEAM_ID":"42"} works, {"TEAM_ID":42} is ignored.
  • Up to 5 variables are applied; any beyond that are ignored.
  • Names must start with a letter or underscore and contain only letters, digits, or underscores. If any name is invalid, none of the variables are saved.
  • Wrap the attribute value in single quotes so the JSON’s double quotes stay intact.
data-env requires CrewAI Platform v0.30.0 or later.
The host page is yours, so anyone who can edit it can change these values. Treat them as context, not as a security boundary — don’t use data-env to pass secrets or to make authorization decisions.

Step 4: Allow the CrewAI Domain in Your CSP (Optional)

If the host page sets its own Content-Security-Policy, it needs your CrewAI deployment’s domain in two directives:
  • script-src — to load the embed script
  • 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. Skip this step if the host page has no Content-Security-Policy.

Step 5: Verify

Open the host page in a standard (non-private) browser window. Studio should mount inside your container and prompt for sign-in. What to expect once it renders:
  • 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 at the top of this page).
  • 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

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.

Troubleshooting

The iframe doesn’t render at all

Check EMBEDDED_STUDIO_ALLOWED_ORIGINS first — see Step 1. The value must match the host page’s origin exactly, including scheme and any non-standard port. A valid token does not bypass this.

Sign-in loops back to the login screen

The browser is blocking third-party cookies. Retry in a standard (non-private) browser window — see Known Limitations.

The embed script never loads

If the host page sets a Content-Security-Policy, confirm both script-src and frame-src allow your CrewAI deployment’s domain — see Step 4.

Environment variables from data-env don’t appear on the project

Failures here are silent by design, so the frame keeps working. Check that:
  • The deployment runs v0.30.0 or later.
  • The browser isn’t serving a cached copy of an older studio-embed.js — the iframe’s URL should include embedded_env=.
  • A project’s editor was opened in the frame; the project list doesn’t save variables.
  • Every value is a JSON string, and every name is valid — see Pass Environment Variables.