See all articles

Metabase vs Looker for embedded analytics

Looker and Metabase both let customers explore their own data inside your app, and both use user attributes to limit each customer to its own rows. Looker does it with signed embedding and LookML access filters, and it needs the Embed edition of Looker (Google Cloud core), which Google prices by quote. Metabase does it with SSO embeds, row and column security and tenants, which are part of the Pro plan at $575 a month and the Enterprise plan.

How does Looker signed embedding work?

Signed embedding shows Looker dashboards, Looks and Explores in an iframe without a separate Looker login. Your server builds a special Looker URL that holds the content, the user’s ID in your app and the permissions you grant. Then it signs the URL with a secret key from Looker.

The URL carries parameters such as nonce, time, session_length, external_user_id, permissions, models, group_ids, external_group_id, user_attributes and access_filters, which you send as an empty placeholder, {}. The ca_chat parameter sets whether embed users see the Conversational Analytics dashboard agent pane on embedded dashboards. Looker uses external_user_id to tell embed users apart, so each user needs a unique ID. To build the string to sign, your server joins the host with login/embed/, the embed URL and the values from nonce to ca_chat, encoded as JSON, one per line. It signs that string with HMAC-SHA1 and the embed secret, and adds the result as the signature parameter.

Your server can also call the create_sso_embed_url API method (POST /embed/sso_url), which returns a signed URL, but it needs admin API credentials. Google keeps sample code in the looker_embed_sso_examples repository, and the Looker Embed SDK manages embedded content in the browser. With cookieless embedding, browsers that block third-party cookies can still sign users in to the iframe.

On Looker (Google Cloud core), signed embedding and cookieless embedding are only in the Embed edition. When you embed for several client companies, Google strongly recommends a closed system, also called a multi-tenant installation, and a separate Looker instance for customer content.

How do Looker access filters compare with Metabase row and column security?

In Looker, an access_filter on an Explore ties a field to a user attribute, so every query from that Explore is filtered by the user’s value. This follows Google’s access_filter reference:

explore: orders {
  access_filter: {
    field: orders.account_id
    user_attribute: account_id
  }
}

You set user attributes for each user or group, or pass them in user_attributes in the signed URL. Each access_filter belongs to one Explore, and Google’s docs note that an Explore without one isn’t restricted. LookML access grants control which Explores, joins, views and fields a user can reach.

In Metabase, each extra claim that you add to the JWT becomes a user attribute, which Metabase syncs on every login. Row and column security then filters a table by a column that matches the attribute. Custom security uses a saved SQL question instead, which can limit both rows and columns. Tenants group each customer’s users. The @tenant claim puts a user in a tenant, each tenant gets its own collection, and @tenant.slug works as an attribute in row and column security.

Two more options fit tenant rules that already live in your database. Connection impersonation runs each query with the database role named in the user’s attribute, on ClickHouse, MySQL, PostgreSQL, Redshift, Snowflake, SQL Server and Starburst or Trino. Database routing sends each tenant’s queries to its own database with the same schema.

Row and column security applies to query builder questions, so give customer groups the query builder, and use impersonation when they also need the SQL editor. Row and column security, tenants, connection impersonation and database routing are part of the Pro and Enterprise plans.

How do I embed Metabase with SSO for self-service analytics?

Modular embedding puts Metabase dashboards, questions, the query builder, AI chat and a collection browser into your app as web components. You can implement components into your app via a the low-code modular embedding wizard, or with the React SDK for more control and deeper customization options. People sign in through your app with JWT or SAML, and these SSO embeds are part of the Pro and Enterprise plans. Set up four things in Metabase:

  1. In Admin > Embedding, toggle on Enable modular embedding, enable the SDK for React under Modular, and add your app’s URL under Cross-Origin Resource Sharing (CORS).
  2. In Admin > Settings > Authentication, click JWT, enter your endpoint as the JWT Identity Provider URI, such as https://app.example.com/sso/metabase, and generate a key.
  3. In Admin settings > People, click the gear icon and choose Multi-tenant strategy to turn on tenants.
  4. In Admin > Permissions, give the All tenant users group row and column security on each table that holds customer data, filtered by the account_id attribute.

Then add the endpoint to your app. This Next.js route handler follows the SDK guide for Next.js and the authentication docs. The SDK calls it and expects { jwt } back:

