> [!NOTE]
> **Note:** If you are using a Looker (Google Cloud core) instance, to enable signed embedding you must use the Embed edition of Looker (Google Cloud core). If you are using a Looker (original) instance, signed embedding must be enabled for your instance. [Contact a Google Cloud sales specialist](https://cloud.google.com/contact) to enable this feature.

Signed embedding is a way to present private embedded Looks, visualizations, Explores, dashboards, or LookML dashboards to your users without requiring them to have a separate Looker login. Instead, users will be authenticated through your own application.

Signed embedding works by creating a special Looker URL that you will use in an iframe. The URL contains the information you want to share, the ID of the user in your system, and the permissions that you want the user to have. You'll then sign the URL with a secret key provided by Looker.

For public embedding, see the [Public embedding with `iframe` tags](https://docs.cloud.google.com/looker/docs/publishing-looks-with-public-urls.md.txt#public_embedding_with_iframe_tags) section of the **Public sharing, importing, and embedding of Looks** documentation page.

Before you can use signed embedding on your Looker instance, a Looker admin must enable signed embedding in the Looker **Admin** panel and create an embed secret key. For instructions, see the [**Getting started with embedding --- enabling signed embedding**](https://docs.cloud.google.com/looker/docs/embed-enable.md.txt) documentation page.

## Proper hosting for signed embedding

Some browsers --- for example, Safari, or browsers with extensions installed that block ads or tracking cookies --- default to a cookie policy that blocks third-party cookies. When the [**Cookieless Embed**](https://docs.cloud.google.com/looker/docs/admin-panel-platform-embed.md.txt#cookieless_embed) feature is enabled, browsers that block third-party cookies can authenticate users in the embedded iframe across different domains. Cookieless embed authentication requires server-side configuration. See the [Cookieless embedding](https://docs.cloud.google.com/looker/docs/cookieless-embed.md.txt) documentation page for setup examples.

> [!NOTE]
> **Note:** You can view a list of the cookies that Looker uses on the [Looker cookie list](https://docs.cloud.google.com/looker/docs/cookie-list.md.txt) documentation page.

If the **Cookieless Embed** feature is not enabled, Looker uses cookies for user authentication. In this case, attempting to authenticate the embedded iframe across domains is not possible in browsers that block third-party cookies (unless the user modifies their browser's cookie privacy settings). For example, if you want to embed information on `https://mycompany.com`, you need to make sure that Looker shares the same domain, such as `https://analytics.mycompany.com`. In this case, if Looker is hosting your instance, [contact Looker Support](https://docs.cloud.google.com/looker/docs/best-practices/looker-support-details.md.txt) to set up the necessary DNS configuration to enable custom domain use. This will allow Looker to share the same domain as the embed application and to utilize first party cookies, which are accepted by default in all browsers.

If you have a customer-hosted Looker instance, make sure that the application that will use signed embedding uses the same domain as your Looker instance.

## Controlling client visibility with a closed system

It is common in a signed embed configuration for Looker users to present data to their own customers while having clients from different companies or groups who shouldn't know about one another. In this scenario, to safeguard your customers' private information, we strongly recommend that you configure Looker as a closed system, also called a *multi-tenant installation* . In a closed system, content is siloed to prevent users from different groups from knowing about each other. For this reason, we recommend that you enable the [**Closed System** option](https://docs.cloud.google.com/looker/docs/admin-panel-general-settings.md.txt#closed_system) before you grant any external users access to your instance.

For more information, see the [Designing and configuring a system of access levels](https://docs.cloud.google.com/looker/docs/access-levels.md.txt) and the [Security best practices for embedded analytics](https://docs.cloud.google.com/looker/docs/security-best-practices-embedded-analytics.md.txt) documentation pages.

## Generating the signed embed URL

There are multiple ways to generate the signed embed URL. You can use one of these methods:

- You can [generate a signed embed URL](https://docs.cloud.google.com/looker/docs/get-signed-embed-url.md.txt) using the **Get embed URL** option on the [three-dot dashboard menu](https://docs.cloud.google.com/looker/docs/viewing-dashboards.md.txt#three-dot_dashboard_menu) of a dashboard, or on the [Explore actions gear menu](https://docs.cloud.google.com/looker/docs/viewing-looks.md.txt#the_look_explore_actions_gear_menu) of a Look or Explore.

- Use the [Looker API Create Signed Embed Url endpoint](https://docs.cloud.google.com/looker/docs/reference/looker-api/latest/methods/Auth/create_sso_embed_url.md.txt), as described [later in this document](https://docs.cloud.google.com/looker/docs/signed-embedding.md.txt#using_the_create_sso_embed_url_api_endpoint).

- Use the [Looker Embed SDK](https://docs.cloud.google.com/looker/docs/embed-sdk-demo.md.txt).

- [Code the signed embed URL](https://docs.cloud.google.com/looker/docs/signed-embedding.md.txt#manually_coding_the_signed_embed_url). Building the proper URL will require you to write code so that you can properly encode the URL with your secret key and generate other security-related items. You can find several sample scripts in the Looker [Embed examples GitHub repository](https://github.com/looker/looker_embed_sso_examples). The following sections explain the information that you'll need to supply to those scripts, as well as how to build a signed embed URL without using a script.

> [!NOTE]
> **Note:** You can have only one user session per browser. When you are developing, you can be logged in to your regular browser as your admin or developer users. When you want to test a signed embed configuration, you can use an incognito window or a different browser. Otherwise, your original user will be logged out of the original session. If your page embeds multiple Looker iframes, see [Best practices for embedding multiple iframes with signed embedding](https://docs.cloud.google.com/looker/docs/signed-embedding.md.txt#best-practices-multiple-iframes).

## Manually coding the signed embed URL

To code the signed embed URL, first [collect the necessary Looker information](https://docs.cloud.google.com/looker/docs/signed-embedding.md.txt#collecting_the_necessary_looker_information), and then [create the signed embed URL](https://docs.cloud.google.com/looker/docs/signed-embedding.md.txt#creating_the_embed_url).

### Collecting the necessary Looker information

As a starting point for building your URL, you'll first want to determine all the information that will need to be included. You will need:

#### Embed URL

Retrieve the URL of the Look, Explore, query visualization, or dashboard that you want to embed. Then remove the domain and place `/embed` before the path, as follows:

| Item | Normal URL Pattern | Embed URL |
|---|---|---|
| Look | `https://instance_name.looker.com/looks/4` | `/embed/looks/4` |
| Explore | `https://instance_name.looker.com/explore/my_model/my_explore` | `/embed/explore/my_model/my_explore` |
| Query visualization | `https://instance_name.looker.com/explore/my_model/my_explore?qid=1234567890abcdefghij12` <br /> <br /> The 22 alphanumeric characters that follow the `qid=` parameter in the Explore URL make up the `Query.client_id`. The `Query.client_id` value is a unique string that represents the query and the visualization settings. <br /> <br /> To embed a query visualization, retrieve the query visualization `Query.client_id` value, and copy the `Query.client_id` into your embed URL. <br /> <br /> You can use the Looker [Explore](https://docs.cloud.google.com/looker/docs/creating-and-editing-explores.md.txt) UI to build a query with a supported visualization and copy the `Query.client_id` value from the `qid=` parameter, or you can retrieve the `Query.client_id` with the Looker API, using the [`Get Query`](https://docs.cloud.google.com/looker/docs/reference/looker-api/latest/methods/Query/query.md.txt) method, for example. | `/embed/query-visualization/Query.client_id` |
| User-defined dashboard | `https://instance_name.looker.com/dashboards/1` <br /> <br /> Include any dashboard filter values [hiding filter values](https://docs.cloud.google.com/looker/docs/filters-user-defined-dashboards.md.txt#hiding_dashboard_filters), the `hide_filter` parameter in the dashboard URL. | `/embed/dashboards/1` |
| LookML dashboard | `https://instance_name.looker.com/dashboards/my_model::my_dashboard` | `/embed/dashboards/my_model::my_dashboard` |
| Conversational Analytics | For the conversations page: `https://instance_name.looker.com/conversations` <br /> <br /> For the agents page: `https://instance_name.looker.com/agents` <br /> <br /> For a specific conversation: `https://instance_name.looker.com/conversations/conversation_id` <br /> <br /> For more information, see the [Embedding Conversational Analytics](https://docs.cloud.google.com/looker/docs/conversational-analytics-looker-embedding.md.txt) documentation page. | `/embed/conversations` <br /> <br /> `/embed/agents` <br /> <br /> `/embed/conversations/c9f370ac830b4669aeb494396422004c` |

> [!IMPORTANT]
> **Important:** Embedded content always reflects the production version of the content. Any changes made while in [Development Mode](https://docs.cloud.google.com/looker/docs/dev-mode-prod-mode.md.txt) that affect content and that have not been deployed to production won't appear in an embed.

#### Permissions

A permission set defines what a [user](https://docs.cloud.google.com/looker/docs/admin-panel-users-users.md.txt) or [group](https://docs.cloud.google.com/looker/docs/admin-panel-users-groups.md.txt) can do. Permissions can be applied in one of two ways:

- **Model Specific:** This type of permission is applied only to the [model sets](https://docs.cloud.google.com/looker/docs/admin-panel-users-roles.md.txt#model_sets) that are part of the same role.
- **Instance Wide:** This type of permission applies to the Looker instance as a whole. Embed users with instance-wide permissions can perform certain functions across the entire Looker instance, but cannot access content based on models not included in their role's model set.

Determine the permissions that you'll want the user to have. The following list shows all available permissions for signed embedding. Permissions that are not on the following list are not supported for signed embedding:

| Permission | Depends On | Type | Definition |
|---|---|---|---|
| `access_data` | None | Model Specific | Allows user to access data (required for viewing Looks, dashboards, or Explores) |
| `see_lookml_dashboards` | `access_data` | Model Specific | Lets user see LookML dashboards. This permission is required even if a user has **View** access to the dashboard's folder. |
| `see_looks` | `access_data` | Model Specific | Lets user see Looks |
| `see_user_dashboards` | `see_looks` | Model Specific | Lets user see user-defined dashboards and to browse folders from an embed |
| `explore` | `see_looks` | Model Specific | Lets user see Explore pages |
| `create_table_calculations` | `explore` | Instance Wide | Needed to create [table calculations](https://docs.cloud.google.com/looker/docs/table-calculations.md.txt) in an Explore |
| `create_custom_fields` | `explore` | Instance Wide | Needed to create [custom fields](https://docs.cloud.google.com/looker/docs/custom-fields.md.txt) in an Explore |
| `can_create_forecast` | `explore` | Instance Wide | Allows users to create or edit [forecasts in visualizations](https://docs.cloud.google.com/looker/docs/forecasting-in-visualizations.md.txt). |
| `save_content` | `see_looks` | Instance Wide | Lets user make and save changes to Looks and dashboards |
| `send_outgoing_webhook` | `see_looks` | Model Specific | Lets user schedule Looker content deliveries to an arbitrary webhook |
| `send_to_s3` | `see_looks` | Model Specific | Lets user schedule Looker content deliveries to an Amazon S3 bucket |
| `send_to_sftp` | `see_looks` | Model Specific | Lets user schedule Looker content deliveries to an SFTP server |
| `schedule_look_emails` | `see_looks` | Model Specific | Lets user schedule Looker content deliveries to their own email (if set with a [user attribute](https://docs.cloud.google.com/looker/docs/admin-panel-users-user-attributes.md.txt) named "email") or to an email address that is within the limitations set by the [email domain allowlist](https://docs.cloud.google.com/looker/docs/admin-panel-general-settings.md.txt#email_domain_allowlist_for_scheduled_looks). Lets user with `create_alerts` permissions send alert notifications to an email address that is within the limitations set by the [email domain allowlist](https://docs.cloud.google.com/looker/docs/admin-panel-general-settings.md.txt#email_domain_allowlist_for_scheduled_looks). |
| `schedule_external_look_emails` | `schedule_look_emails` | Model Specific | Lets user schedule Looker content deliveries to any email domain. Lets user with `create_alerts` permissions send alert notifications to any email domain. |
| `send_to_integration` | `see_looks` | Model Specific | Lets user [deliver Looker content](https://docs.cloud.google.com/looker/docs/scheduling.md.txt) to the [third-party services integrated with Looker](https://docs.cloud.google.com/looker/docs/admin-panel-platform-actions.md.txt#list_of_integrated_services) through the Looker Action Hub. This permission is not related to [data actions](https://docs.cloud.google.com/looker/docs/reference/param-field-action.md.txt). |
| `schedule_without_limit` | `see_looks` | Model Specific | Added 26.4 When combined with at least one other permission that allows a user to deliver Looker content, this permission allows users to [deliver Looks or Explores](https://docs.cloud.google.com/looker/docs/delivering-looks-explores.md.txt) that send all data rows. This permission makes visible the **All Results** option in the Looker Scheduler for Looks and Explores. |
| `create_alerts` | `see_looks` | Instance Wide | Lets user create [alerts](https://docs.cloud.google.com/looker/docs/alerts-overview.md.txt) on dashboard tiles to receive notifications when specified conditions are met or exceeded. Users can edit, duplicate, and delete their own alerts and other users' **Public** alerts. If the user's Slack workspace is not connected to the Looker instance, the user won't be able to create alerts that send notifications to Slack. |
| `download_with_limit` | `see_looks` | Instance Wide | Lets user download a query's results with a limit applied |
| `download_without_limit` | `see_looks` | Instance Wide | Lets user download a query's results with no limit applied |
| `see_sql` | `see_looks` | Model Specific | Lets user see the SQL for queries and any SQL errors resulting from running queries |
| `clear_cache_refresh` | `access_data` | Model Specific | Users can clear cache and refresh embedded dashboards, legacy dashboards, dashboard tiles, Looks, and Explores. |
| `see_drill_overlay` | `access_data` | Model Specific | Lets user drill without needing to go to the full Explore page. |
| `manage_spaces` | None | Instance Wide | Enables the content browser so that users can create, copy, move, and delete folders. Users will also need the [**Manage Access, Edit**](https://docs.cloud.google.com/looker/docs/access-levels.md.txt#types_of_access_to_folders) content access permission for the folder, or, in the case of creating a new folder, for the parent folder. |
| `embed_browse_spaces` | None | Instance Wide | Enables the content browser so that a user can browse folders from an embed. Any embed user who is granted `embed_browse_spaces` permission is given access to a [personal embed folder](https://docs.cloud.google.com/looker/docs/viewing-embedded-items.md.txt#using_embedded_spaces_to_find_looks_and_dashboards) and to your organization's **Shared** folder, if there is one. <br /> The `embed_browse_spaces` permission is recommended for users who have the `save_content` permission, so that the user can browse folders when selecting where to save content. <br /> To see the content in folders, the user also needs the [`see_looks`](https://docs.cloud.google.com/looker/docs/signed-embedding.md.txt#see_looks), [`see_user_dashboards`](https://docs.cloud.google.com/looker/docs/signed-embedding.md.txt#see_user_dashboards), and [`see_lookml_dashboards`](https://docs.cloud.google.com/looker/docs/signed-embedding.md.txt#see_lookml_dashboards) permissions. <br /> <br /> The `embed_browse_spaces` permission is required for embed users who want to mark dashboards or Looks as favorites, since marking content as a favorite requires access to the **Favorites** folder. |
| `embed_save_shared_space` | None | Instance Wide | Lets user who also has the `save_content` permission navigate to the organization's **Shared** folder, if there is one, from within the **Save** dialog. Users who have the `save_content` permission but not the `embed_save_shared_space` permission will only have the option to save content to their [personal embed folder](https://docs.cloud.google.com/looker/docs/viewing-embedded-items.md.txt#using_embedded_spaces_to_find_looks_and_dashboards). <br /> The `embed_save_shared_space` permission does not override [content access permissions](https://docs.cloud.google.com/looker/docs/organizing-spaces.md.txt#viewing_and_managing_access_for_a_folder). For example, to enable a user to be able to save to the **Shared** folder, they still need **Manage Access, Edit** access to the **Shared** folder. In addition, the lack of the `embed_save_shared_space` permission doesn't prevent a user who has the `save_content` permission and **Manage Access, Edit** access to the **Shared** folder from saving content there if they have an alternate way to navigate to the **Shared** folder, such as by using the **Explore from here** option from an embedded dashboard. |
| `gemini_in_looker` | None | Model Specific | This permission is the only permission that is included in the **Gemini** [default role](https://docs.cloud.google.com/looker/docs/admin-panel-users-roles.md.txt#gemini). <br /> This permission grants users the ability to perform the tasks that are associated with any of the Gemini in Looker features that are enabled from the **Gemini in Looker** page in the **Admin** panel. Additional permissions may be required for some tasks. |
| `chat_with_agent` | `gemini_in_looker` | Model Specific | Added 25.18 Conversational Analytics users can chat with [data agents](https://docs.cloud.google.com/looker/docs/conversational-analytics-looker-data-agents.md.txt) that are based on the data from up to five Looker Explores or with [dashboard data agents](https://docs.cloud.google.com/looker/docs/conversational-analytics-looker-data-agents-dashboards.md.txt). [Additional permissions](https://docs.cloud.google.com/looker/docs/conversational-analytics-looker-setup.md.txt#required-permissions) are required to chat with dashboard data agents. |
| `chat_with_explore` | `chat_with_agent` | Model Specific | Added 25.18 Conversational Analytics users can chat with a Looker Explore when they also have [additional required permissions](https://docs.cloud.google.com/looker/docs/conversational-analytics-looker-setup.md.txt#required-permissions). |
| `save_agents` | `chat_with_explore` | Model Specific | Added 25.18 Conversational Analytics users can create, edit, delete, and share [data agents](https://docs.cloud.google.com/looker/docs/conversational-analytics-looker-data-agents.md.txt) on dashboards or Explores. To edit, delete, or share a data agent that was created by another user, users must be granted a role that contains this permission on every model that is used by the agent as well as [additional required permissions](https://docs.cloud.google.com/looker/docs/conversational-analytics-looker-setup.md.txt#required-permissions) and **Manage Access, Edit** access to the agent. |
| `admin_agents` | `gemini_in_looker` | Model Specific | Added 25.18 For use with the Conversational Analytics API and [embedded Conversational Analytics](https://docs.cloud.google.com/looker/docs/conversational-analytics-looker-embedding.md.txt), users can create, edit, share, and delete data agents. When a user creates a data agent, they're granted **Manage Access, Edit** data agent access automatically. With this permission, a user doesn't need to be granted content access to the data agent in order to [edit, delete](https://docs.cloud.google.com/looker/docs/conversational-analytics-looker-data-agents.md.txt#create-and-edit-data-agents), or [share](https://docs.cloud.google.com/looker/docs/conversational-analytics-looker-data-agents.md.txt#share-data-agents) a data agent that was created by another user. |

#### Model access

Determine which LookML models the user should have access to. This will be a [list of model names](https://docs.cloud.google.com/looker/docs/signed-embedding.md.txt#models).

#### User attributes

Determine which [user attributes](https://docs.cloud.google.com/looker/docs/admin-panel-users-user-attributes.md.txt) the user should have, if any. You'll need the name of the user attribute from Looker, as well as the value that the user should have for that attribute.

#### Groups

Determine which [groups](https://docs.cloud.google.com/looker/docs/admin-panel-users-groups.md.txt) the user should belong to, if any. You'll need the group IDs as opposed to the group names. Adding a signed embed user to a Looker group lets you manage that user's access to Looker folders. Signed embed users will [have access](https://docs.cloud.google.com/looker/docs/viewing-embedded-items.md.txt#interacting_with_an_embedded_look,_explore,_or_dashboard) to any folders that are shared with members of their Looker groups.

You can also use the [`external_group_id` parameter](https://docs.cloud.google.com/looker/docs/signed-embedding.md.txt#parameters) to create a group that is external to the regular Looker groups. In that case, signed embed users with the same `external_group_id` will [have access](https://docs.cloud.google.com/looker/docs/viewing-embedded-items.md.txt#interacting_with_an_embedded_look,_explore,_or_dashboard) to a shared folder, named "Group," that is unique to the external group.

> [!NOTE]
> **Note:** The `external_group_id` parameter is the only available method for creating external groups of embed users. There is no way to configure external embed user groups from within the Looker UI.
>
> <br />
>
> Signed embed users are distinct, synthetic users generated by the embed URL and can't inherit permissions from SAML externally managed groups. To grant permissions to a signed embed user, you must use locally managed Looker groups and pass those group IDs in the `group_ids` parameter of the embed URL. If you need to respect externally managed SAML group permissions within an embedded iframe, use [private embedding](https://docs.cloud.google.com/looker/docs/private-embedding.md.txt) instead of signed embedding, which lets the user authenticate through the standard SAML login process.

#### Embedded roles

The `permissions` and `models` parameters create a [role](https://docs.cloud.google.com/looker/docs/admin-panel-users-roles.md.txt) for the embed user. This role appears as an "Embedded Role" in the [**Users** page in Looker's **Admin** section](https://docs.cloud.google.com/looker/docs/admin-panel-users-users.md.txt). If the `permissions`, `models`, and `group_ids` parameters are all specified in the embed URL, then the embedded role is *additive* to any roles already assigned to the groups listed in the `group_ids` parameter. This is the same as standard roles in that all roles in Looker are additive.

For example, say you have an existing group in Looker with the group ID `1`, and that group already has the `explore` permission for a model named `model_one`, and you create an embed URL with the following parameters:

- `group_ids` = `["1"]`
- `permissions` = `["access_data","see_looks"]`
- `models` = `["model_two"]`

In that case, the embed user will inherit the ability to view and explore the data on `model_one`, and the embed role created with the preceding parameters will also grant the ability to view the data on `model_two`.

### Creating the embed URL

A signed embed URL has the following format:

https://HOST/login/embed/EMBED URL?PARAMETERS\&signature=SIGNATURE

#### Host

The host is the location where your Looker instance is being hosted. For example, `analytics.mycompany.com`. Be sure to include the port number if you haven't enabled port forwarding, such as `analytics.mycompany.com:9999`.

#### Embed URL

The embed URL was determined previously. It will have a format such as:

- `/embed/looks/4`
- `/embed/explore/my_model/my_explore`
- `/embed/query-visualization/Query.client_id`
- `/embed/dashboards/1` or `/embed/dashboards-legacy/1`
- `/embed/dashboards/my_model::my_dashboard` or `/embed/dashboards-legacy/my_model::my_dashboard`

This does mean that the pattern `/embed//embed/` will show up in your final URL; this is correct.

If you are using [embedded JavaScript events](https://docs.cloud.google.com/looker/docs/embedded-javascript-events.md.txt) be sure to add the `embed_domain` parameter (the domain where the iframe is being used) to the end of the embed URL, like this:
`/embed/looks/4` ⇨ `/embed/looks/4?embed_domain=https://mywebsite.com`

The `embed_domain` parameter is added to the embed URL before URL encoding. If your embed URL already contains content query parameters (such as filter values), append the `embed_domain` parameter using an ampersand (`&`):
`/embed/looks/4?filter_name=value` ⇨ `/embed/looks/4?filter_name=value&embed_domain=https://mywebsite.com`

If you are using the [Embed SDK](https://docs.cloud.google.com/looker/docs/embed-sdk.md.txt) be sure to add the `embed_domain` parameter and also include `sdk=2` to the end of the embed URL, like this:
`/embed/looks/4` ⇨ `/embed/looks/4?embed_domain=https://mywebsite.com&sdk=2`

The `sdk=2` parameter lets Looker identify that the SDK is present and can take advantage of additional features provided by the SDK. The SDK cannot add this parameter itself because it is part of the signed URL.

> [!IMPORTANT]
> **Important:** The `embed_domain` and `sdk` parameters must be appended directly to the target content embed URL before URL encoding. Don't include `embed_domain` or `sdk` in the top-level query parameters of the `/login/embed/` URL or in the signed parameter list used for signature calculation. Doing so results in the error `This request includes invalid params: ["embed_domain", "sdk"]`.

#### Parameters

The following URL parameters are used to specify the necessary information for the signed embed:

| Parameter | Default Value | Description | Data Type | Example |
|---|---|---|---|---|
| `nonce` | Value Required | Any random string you like, but it cannot be repeated within an hour and must be less than 255 characters. <br /> <br /> This prevents an attacker from re-submitting a legitimate user's URL to gather information they shouldn't have. | JSON String | `"22b1ee700ef3dc2f500fb7"` |
| `time` | Value Required | The current time as a UNIX timestamp. | Integer | `1407876784` |
| `session_length` | Value Required | The number of seconds that the user should remain logged in to Looker, between 0 and 2,592,000 seconds (30 days). | Integer | `86400` |
| `external_user_id` | Value Required | An identifier for each user in the application that is embedding Looker. Looker uses `external_user_id` to differentiate signed embed users, so each user must have a unique ID assigned to them. <br /> <br /> You can create an `external_user_id` for a user with any string you like, as long as it's unique to that user. Each ID is associated with a set of permissions, user attributes, and models. A single browser can support only one `external_user_id`, or user session, at a time. No changes can be made to a user's permissions or user attributes mid-session. <br /> <br /> For security purposes, ensure that you are not using the same `external_user_id` across different embed sessions for different interactive users, and ensure that you are not using the same `external_user_id` for a single user who has different permissions, user attribute values, or model access. <br /> <br /> Using the same `external_user_id` for multiple users or for the same user with multiple permissions, user attributes, or model sets, can cause data to be visible to users who otherwise wouldn't have access to it. | JSON string | `"user-4"` |
| `permissions` | Value Required | The list of permissions the user should have. <br /> <br /> See the [Permissions](https://docs.cloud.google.com/looker/docs/signed-embedding.md.txt#permissions) section on this page for the list of allowed permissions. | Array of strings | `[` <br /> `"access_data",` <br /> `"see_looks"` <br /> `]` |
| `models` | Value Required | The list of model names the user should have access to. | Array of strings | `[` <br /> `"model_one",` <br /> `"model_two"` <br /> `]` |
| `group_ids` | \[\] | The list of Looker groups the user should be a member of, if any. Use group IDs instead of group names. | Array of strings | `["4", "3"]` |
| `external_group_id` | "" | A unique identifier for the group that the user belongs to in the application that is embedding Looker. <br /> <br /> Users who have permission to save content, and who share an external group ID, can save and edit content in a [shared Looker folder called "Group"](https://docs.cloud.google.com/looker/docs/viewing-embedded-items.md.txt#using_embedded_spaces_to_find_looks_and_dashboards). The `external_group_id` parameter is the only available method for creating external groups of embed users. There is no way to configure external embed user groups from within the Looker UI. <br /> <br /> The length of the `external_group_id` shouldn't exceed 81 characters. A corresponding folder is created for the group, and folder names have a limit of 100 characters. The folder name is prefixed with "Embed Shared Group ", so the `external_group_id` is restricted to 81 characters to keep it to the 100 or fewer character limit. | JSON string | `"Accounting"` |
| `user_attributes` | {} | The list of [user attributes](https://docs.cloud.google.com/looker/docs/admin-panel-users-user-attributes.md.txt) the user should have, if any. Contains a list of user attribute names followed by the user attribute value. <br /> <br /> If your [LookML model is localized](https://docs.cloud.google.com/looker/docs/model-localization.md.txt), you can use the `locale` user attribute in the embed URL to specify a language for the embed. For example, including the parameter `user_attributes { "locale" : "fr_FR" }` would cause the embed to load French as its language. | Hash of strings | `{` <br /> `"vendor_id" : "17",` <br /> `"company" : "xactness"` <br /> `}` |
| `access_filters` | Value Required | In Looker 3.10 this parameter was removed, but it is still required in the URL. Use `access_filters` with an empty placeholder, for example `access_filters={}`. | Empty Placeholder | `{}` |
| `first_name` | "" | The user's first name. If left blank, `first_name` will retain the value from the last request, or be "Embed" if no first name has ever been set. | JSON string | `"Alice"` |
| `last_name` | "" | The user's last name. If left blank, `last_name` will retain the value from the last request, or be "Embed" if no last name has ever been set. | JSON string | `"Jones"` |
| `user_timezone` | "" | If you've enabled [User Specific Time Zones](https://docs.cloud.google.com/looker/docs/admin-panel-general-settings.md.txt#user_specific_time_zones), sets the value of the **Viewer Time Zone** option in the **Time Zone** drop-down on the embedded Look or dashboard. This parameter does not directly change the time zone in which the content is shown; the user will need to select a time zone from the drop-down. <br /> <br /> See valid values on the [Signed embedding time zone reference](https://docs.cloud.google.com/looker/docs/sso-embedding-time-zone-reference) documentation page. <br /> <br /> **Chat team tip:** If you want your embedded content to default to the viewer's time zone, use one of the following methods: <br /> <br /> - Add the parameter `?query_timezone=user_timezone` to the [embed URL](https://docs.cloud.google.com/looker/docs/signed-embedding.md.txt#embed_url). For example: <br /> <br /> `/embed/dashboards/1?query_timezone=user_timezone` - Save the embedded dashboard or Look with the [default time zone](https://docs.cloud.google.com/looker/docs/editing-legacy-dashboards#default_timezone) set to **Viewer Time Zone**, which will use the user's time zone by default for both embed users and non-embed users. | JSON string or null | `"US/Pacific"` <br /> <br /> - or - <br /> <br /> `null` |
| `force_logout_login` | Value Required | If a normal Looker user is already logged in to Looker, and they view a signed embedded item, you can choose if: <br /> <br /> 1) they should view the item with their current credentials <br /> <br /> or <br /> <br /> 2) they should be logged out and logged back in with the signed embed credentials. | Boolean (true or false) | `true` |
| `ca_chat` | `true` | If you've enabled Conversational Analytics and the **Dashboard agents** setting, sets whether the dashboard agent conversation pane is visible to embed users. If `true`, the ![](https://fonts.gstatic.com/s/i/short-term/release/googlesymbols/chat_spark/default/24px.svg) Gemini spark is visible to users who have the [appropriate permissions to interact with dashboard agents](https://docs.cloud.google.com/looker/docs/conversational-analytics-looker-setup.md.txt#required-permissions). Applies to embedded dashboards only. | Boolean (true or false) | `true` |

#### Signature

Looker uses the signature to verify that the correct embed secret was used to generate the signature in the embed URL and that the parameters in the embed URL have not changed. If either the embed secret or URL parameters are different or have changed, the signature won't match and the authentication will be rejected.

As a result, the signature in the embed URL provides cryptographically strong proof that the embed URL was not modified in transit and that the embed URL was created by a trusted party who has possession of the embed secret key.

To generate the signature you'll need to follow these steps.

1. Gather the following parameter values in this order:
   - Host, followed by `login/embed/` (for example, `analytics.mycompany.com/login/embed/`)
   - Embed URL
   - Nonce
   - Current Time
   - Session Length
   - External User ID
   - Permissions
   - Models
   - Group IDs
   - External Group ID
   - User Attributes
   - Access Filters (requires an empty placeholder)
   - Conversational Analytics dashboard data agent visibility
2. Format all values other than Host and Embed URL as JSON
3. Concatenate the values with line breaks (`\n`)
4. HMAC-SHA1 sign the concatenated string with your Looker embed secret key

#### Encoding

The final step is to URL encode your URL.

*Before* you encode the URL, a properly formatted embed URL that uses all possible parameters might look like this:

    https://analytics.mycompany.com/login/embed//embed/dashboards/1?
    nonce="22b1ee700ef3dc2f500fb7"&
    time=1407876784&
    session_length=86400&
    external_user_id="user-4"&
    permissions=["access_data","see_user_dashboards","see_looks"]&
    models=["model_one","model_two"]&
    group_ids=[4,3]&
    external_group_id="Allegra K"&
    user_attributes={"vendor_id":"17","company":"xactness"}&
    access_filters={}&
    ca_chat=false&
    first_name="Alice"&
    last_name="Jones"&
    user_timezone="US/Pacific"&
    force_logout_login=true&
    signature=123456789ABCDEFGHIJKL

As noted previously, it is correct for `/embed//embed/` to appear in your URL.

*After* you encode the URL, it would look like this:

    https://analytics.mycompany.com/login/embed/%2embed%2Fdashboards%2F1?
    nonce=%2222b1ee700ef3dc2f500fb7&%22&
    time=1407876784&
    session_length=86400&
    external_user_id=%22user-4%22&
    permissions=%5B%22access_data%22%2C%22see_user_dashboards%22%2C%22see_looks%22%5D&
    models=%5B%22model_one%22%2C%22model_two%22%5D&
    group_ids=%5B4%2C3%5D&
    external_group_id=%22Allegra%20K%22&
    user_attributes=%7B%22vendor_id%22%3A%2217%22%2C%22company%22%3A%22xactness%22%7D&
    access_filters%7B%7D%26%0A
    ca_chat=false&
    first_name=%22Alice%22&
    last_name=%22Jones%22&
    user_timezone=%22US%2FPacific%22&
    force_logout_login=true&
    signature=123456789ABCDEFGHIJKL

> [!NOTE]
> **Note:** For security purposes, once the embed URL is created, if the embed URL is not connected to within five minutes, the URL will expire and will no longer work.


## Using the Create Signed Embed Url API endpoint

The Looker API includes the [Create Signed Embed Url](https://docs.cloud.google.com/looker/docs/reference/looker-api/latest/methods/Auth/create_sso_embed_url.md.txt) endpoint, which takes a set of signed embed parameters that includes the URL of the content that you want to embed and returns a complete, encoded, cryptographically signed URL.

To use this API endpoint from a web server, the web server must be able to [authenticate into the Looker API](https://docs.cloud.google.com/looker/docs/api-auth.md.txt) with admin privileges. The web server domain must also be listed in the [Embed Domain Allowlist](https://docs.cloud.google.com/looker/docs/admin-panel-platform-embed.md.txt#embedded_domain_allowlist).

You can also use the [API Explorer](https://docs.cloud.google.com/looker/docs/api-explorer.md.txt) to generate a signed URL that uses this endpoint. You can install the API Explorer on your Looker instance from the [Looker Marketplace](https://docs.cloud.google.com/looker/docs/marketplace.md.txt). Once generated, the signed URL must be copied exactly and can be used only once --- otherwise, it will fail. The API Explorer is also useful for generating a signed URL and comparing it to a manually created signed URL for troubleshooting purposes.

For more information about the Looker API, see the [Getting started with the Looker API](https://docs.cloud.google.com/looker/docs/api-getting-started.md.txt) documentation page.

## Testing the embed URL

To test your final URL, paste it into the [Embed URI Validator](https://docs.cloud.google.com/looker/docs/admin-panel-platform-embed.md.txt#embed_uri_validator) on the **Embed** page of Looker's **Admin** section. While this option can't tell you if the data and permissions you envision have been set up correctly, it can validate that your authentication is working properly.

## Best practices for embedding multiple iframes with signed embedding

When you embed multiple Looker iframes on a single page, simultaneous authentication requests for the same `external_user_id` can cause user provisioning collisions, lock contention on the Looker server, or dropped sessions. Follow these best practices when your application embeds multiple iframes:

- **Authenticate only the first iframe with a signed URL:** When using signed embedding with cookies enabled through a custom domain, only the first iframe on the page should load a signed `/login/embed/...` URL. Subsequent iframes must wait until the first iframe finishes authenticating and then load unsigned embed URLs (for example, `/embed/dashboards/DASHBOARD_ID`) so that they inherit the session cookie from the first iframe without re-running user provisioning. The [Looker Embed SDK](https://www.npmjs.com/package/@looker/embed-sdk) (`@looker/embed-sdk`) handles this automatically after the first connection resolves.

- **Preload an iframe to establish the session:** To instantiate an embed user session before loading multiple iframes, preload an iframe by using `/embed/preload` (or the `.preload()` method in Embed SDK v2) to establish the session as quickly as possible.

- **Use in-frame navigation instead of recreating iframes:** When using Embed SDK v2, you can navigate within an already instantiated iframe by calling methods such as `connection.loadDashboard(DASHBOARD_ID)` or `connection.loadUrl(EMBED_URL)` rather than creating a new iframe. For more information, see [Introduction to the Embed SDK](https://docs.cloud.google.com/looker/docs/embed-sdk-intro.md.txt).

- **Share a single `session_reference_token` in cookieless embedding:** If you use [cookieless embedding](https://docs.cloud.google.com/looker/docs/cookieless-embed.md.txt) with multiple iframes on a page, see [Best practices for embedding multiple iframes with cookieless embedding](https://docs.cloud.google.com/looker/docs/cookieless-embed.md.txt#best-practices-multiple-iframes) on the **Cookieless embedding** page.