These are the docs for the Metabase master branch. Some features documented here may not yet be available in the latest release. Check out the docs for the latest version, Metabase v0.51.
Embedded analytics SDK - Using the SDK with Next.js
⚠️ This feature is in beta. Feel free to play around with it, but be aware that things might change (and may not work as expected).
Embedded analytics SDK is only available on Pro and Enterprise plans (both self-hosted and on Metabase Cloud). You can, however, play around with the SDK on your local machine without a license by using API keys to authenticate your embeds.
Some notes on using the Embedded analytics SDK with Next.js.
Using App Router
Create a component that imports the MetabaseProvider
and mark it as a React Client component with “use client”.
"use client";
import { MetabaseProvider, StaticQuestion, defineEmbeddingSdkConfig } from "@metabase/embedding-sdk-react";
const config = defineEmbeddingSdkConfig({
//...
}); // Your Metabase SDK configuration
export default function MetabaseComponents() {
return (
<MetabaseProvider config={config}>
<StaticQuestion questionId={QUESTION_ID} />
</MetabaseProvider>
);
You must use the default export. A named export isn’t supported with this setup, and it won’t work.
Then, import this component in your page:
// page.tsx
const MetabaseComponentsNoSsr = dynamic(
() => import("@/components/MetabaseComponents"),
{
ssr: false,
},
);
export default function HomePage() {
return (
<>
<MetabaseComponentsNoSsr />
</>
);
}
To repeat: if you export the component as a named export, it won’t work with Next.js. You must use a default export. For example, this won’t work:
const DynamicAnalytics = dynamic(
() =>
import("@/components/MetabaseComponents").then(
module => module.MetabaseComponents,
),
{
ssr: false,
},
);
Handling authentication
If you authenticate with Metabase using JWT, you can create a Route handler that signs people in to Metabase.
Create a new route.ts
file in your app/*
directory, for example app/sso/metabase/route.ts
that corresponds to an endpoint at /sso/metabase.
import jwt from "jsonwebtoken";
const METABASE_JWT_SHARED_SECRET = process.env.METABASE_JWT_SHARED_SECRET || "";
const METABASE_INSTANCE_URL = process.env.METABASE_INSTANCE_URL || "";
export async function GET() {
const token = jwt.sign(
{
email: user.email,
first_name: user.firstName,
last_name: user.lastName,
groups: [user.group],
exp: Math.round(Date.now() / 1000) + 60 * 10, // 10 minutes expiration
},
// This is the JWT signing secret in your Metabase JWT authentication setting
METABASE_JWT_SHARED_SECRET,
);
const ssoUrl = `${METABASE_INSTANCE_URL}/auth/sso?token=true&jwt=${token}`;
try {
const ssoResponse = await fetch(ssoUrl, { method: "GET" });
const ssoResponseBody = await ssoResponse.json();
return Response.json(ssoResponseBody);
} catch (error) {
if (error instanceof Error) {
return Response.json(
{
status: "error",
message: "authentication failed",
error: error.message,
},
{
status: 401,
},
);
}
}
}
Pass this config
to MetabaseProvider
import { defineEmbeddingSdkConfig } from "@metabase/embedding-sdk-react";
const config = defineEmbeddingSdkConfig({
metabaseInstanceUrl: "https://metabase.example.com", // Required: Your Metabase instance URL
authProviderUri: "/sso/metabase", // Required: An endpoint in your app that signs people in and returns a token.
});
Using pages router
This works almost the same as the App Router, but you don’t need to mark the component that imports the Metabase SDK components as a React Client component.
If you authenticate with Metabase using JWT, you can create an API route that signs people in to Metabase.
Create a new metabase.ts
file in your pages/api/*
directory, for example pages/api/sso/metabase.ts
that corresponds to an endpoint at /api/sso/metabase.
import type { NextApiRequest, NextApiResponse } from "next";
import jwt from "jsonwebtoken";
const METABASE_JWT_SHARED_SECRET = process.env.METABASE_JWT_SHARED_SECRET || "";
const METABASE_INSTANCE_URL = process.env.METABASE_INSTANCE_URL || "";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
const token = jwt.sign(
{
email: user.email,
first_name: user.firstName,
last_name: user.lastName,
groups: [user.group],
exp: Math.round(Date.now() / 1000) + 60 * 10, // 10 minutes expiration
},
// This is the JWT signing secret in your Metabase JWT authentication setting
METABASE_JWT_SHARED_SECRET,
);
const ssoUrl = `${METABASE_INSTANCE_URL}/auth/sso?token=true&jwt=${token}`;
try {
const ssoResponse = await fetch(ssoUrl, { method: "GET" });
const ssoResponseBody = await ssoResponse.json();
res.status(200).json(ssoResponseBody);
} catch (error) {
if (error instanceof Error) {
res.status(401).json({
status: "error",
message: "authentication failed",
error: error.message,
});
}
}
}
And pass this config
to MetabaseProvider
import { defineEmbeddingSdkConfig } from "@metabase/embedding-sdk-react";
const config = defineEmbeddingSdkConfig({
metabaseInstanceUrl: "https://metabase.example.com", // Required: Your Metabase instance URL
authProviderUri: "/api/sso/metabase", // Required: An endpoint in your app that returns signs the user in and delivers a token
});
Read docs for other versions of Metabase.