// app/sso/metabase/route.ts
import jwt from "jsonwebtoken";

const METABASE_JWT_SHARED_SECRET = process.env.METABASE_JWT_SHARED_SECRET || "";

// Replace this with your app's session lookup.
async function getCurrentUser() {
  return {
    email: "rene@example.com",
    firstName: "Rene",
    lastName: "Descartes",
    tenantSlug: "acme",
    accountId: "42",
  };
}

export async function GET() {
  const user = await getCurrentUser();
  const token = jwt.sign(
    {
      email: user.email,
      first_name: user.firstName,
      last_name: user.lastName,
      "@tenant": user.tenantSlug,
      account_id: user.accountId,
      exp: Math.round(Date.now() / 1000) + 60 * 10, // 10 minutes
    },
    METABASE_JWT_SHARED_SECRET,
  );
  return Response.json({ jwt: token });
}

Install the SDK with the @{major}-stable tag that matches your Metabase version, for example @64-stable on Metabase 64. Then render the components, as in the SDK quickstart:

# Use the @{major}-stable tag that matches your Metabase version.
npm install @metabase/embedding-sdk-react@64-stable jsonwebtoken
// app/analytics/customer-analytics.tsx
"use client";

import {
  InteractiveDashboard,
  InteractiveQuestion,
  MetabaseProvider,
  defineMetabaseAuthConfig,
} from "@metabase/embedding-sdk-react";

const authConfig = defineMetabaseAuthConfig({
  metabaseInstanceUrl: "https://metabase.example.com",
});

export default function CustomerAnalytics() {
  return (
    <MetabaseProvider authConfig={authConfig}>
      <InteractiveDashboard dashboardId={1} />
      <InteractiveQuestion questionId="new" />
    </MetabaseProvider>
  );
}

InteractiveQuestion with questionId="new" opens the embedded query builder, so customers can build their own questions and save them, for example in their tenant collection. To embed the whole Metabase app in an iframe instead, use full-app embedding, which is also part of Pro and Enterprise. Metabase suggests modular embedding for new projects.

LookML vs Metabase models and metrics

LookML is the language Looker uses to create semantic data models. Developers define views, dimensions, measures, Explores and joins in LookML projects that live in Git, and business users then query the Explores without writing SQL. Google says that metrics defined in a Looker model can be used in Connected Sheets, Data Studio (formerly Looker Studio), Power BI, Tableau and ThoughtSpot.

Metabase builds its semantic layer from your tables and the definitions you add to them in the query builder or in SQL. A metric is the official way to calculate a number, and Metabase’s Data Studio adds measures, segments and a glossary on top of your tables. To build curated tables, Metabase uses transforms, which write the results of a query to your database, and its docs call transforms the successor to models. Basic SQL transforms are included when you self-host Metabase and are billed per run on Metabase Cloud. On Pro and Enterprise plans, the Library collects your trusted tables and metrics, and Remote Sync keeps them as YAML files in Git. Changes can then go through review in pull requests before they reach a read-only production Metabase.

Looker embed pricing vs Metabase pricing

Looker publishes no list prices. Its pricing page lists the Standard, Enterprise and Embed editions of Looker (Google Cloud core) as “Call sales” on an annual commitment of one, two or three years. You pay a platform fee for each instance and a license for each user, and each platform includes 10 Standard users and 2 Developer users. The Embed edition includes up to 500,000 query-based API calls a month, and trial instances last 90 days after you request one through a form.

Metabase publishes its prices. Pro costs $575 a month with 10 users, and each extra user costs $12 a month. People who view SSO embeds sign in, so they count as users, while guest embeds don’t add users. Enterprise starts at $20,000 a year, and Enterprise customers can get per-tenant or flat-fee pricing for large embedded deployments. Metabase Cloud Starter and Pro come with a 14-day free trial, and the open-source edition is free to self-host.

Looker (Google Cloud core)Metabase
Edition for SSO embeddingEmbed edition, priced by quotePro at $575 a month, or Enterprise from $20,000 a year
Users10 Standard and 2 Developer users included, more by quote10 users included in Pro, then $12 a month each
How to start90-day trial instance on requestOpen-source edition for guest embeds, or a 14-day Cloud trial

What does a first embed take?

