Skip to main content

Embed a web app with Retool Embed

Retool Embed allows you to authenticate users–internal or external to your company–into embedded Retool apps. Not much changes in how you build your apps, but you need to complete a few steps to embed your apps for external use:

  1. Generate an access token so you can create sessions for embedding apps.
  2. Create permission groups for your users so you can give them access to apps.
  3. Create an embed URL to use when embedding Retool apps into your parent app.
  4. Use the embed URL to display the app.


To use Retool Embed, you need to:

  • Set up a custom domain for your Retool instance.
    • If Retool is your hosting provider, follow the Cloud instructions to add A records to your DNS provider.
    • If you are running self-hosted Retool, configure your custom domain in your cloud provider's settings.
  • Turn Prevent Query Spoofing on.
  • Host Retool on the same top-level domain as the parent application.
  • Use HTTPS when generating embed URLs.
  • Have already built a Retool app to embed.

Self-hosted recommendations

If you're self-hosting Retool, in addition to the above prerequisites, Retool recommends that you:

When you deploy Retool at scale, you can have separate instances for internal and external use. This helps with separation of concerns, performance, scalability, managing updates, development lifecycle, and permissions.

For external use cases, you might also want to use Source Control to release your apps. This allows you to use a Git-based workflow to release apps to external users.

Authentication flow

When your web application authenticates a user, using your preferred authentication method, your backend must make a request to Retool to generate an embed URL. This embed URL is a secure, single-use link that can be used anywhere in your product. To generate and use the embed URL to securely embed Retool apps inside your web app, you need to make some small updates to the frontend and backend parts of your codebase. The following diagram illustrates the authentication flow.

Embed authentication flow

See the GitHub repository for a live demo of Retool Embed, or run it locally to get started.

1. Generate an access token

To embed apps, you need to create an access token with the Embed scope. This token allows you to create sessions for embedding Retool apps.

You can create API tokens with the Embed scope in the API settings for your organization.

Retool Public API availability

The Retool Public API is available as an opt-in beta for Retool Cloud, and for Self-hosted Retool 3.4.0 and later.

  1. In Settings > Beta, enable the Use Public API for Permissions setting.
  2. Go to Settings > API and click Create new to generate an access token.
  3. Enter a name and description, then select the required scope.
  4. Copy and save your token, as you can only access it once.

Creating a token with the Embed scope

2. Create permission groups for your users

Permission groups determine the apps users can access. Depending on your use case, you might need to create more than one permission group.

To create a permission group:

  1. Navigate to the Permission Groups page at /settings/permissions.
  2. Click Create new in the top right and complete the form to create a group.
  3. On the Members tab, click + Add new members to add users.
  4. On the Apps tab, enable Use access to the apps you want users to have access to.

Giving users access to apps

Make sure to note down the group IDs you want to give access to. You can find a group's ID by hovering over the group, clicking the ••• menu, and then selecting Copy group ID.

Copying the group ID

3. Create an embed URL

The embed URL is a single-use link to a Retool app for an authenticated user. Your backend sends a POST request to /api/embed-url/external-user with a few parameters, and Retool returns the URL. This URL is then used by your frontend to display the app.

If an email is passed into userInfo within the request and it matches that of an existing user, Retool updates the user. Otherwise, a new user is created. See testing for more information.

POST request parameters

The table below outlines the parameters you can send, and whether they're required.

landingPageUuidYesA string to specify the page in the Retool app to render. You can find the landingPageUuid by opening the app and using the Command Palette (opened with ctrl k) to select Copy app UUID.
groupIdsYesAn array of integers specifying the Retool group IDs to allow.
sessionDurationMinutesNoThe session token's duration, in minutes. If unset, defaults to 1440 (1 day). Values from 10 to 43200 (30 days) are accepted.
externalIdentifierYesA string or integer unique identifier for the external user.
userInfoNoUser profile information. Can contain string fields for email, firstName, and lastName.
metadataNoAdditional metadata. Accepts strings, int64, and booleans. Can be at most 1KB of stringified JSON.
environmentNoA string to specify an environment for the app to run in.
branchNoA string to specify a branch to be displayed. You can't display both releaseVersion and branch.
releaseVersionNoA string to specify a release to be displayed. Defaults to latest but you can pass version numbers too (e.g.,1.0.0). You can't display both releaseVersion and branch.


When generating the embed URL, Retool may create an additional user depending on the data that is passed into your POST request. To avoid creating an extra user while testing, pass in the email associated with your Retool account in the email property of the userInfo object, as well as the IDs of the permission groups you’re in.

If an email is specified and it matches that of an existing Retool user, Retool will update the user, its metadata, and permission groups. Otherwise it will create a new user if this email does not exist.

