Skip to main content

Overview

Embedded analytics lets you mount Go Fig dashboards inside your own application as an iframe. Each of your customers signs in to your product. The embed shows them their own dashboards and only their own rows. You never expose a Go Fig login, and one customer can never see another customer’s data. The flow is always the same three steps:
  1. On your server, mint a short-lived token that names which of your customers is viewing and whether they may edit.
  2. Exchange the token for a handshake URL and drop that URL into the iframe’s src.
  3. On first load the embed swaps the token for a cookie and cleans it out of the URL, so the credential never rides a later request.
Embedded analytics is provisioned per team. Ask Go Fig support to enable an Embedded team for your organization. You configure the rest in the setup wizard described below.

Roles

Every token carries exactly one role. A viewer reads the team’s shared template project. An editor gets a private project of their own, keyed on the tenant identifier in their token so two editors from two of your customers never share a workspace.

Setup in the wizard

Open the embedded setup wizard for your team (Embedded → Setup). It walks four steps:
  1. Multitenant: declare the identity claims your tokens carry and pick which one is the tenant identifier (the claim that names one of your customers). This is the key your row filters and private-project routing hang on.
  2. Data: choose which tables the embed may expose and, per table, the filter column and the token claim whose value it must match. This is what scopes rows to a tenant (see Data isolation).
  3. Test: preview the embed as any tenant/role using the built-in picker.
  4. Deploy: register the origins allowed to frame your embed and copy your client API key and iframe snippet.

Registering embed origins

The embed refuses to render in a frame unless the framing page’s origin is on your allowlist. This is enforced with a per-customer frame-ancestors Content-Security-Policy directive.
  • Add each origin you embed from, e.g. https://app.acme.com.
  • An empty allowlist refuses all framing (frame-ancestors 'none'). This is the conservative default. A missing origin surfaces during setup, not in production.

Minting a token

Tokens are minted server-side. Never mint a token in the browser: minting requires your client API key, which must stay on your server. POST /embedded/api/token with your API key. Authenticate with an Authorization: Bearer header, an X-API-Key header, or an api_key field.
The claim names (account_id above) are the identity claims you enabled in the wizard. The tenant identifier claim is required. A request that omits it is refused with a 400, never issued a token that cannot be scoped. The response carries the token and, more usefully, the handshake URL to drop into your iframe:
Tokens expire in one hour (expires_in: 3600). Mint a fresh token per page load from your server. Do not cache or share tokens between your customers.

Embedding the iframe

Set the iframe src to the embedded_url from the token response:
On that first load the embed validates the token, plants a host-only session cookie, and redirects to a token-free URL. Every subsequent navigation inside the iframe carries the cookie so the token appears in exactly one URL (the initial src) and never again.
The framing page’s origin must be on your embed-origin allowlist (see Registering embed origins), or the browser refuses to render the frame.

Data isolation

Isolation runs at two levels, and both matter. Project level. A viewer reads the team’s shared template project. An editor gets a private project keyed on their tenant identifier so editors from different customers never share a workspace. Row level. Within a shared dashboard, the tenant row filter you configure in the wizard narrows every widget’s query to the rows belonging to the viewing tenant. For each table you gave a filter column and a token claim, the embed ANDs column == token[claim] onto the query before it runs. Two tenants viewing the same widget see two different result sets, and their cached results are keyed separately so one tenant can never read another’s bytes. The filter is fail-closed: any configuration that cannot be satisfied returns zero rows, never every tenant’s rows. A token that is missing its tenant claim, or missing a claim a configured filter needs, produces an empty result rather than a leak.
A table with no filter configured is served in full to every tenant. Configure a filter for every table that holds per-tenant data. An unfiltered table is a shared table by design.

Rate limits

Each tenant has its own request budget so one of your customers cannot starve another sharing the same embed. Viewers and editors carry independent sustained and burst limits, configurable per team. A tenant that exceeds either limit receives a 429. Other tenants are unaffected.

Troubleshooting