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

> ## Agent Instructions
> Internal links on these pages omit the .md extension. Append .md to a docs page URL, or send an Accept: text/markdown header, to get that page as markdown.

# Embed the app

> Show an app inside your platform, already signed in as the person looking at it.

You can show an app inside your platform in an iframe. If the app asks people to sign in, they see its sign-in page inside the frame. To skip that and open the app already signed in as the end user, your server can create a one-time sign-in token and add it to the iframe URL. The app itself doesn't need any changes.

## Decide if you need a token

You need a sign-in token only when the app asks people to sign in. That depends on the app's visibility, which you set with `public_settings` when you [create the app](/api-reference/create-app).

| Visibility API value | Shown in settings as | Needs a token |
| :- | :- | :- |
| `public_without_login` | **Public (no login)** | No |
| `public_with_login` | **Public (login required)** | Yes |
| `private_with_login` | **Private** | Yes |

If you don't need a token, load the app's address in the iframe. If you do, [mint one](#sign-the-end-user-in) for each end user so they skip the sign-in page.

<Note>
  An app with no login can't tell visitors apart, so features that depend on who someone is, such as profiles or data saved for each person, don't work. Learn more about [app visibility](/Setting-up-your-app/Managing-access#setting-your-app-visibility).
</Note>

## Sign the end user in

Your server signs an end user in with two calls. The first gives them access to the app, and the second returns the app's address with a sign-in token on it. Then you load that address in your iframe.

<Tip>
  **Before you begin:** Create a [workspace API key](/Enterprise/workspace-secrets) in your enterprise workspace with the **Provision app users** and **Mint embed sign-in tokens** permissions. Set **App access** to **All current and future apps**, since your builders keep creating new ones. Send it from your server as `api_key: <key>`, together with `X-Active-Workspace-Id: <workspace id>`.
</Tip>

<Steps>
  <Step title="Provision the end user">
    Send `POST /api/apps/{app_id}/users/provisions` with the end user's email and a role. Apps have `admin` and `user` roles by default, and you can [add your own](/Setting-up-your-app/Managing-access#choosing-your-users-roles):

    ```json theme={null}
    { "email": "dana@example.com", "role": "user" }
    ```

    This gives them access to the app. It's idempotent, so you can call it before every mint. The response returns the end user's `email` and `role`, and a `status` that is `created` the first time and `exists` after that. If the end user already existed, `role` is the role they already had.

    <Warning>
      Take the email from your own server-side session, never from a value the browser sends. The token signs in whichever email you send, so if that email comes from the browser, an end user could send someone else's and open the app as them.
    </Warning>
  </Step>

  <Step title="Mint a sign-in token">
    Send `POST /api/apps/{app_id}/embed-url` with the same email and a `target`, which is the version of the app you want to show:

    ```json theme={null}
    { "email": "dana@example.com", "target": "latest_preview" }
    ```

    | Target value | What it shows |
    | :- | :- |
    | `live_site` | The published app. This is the default, and it needs the app to be published. |
    | `latest_preview` | The latest built version, including changes you haven't published. |
    | `live_preview` | The app's running sandbox, which shows each change while the agent builds. |

    The response returns two fields. The `embed_url` field is the address of that version with the token already on it. The `expires_in` field is how many seconds the token lasts.
  </Step>

  <Step title="Load the URL in your iframe">
    Set the iframe's `src` to `embed_url`, and the app opens signed in as the end user. A token is short lived and works only once, so mint a new one each time you load the frame.

    <Note>
      If your workspace has an [embedding policy](/Enterprise/Enterprise-SSO-and-app-visibility#controlling-app-embedding) set to **Only these sites**, add your platform's website to its list, or the app won't load in your iframe. With **No one**, no website can embed your apps.
    </Note>
  </Step>
</Steps>

<Tip>
  The reference integration does all three steps in [`embedSession.ts`](https://github.com/base44/base44-platform-starter/blob/main/src/lib/embedSession.ts).
</Tip>

## Errors

If a call fails, the response includes an error with a `code`, a `message`, and `details`. Use the `code` to tell what went wrong. These are the errors minting a token can return.

| Status | Error code | What it means |
| :- | :- | :- |
| `400` | `app_not_deployed` | You asked for `live_site`, and the app isn't published. |
| `400` | `app_has_no_slug` | The app doesn't have an address yet. |
| `403` | `privileged_user` | The email belongs to the app's owner, an editor, or a service account, including the account your integration authenticates as. Sign-in tokens are for end users only. |
| `404` | `unknown_user` | The email isn't provisioned for this app. |

## See also

* [The build turn](/developers/white-label/the-build-turn): Create, preview, and publish the app you're embedding
* [Tenancy and credentials](/developers/white-label/tenancy-and-credentials): The account that owns your builders' apps, and the token that creates them
* [Workspace secrets](/Enterprise/workspace-secrets): Create and manage the workspace API key this page uses
* [Controlling app embedding](/Enterprise/Enterprise-SSO-and-app-visibility#controlling-app-embedding): Choose which websites can embed the apps in your workspace


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.