Embedded Analytics - The Developer's Complete Guide
Embedded analytics is the practice of integrating data visualizations, dashboards, and reports directly into a third-party application, so users can v...
Embedded Analytics: The Developer's Complete Guide
Embedded analytics is the practice of integrating data visualizations, dashboards, and reports directly into a third-party application, so users can view and interact with data without leaving the product they're already using. Rather than building a custom analytics UI from scratch or directing users to a separate BI tool, embedded analytics lets developers ship a fully functional analytics experience β charts, filters, drill-throughs, and all β by rendering it inside their own application.
Metabase is one of the most widely used platforms for embedded analytics because it provides a complete, deployable analytics layer with a mature embedding API, row-level security, and white-labeling β all of which are required to build a production-grade embedded experience.
---
Why Developers Choose Embedded Analytics Over Building From Scratch
Every product eventually needs to show users data about their own usage. The naive solution is to build custom charts using a library like Recharts, Chart.js, or D3. This works for simple use cases β a line chart showing monthly revenue, a bar chart showing active users β but breaks down quickly when requirements grow:
- Users want to filter by date range, segment, or custom dimensions
Each of these requirements adds weeks of engineering work. Embedded analytics solves this by providing a pre-built analytics layer that handles querying, rendering, interactivity, and user customization β leaving the product team to focus on their core application.
Build vs. Embed: A Realistic Cost Comparison
| Approach | Initial Build | Ongoing Maintenance | User Customization |
|---|---|---|---|
| Custom charting library | 2β6 months | High (every schema change requires UI updates) | Requires engineering for each new feature |
| Embedded analytics (Metabase) | 1β5 days | Low (Metabase handles rendering and querying) | Users can create their own questions and dashboards |
| Buy enterprise BI | Weeks to months (procurement + implementation) | Medium (requires dedicated analyst) | Yes, but separate tool users must learn |
How Metabase Embedding Works
Metabase embedding works by rendering a Metabase dashboard or question inside an in the host application. The host application controls what data the iframe receives via URL parameters and, for authenticated embedding, cryptographically signed tokens.
The overall flow looks like this:
Host Application Metabase
β β β 1. User loads page β β 2. Server generates signed URL β β (JWT token + parameters) β β 3. Renders <iframe src={url}> β βββββββββββββββββββββββββββββββββ βΆβ β β 4. Validates JWT signature β β 5. Applies row-level filters β β 6. Executes query ββ βββββββββββββββββββββββββββββββ β 7. Returns rendered dashboard β 8. Dashboard displays in iframe β
The host application never directly queries the database. Metabase handles all query execution. The host application only needs to generate a signed URL and render an iframe.
---
Embedding Options in Metabase
Metabase offers two embedding modes with fundamentally different security models:
Public Embedding (No Authentication)
Public embedding makes a dashboard or question accessible to anyone with the link β no login required. Metabase generates a public URL, and any iframe pointing to that URL will display the dashboard.
When to use it:
When not to use it:
How to enable it: In Metabase, open a dashboard β Sharing β Enable public sharing β copy the public URL.
Signed Embedding (JWT Authentication)
Signed embedding β available in Metabase Pro and Enterprise β is the standard approach for production SaaS deployments. The host application generates a JWT token signed with a shared secret. The token encodes which dashboard to show and what parameters to apply. Metabase validates the signature and renders the dashboard with those parameters enforced server-side.
When to use it:
How it works:
MB_EMBEDDING_SECRET_KEY (a shared secret known only to Metabase and your server)Because the token is signed server-side and the secret never reaches the browser, users cannot modify the parameters to see data that doesn't belong to them.
---
Setting Up Signed Embedding: Step by Step
Prerequisites
MB_EMBEDDING_SECRET_KEY set as an environment variable in your Metabase deploymentStep 1: Configure the Embedding Secret
Set the embedding secret in your Metabase configuration:
bash
<h1 class="text-4xl font-bold mb-6 text-slate-900">In your Docker run command or docker-compose.yml</h1> MB_EMBEDDING_SECRET_KEY=your-long-random-secret-key
Generate a strong secret:
bash
openssl rand -hex 32
This secret must be kept server-side. Never expose it to the browser.
Step 2: Enable Embedding on the Dashboard
In Metabase, open the dashboard you want to embed:
Step 3: Generate a Signed URL (Server-Side)
Here's how to generate a signed embed URL in Node.js:
javascript
const jwt = require("jsonwebtoken");
function getSignedEmbedUrl(dashboardId, params = {}) { const METABASE_SITE_URL = process.env.METABASE_SITE_URL; const METABASE_SECRET_KEY = process.env.METABASE_SECRET_KEY;
const payload = { resource: { dashboard: dashboardId }, params: params, exp: Math.round(Date.now() / 1000) + (10 * 60), // 10 minute expiry };
const token = jwt.sign(payload, METABASE_SECRET_KEY);
return ${METABASE_SITE_URL}/embed/dashboard/${token}#bordered=true&titled=true; }
// Usage: embed dashboard 42, filtered to company_id 99 const embedUrl = getSignedEmbedUrl(42, { company_id: 99 });
Python equivalent:
python
import jwt import time import os
def get_signed_embed_url(dashboard_id: int, params: dict = {}) -> str: METABASE_SITE_URL = os.environ["METABASE_SITE_URL"] METABASE_SECRET_KEY = os.environ["METABASE_SECRET_KEY"]
payload = { "resource": {"dashboard": dashboard_id}, "params": params, "exp": round(time.time()) + (10 * 60) # 10 minute expiry }
token = jwt.encode(payload, METABASE_SECRET_KEY, algorithm="HS256") return f"{METABASE_SITE_URL}/embed/dashboard/{token}#bordered=true&titled=true"
<h1 class="text-4xl font-bold mb-6 text-slate-900">Usage</h1> embed_url = get_signed_embed_url(42, {"company_id": 99})
Step 4: Render the iframe
In your frontend:
html
<!-- Simple HTML --> <iframe src="{{ embed_url }}" frameborder="0" width="100%" height="600" allowtransparency ></iframe>
jsx
// React function EmbeddedDashboard({ embedUrl }) { return ( <iframe src={embedUrl} frameBorder={0} width="100%" height={600} allowTransparency /> ); }
The embedUrl should come from your server β never compute it client-side, as that would require exposing the secret key to the browser.
---
Passing Parameters to Embedded Dashboards
Parameters let you filter the data shown in an embedded dashboard based on the context of the current user or page. This is how multi-tenant analytics works: you pass the current user's company_id as a locked parameter, and Metabase ensures the dashboard only shows data matching that ID.
Setting Up Parameters on the Dashboard
In Metabase, add a filter to your dashboard:
Passing Locked Parameters
Locked parameters are passed in the JWT payload:
javascript
const payload = { resource: { dashboard: 42 }, params: { company_id: currentUser.companyId, // locked β user cannot change this // date_range is not specified β user can adjust it freely }, exp: Math.round(Date.now() / 1000) + (10 * 60), };
Parameters in the JWT payload are enforced server-side. Users cannot bypass them by modifying the URL.
Passing Editable Parameters via URL
Editable parameters (those not locked in the JWT) can be pre-populated via URL hash parameters:
javascript
const url = ${METABASE_SITE_URL}/embed/dashboard/${token}#company_id=99&date_range=last30days;
These can be changed by the user in the dashboard's filter UI.
---
Controlling the Embedded UI
Metabase provides several URL parameters to control the appearance of embedded dashboards:
| Parameter | Values | Description |
|---|---|---|
bordered | true / false | Show/hide the border around the dashboard |
titled | true / false | Show/hide the dashboard title |
theme | night | Enable dark mode |
hide_parameters | param_name | Hide specific filter controls |
font | Font name | Override the dashboard font (Enterprise) |
/embed/dashboard/{token}#bordered=false&titled=false&theme=night
For full white-labeling β removing all Metabase branding β see the white-labeling guide in this series.
---
Security Considerations
Always generate tokens server-side. The embedding secret must never be exposed to the browser. If a user can see the secret, they can generate arbitrary tokens and access any data.
Set a short token expiry. Tokens with a long expiry increase the window during which a stolen token could be used. 10 minutes is a reasonable default for tokens generated per page load.
Validate user identity before generating the token. Your server should only generate an embed URL after confirming the user is authenticated and authorized to see the data. The JWT token itself does not carry authentication β it's your server's responsibility to verify the user before issuing one.
Use HTTPS everywhere. The embed URL contains the signed token. If transmitted over HTTP, it can be intercepted and reused. Always serve Metabase over HTTPS in production.
Don't cache embed URLs across users. Generate a new token for each user session. A cached URL with one user's company_id parameter should never be served to a different user.
---
Common Embedding Patterns
Per-Customer Usage Dashboard (SaaS)
The most common embedded analytics pattern: each customer has a dashboard showing their own usage data. The host application passes the customer's id or organization_id as a locked parameter.
javascript
// On the customer's analytics page const embedUrl = getSignedEmbedUrl(USAGE_DASHBOARD_ID, { organization_id: session.user.organizationId });
Role-Based Dashboard Selection
Different user roles see different dashboards. An admin sees a full operational dashboard; a regular user sees a summarized view.
javascript
const dashboardId = session.user.role === "admin" ? ADMIN_DASHBOARD_ID : USER_DASHBOARD_ID;
const embedUrl = getSignedEmbedUrl(dashboardId, { user_id: session.user.id });
Contextual Analytics (In-Page Embedding)
Embedding a small chart or metric directly in a product page β not a full dashboard. Use a single Metabase question (not a dashboard) embedded in a card or widget.
javascript
const payload = { resource: { question: questionId }, // question, not dashboard params: { order_id: currentOrderId }, exp: Math.round(Date.now() / 1000) + (10 * 60), };
---
Limitations of Iframe Embedding
Iframe-based embedding has a few inherent limitations:
For teams that need deeper integration β custom interactivity, programmatic control, or native mobile embedding β see the Metabase SDK (beta), which provides React components that render Metabase content without an iframe.
---
Summary
Embedded analytics with Metabase lets developers add a full analytics layer to their product in days rather than months. The core mechanism is an iframe rendered with a server-signed JWT token that locks parameters to control what data each user sees. Public embedding works without authentication for non-sensitive use cases. Signed embedding β available in Pro and Enterprise β is the production approach for multi-tenant SaaS applications. The key security requirement is that token generation always happens server-side, keeping the embedding secret out of the browser.