In Metabase, a guest embed works on every edition, including the free open-source edition. Toggle on Enable guest embeds in Admin > Embedding, which sits under Guest embeds on paid plans. Then open a dashboard, click Share > Embed, choose Guest under Authentication, and publish to get the code. Guest embeds are view-only and filter data with locked parameters that your server signs. For SSO embeds, you need the four settings above, the API route and one React component. To try the SDK on your laptop first, npx @metabase/embedding-sdk-react@latest start starts Metabase in Docker with sample data and writes example components, for local evaluation only.

In Looker, a first signed embed needs an Embed edition instance and a LookML project with a model and an Explore. A Looker admin turns on signed embedding, creates an embed secret and adds your domain to the embed allowlist. Your server then signs each URL or calls create_sso_embed_url.

Where does each tool fit?

Looker fits a data team that wants one central modeling layer, written in LookML, kept in Git and owned by the data team, with access rules in the same code. It also fits teams that run on Google Cloud, because Looker (Google Cloud core) manages access with Google Cloud IAM and reaches BigQuery over Google’s private network. Looker’s Conversational Analytics, powered by Gemini, answers natural language questions from Explores and can be embedded with an iframe.

Metabase fits a product team that wants customers to explore and build their own reports inside the app, with SSO embeds, tenants, a React SDK and published prices. On Pro and Enterprise plans, the embedded AI chat lets customers ask Metabot questions in plain language.

Next steps

# Metabase vs Looker for embedded analytics

Looker and Metabase both let customers explore their own data inside your app, and both use user attributes to limit each customer to its own rows. Looker does it with signed embedding and LookML access filters, and it needs the Embed edition of Looker (Google Cloud core), which Google prices by quote. Metabase does it with SSO embeds, row and column security and tenants, which are part of the Pro plan at $575 a month and the Enterprise plan.

## How does Looker signed embedding work?

Signed embedding shows Looker dashboards, Looks and Explores in an iframe without a separate Looker login. Your server builds a special Looker URL that holds the content, the user's ID in your app and the permissions you grant. Then it signs the URL with a secret key from Looker.

The URL carries parameters such as `nonce`, `time`, `session_length`, `external_user_id`, `permissions`, `models`, `group_ids`, `external_group_id`, `user_attributes` and `access_filters`, which you send as an empty placeholder, `{}`. The `ca_chat` parameter sets whether embed users see the Conversational Analytics dashboard agent pane on embedded dashboards. Looker uses `external_user_id` to tell embed users apart, so each user needs a unique ID. To build the string to sign, your server joins the host with `login/embed/`, the embed URL and the values from `nonce` to `ca_chat`, encoded as JSON, one per line. It signs that string with HMAC-SHA1 and the embed secret, and adds the result as the `signature` parameter.