If no email is specified, Retool updates the user if the externalIdentifier matches, or will create a new user if the externalIdentifier does not exist.

POST request code example

Below is sample code that accepts a request from the client, builds and sends the POST request to /api/embed-url/external-user, receives the embed URL, and then returns the URL to the client.

@app.route('/embedUrl', methods=['POST'])
def embed_url():
data = request.get_json()
app_uuid = app_name_to_uuid[data['retoolAppName']]
token, first_name, last_name, email = jwt.decode(data['userJwt'], secret_key)

headers = {
// The RETOOL_API_KEY is the token generated in the first step
'Authorization': f"Bearer {os.environ['RETOOL_API_KEY']}",
'Content-type': 'application/json',
body = {
'landingPageUuid': app_uuid,
'groupIds': [12, 13],
'externalIdentifier': token,
'userInfo': {
'firstName': first_name,
'lastName': last_name,
'email': email,
'metadata': {
'storeId': 5

options = {
'method': 'POST',
'headers': headers,
'body': json.dumps(body),

resp ="https://{os.environ['RETOOL_URL']}/api/embed-url/external-user", **options)
if resp.ok:
return resp.json()
# Handle error

If you need to make sure users can only see data specific to them, see the Control access and app behavior with metadata section.

4. Use the embed URL to display the app

On your frontend, use the Retool React component to render the embed URL. Below is a sample request your frontend would make to your backend.

const RetoolWrapper = ({ retoolAppName, userJwt }) => {
const [retoolEmbedUrl, setRetoolEmbedUrl] = useState("");

useEffect(() => {
const options = {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userJwt, retoolAppName }),
fetch("/api/embedUrl", options)
.then((res) => res.json())
.then((data) => {
}, [retoolAppName]);

return (
retoolEmbedUrl && (
<Container maxWidth={false} disableGutters>
<Retool url={retoolEmbedUrl} />

Control data access and app behavior

There are a few ways to manage data access and control app behavior beyond permission groups. If permission groups don't provide the customization you need, try using metadata or React to interact with the parent application.

Control access and app behavior with metadata

You can pass information in the metadata object to dynamically control the data users see and behavior within an application. These variables are added to the current_user.metadata object when the embed URL is generated.

For example, with the set of metadata below, you could use the storeId to filter sales metrics for a specific store, or show a download button to users with canExportData enabled.

const options = {
method: "post",
headers: {
Authorization: `Bearer ${process.env.RETOOL_API_KEY}`,
"content-type": "application/json",
body: JSON.stringify({
landingPageUuid: LANDING_PAGE_UUID,
externalIdentifier: token,
groupIds: [12, 13],
userInfo: {
metadata: {
storeId: 51,
isAdmin: true,
canExportData: true,

Because current_user.metadata values are populated only when the embed URL is generated, you don't have access to them while you build your app. However, you can create a transformer that returns mock values that you can use while working on your app. After building your app, you can then replace each reference to the transformer with the values passed in the metadata object. These values are injected into the current_user.metadata object when the URL is generated.

Your metadata is secure

If you have Prevent Query Spoofing turned on, the metadata associated with the current user cannot be spoofed. Retool will reject any requests if a bad actor alters any metadata values passed in via the POST request above.

Interact with the parent application

You can interact with the parent application using React. Depending on your use case, you can listen for updates from Retool, or post information directly to the parent application.

Listen for updates from Retool

With the react-retool library, you can set up hooks that listen to state updates within the parent application. To do so, pass in a data object as a prop into the <Retool> component.

const RetoolWrapper = ({ isAdmin }) => (

Within the embedded Retool application, you can set up a Parent Window Query whose selector is a key within the data object:

Using a Parent Window Query

This application allows the user to export the report if isAdmin is true on the parent application. When the parent application changes, the Parent Window Query reruns and updates its value.

Export to S3 button is disabled when isAdmin is false

Post information to the parent application

You can write JavaScript queries within Retool that use the postMessage browser API to pass data to the parent application or invoke callback functions.

For example, the code below triggers a navigation change in the parent application from the embedded Retool app.

parent.postMessage("home", "");

You can also use the react-retool library to pass a function into the onData property. This function accepts data passed in from the JavaScript query called within the Retool app. For example, React code that sets the active tab in the app might look like this:

<Retool onData={(tab) => setActiveTab(tab)} />

Usage and billing

Activity is logged for users that have access to your embedded apps. These users have the Embed product experience, and you can view them on the Users page. Select a user to view which apps they've accessed and session metadata associated with them.

For the purposes of billing, these users are billed at the same rate as End users. To learn about custom pricing, book a call with our team.