Your server can also call the `create_sso_embed_url` API method (`POST /embed/sso_url`), which returns a signed URL, but it needs admin API credentials. Google keeps sample code in the [looker_embed_sso_examples](https://github.com/looker/looker_embed_sso_examples) repository, and the Looker Embed SDK manages embedded content in the browser. With cookieless embedding, browsers that block third-party cookies can still sign users in to the iframe.

On Looker (Google Cloud core), signed embedding and cookieless embedding are only in the Embed edition. When you embed for several client companies, Google strongly recommends a closed system, also called a multi-tenant installation, and a separate Looker instance for customer content.

## How do Looker access filters compare with Metabase row and column security?

In Looker, an `access_filter` on an Explore ties a field to a user attribute, so every query from that Explore is filtered by the user's value. This follows Google's [access_filter reference](https://docs.cloud.google.com/looker/docs/reference/param-explore-access-filter):

```javascript
explore: orders {
  access_filter: {
    field: orders.account_id
    user_attribute: account_id
  }
}
```

You set user attributes for each user or group, or pass them in `user_attributes` in the signed URL. Each `access_filter` belongs to one Explore, and Google's docs note that an Explore without one isn't restricted. LookML access grants control which Explores, joins, views and fields a user can reach.

In Metabase, each extra claim that you add to the JWT becomes a user attribute, which Metabase syncs on every login. [Row and column security](/docs/latest/permissions/row-and-column-security) then filters a table by a column that matches the attribute. Custom security uses a saved SQL question instead, which can limit both rows and columns. [Tenants](/docs/latest/embedding/tenants) group each customer's users. The `@tenant` claim puts a user in a tenant, each tenant gets its own collection, and `@tenant.slug` works as an attribute in row and column security.

Two more options fit tenant rules that already live in your database. [Connection impersonation](/docs/latest/permissions/impersonation) runs each query with the database role named in the user's attribute, on ClickHouse, MySQL, PostgreSQL, Redshift, Snowflake, SQL Server and Starburst or Trino. [Database routing](/docs/latest/permissions/database-routing) sends each tenant's queries to its own database with the same schema.

Row and column security applies to query builder questions, so give customer groups the query builder, and use impersonation when they also need the SQL editor. Row and column security, tenants, connection impersonation and database routing are part of the Pro and Enterprise plans.

## How do I embed Metabase with SSO for self-service analytics?

[Modular embedding](/docs/latest/embedding/modular-embedding) puts Metabase dashboards, questions, the query builder, AI chat and a collection browser into your app as web components. You can implement components into your app via a the low-code modular embedding wizard, or with the [React SDK](/docs/latest/embedding/sdk/introduction) for more control and deeper customization options. People sign in through your app with JWT or SAML, and these SSO embeds are part of the Pro and Enterprise plans. Set up four things in Metabase:

1. In Admin > Embedding, toggle on Enable modular embedding, enable the SDK for React under Modular, and add your app's URL under Cross-Origin Resource Sharing (CORS).
2. In Admin > Settings > Authentication, click JWT, enter your endpoint as the JWT Identity Provider URI, such as `https://app.example.com/sso/metabase`, and generate a key.
3. In Admin settings > People, click the gear icon and choose Multi-tenant strategy to turn on tenants.
4. In Admin > Permissions, give the All tenant users group row and column security on each table that holds customer data, filtered by the `account_id` attribute.

Then add the endpoint to your app. This Next.js route handler follows the [SDK guide for Next.js](/docs/latest/embedding/sdk/next-js) and the [authentication docs](/docs/latest/embedding/authentication). The SDK calls it and expects `{ jwt }` back:

```typescript
// app/sso/metabase/route.ts
import jwt from "jsonwebtoken";

const METABASE_JWT_SHARED_SECRET = process.env.METABASE_JWT_SHARED_SECRET || "";

// Replace this with your app's session lookup.
async function getCurrentUser() {
  return {
    email: "rene@example.com",
    firstName: "Rene",
    lastName: "Descartes",
    tenantSlug: "acme",
    accountId: "42",
  };
}

export async function GET() {
  const user = await getCurrentUser();
  const token = jwt.sign(
    {
      email: user.email,
      first_name: user.firstName,
      last_name: user.lastName,
      "@tenant": user.tenantSlug,
      account_id: user.accountId,
      exp: Math.round(Date.now() / 1000) + 60 * 10, // 10 minutes
    },
    METABASE_JWT_SHARED_SECRET,
  );
  return Response.json({ jwt: token });
}
```

Install the SDK with the `@{major}-stable` tag that matches your Metabase version, for example `@64-stable` on Metabase 64. Then render the components, as in the [SDK quickstart](/docs/latest/embedding/sdk/quickstart):

```bash
# Use the @{major}-stable tag that matches your Metabase version.
npm install @metabase/embedding-sdk-react@64-stable jsonwebtoken
```

```typescript
// app/analytics/customer-analytics.tsx
"use client";

import {
  InteractiveDashboard,
  InteractiveQuestion,
  MetabaseProvider,
  defineMetabaseAuthConfig,
} from "@metabase/embedding-sdk-react";

const authConfig = defineMetabaseAuthConfig({
  metabaseInstanceUrl: "https://metabase.example.com",
});

export default function CustomerAnalytics() {
  return (
    <MetabaseProvider authConfig={authConfig}>
      <InteractiveDashboard dashboardId={1} />
      <InteractiveQuestion questionId="new" />
    </MetabaseProvider>
  );
}
```

`InteractiveQuestion` with `questionId="new"` opens the [embedded query builder](/docs/latest/embedding/query-builder), so customers can build their own questions and save them, for example in their tenant collection. To embed the whole Metabase app in an iframe instead, use [full-app embedding](/docs/latest/embedding/full-app-embedding), which is also part of Pro and Enterprise. Metabase suggests modular embedding for new projects.

## LookML vs Metabase models and metrics

LookML is the language Looker uses to create semantic data models. Developers define views, dimensions, measures, Explores and joins in LookML projects that live in Git, and business users then query the Explores without writing SQL. Google says that metrics defined in a Looker model can be used in Connected Sheets, Data Studio (formerly Looker Studio), Power BI, Tableau and ThoughtSpot.

Metabase builds its semantic layer from your tables and the definitions you add to them in the query builder or in SQL. A [metric](/docs/latest/data-modeling/semantic-layer/metrics) is the official way to calculate a number, and Metabase's Data Studio adds measures, segments and a glossary on top of your tables. To build curated tables, Metabase uses transforms, which write the results of a query to your database, and its docs call transforms the successor to [models](/docs/latest/data-modeling/models/models). Basic SQL transforms are included when you self-host Metabase and are billed per run on Metabase Cloud. On Pro and Enterprise plans, the Library collects your trusted tables and metrics, and Remote Sync keeps them as YAML files in Git. Changes can then go through review in pull requests before they reach a read-only production Metabase.

## Looker embed pricing vs Metabase pricing

Looker publishes no list prices. Its pricing page lists the Standard, Enterprise and Embed editions of Looker (Google Cloud core) as "Call sales" on an annual commitment of one, two or three years. You pay a platform fee for each instance and a license for each user, and each platform includes 10 Standard users and 2 Developer users. The Embed edition includes up to 500,000 query-based API calls a month, and trial instances last 90 days after you request one through a form.

Metabase publishes its prices. Pro costs $575 a month with 10 users, and each extra user costs $12 a month. People who view SSO embeds sign in, so they count as users, while guest embeds don't add users. Enterprise starts at $20,000 a year, and Enterprise customers can get per-tenant or flat-fee pricing for large embedded deployments. Metabase Cloud Starter and Pro come with a 14-day free trial, and the open-source edition is free to self-host.

|  | Looker (Google Cloud core) | Metabase |
|---|---|---|
| Edition for SSO embedding | Embed edition, priced by quote | Pro at $575 a month, or Enterprise from $20,000 a year |
| Users | 10 Standard and 2 Developer users included, more by quote | 10 users included in Pro, then $12 a month each |
| How to start | 90-day trial instance on request | Open-source edition for guest embeds, or a 14-day Cloud trial |

## What does a first embed take?

In Metabase, a guest embed works on every edition, including the free open-source edition. Toggle on Enable guest embeds in Admin > Embedding, which sits under Guest embeds on paid plans. Then open a dashboard, click Share > Embed, choose Guest under Authentication, and publish to get the code. Guest embeds are view-only and filter data with locked parameters that your server signs. For SSO embeds, you need the four settings above, the API route and one React component. To try the SDK on your laptop first, `npx @metabase/embedding-sdk-react@latest start` starts Metabase in Docker with sample data and writes example components, for local evaluation only.

In Looker, a first signed embed needs an Embed edition instance and a LookML project with a model and an Explore. A Looker admin turns on signed embedding, creates an embed secret and adds your domain to the embed allowlist. Your server then signs each URL or calls `create_sso_embed_url`.

## Where does each tool fit?

Looker fits a data team that wants one central modeling layer, written in LookML, kept in Git and owned by the data team, with access rules in the same code. It also fits teams that run on Google Cloud, because Looker (Google Cloud core) manages access with Google Cloud IAM and reaches BigQuery over Google's private network. Looker's Conversational Analytics, powered by Gemini, answers natural language questions from Explores and can be embedded with an iframe.

Metabase fits a product team that wants customers to explore and build their own reports inside the app, with SSO embeds, tenants, a React SDK and published prices. On Pro and Enterprise plans, the embedded AI chat lets customers ask Metabot questions in plain language.

## Next steps

- [Full-app embedding](/docs/latest/embedding/full-app-embedding)
- [Modular embedding SDK for React](/docs/latest/embedding/sdk/introduction)
- [Row and column security](/docs/latest/permissions/row-and-column-security)
- [Tenants](/docs/latest/embedding/tenants)
- [Embedding authentication](/docs/latest/embedding/authentication)
- [Modular embedding](/docs/latest/embedding/modular-embedding)
- [Embedded query builder](/docs/latest/embedding/query-builder)
- [Pricing](/pricing)