Embedded analytics SDK - questions

⚠️ 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.

There are different ways you can embed questions:

Embedding a static question

You can embed a static question using the StaticQuestion component.

The component has a default height, which can be customized by using the height prop. To inherit the height from the parent container, you can pass 100% to the height prop.

import React from "react";
import {MetabaseProvider, StaticQuestion} from "@metabase/embedding-sdk-react";

const authConfig = {...}

export default function App() {
    const questionId = 1; // This is the question ID you want to embed

    return (
        <MetabaseProvider authConfig={authConfig}>
            <StaticQuestion questionId={questionId} withChartTypeSelector={false}/>
        </MetabaseProvider>
    );
}

Embedding an interactive question

You can embed an interactive question using the InteractiveQuestion component.

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

const authConfig = {...}

export default function App() {
    const questionId = 1; // This is the question ID you want to embed

    return (
        <MetabaseProvider authConfig={authConfig}>
            <InteractiveQuestion questionId={questionId}/>
        </MetabaseProvider>
    );
}

Question props

Prop Type Description
questionId number or string (required) The ID of the question. This is either:
- The numerical ID when accessing a question link, e.g., http://localhost:3000/question/1-my-question where the ID is 1.
- The entity_id key of the question object. You can find a question’s entity ID in the info panel when viewing a question.
plugins { mapQuestionClickActions: Function } or null Additional mapper function to override or add drill-down menu.
height number or string (optional) A number or string specifying a CSS size value that specifies the height of the component
entityTypeFilter string array; options include “table”, “question”, “model”, “metric” (optional) An array that specifies which entity types are available in the data picker
isSaveEnabled boolean (optional) Whether people can save the question.
withResetButton boolean (optional, default: true) Determines whether a reset button is displayed. Only relevant when using the default layout
withChartTypeSelector boolean (optional, default: true) Determines whether the chart type selector is shown. Only relevant when using the default layout.
title boolean or string or ReactNode or () => ReactNode (optional) Determines whether the question title is displayed, and allows a custom title to be displayed instead of the default question title. Shown by default. Only Only applicable to interactive questions when using the default layout.
onBeforeSave () => void (optional) A callback function that triggers before saving. Only relevant when isSaveEnabled = true.
onSave () => void (optional) A callback function that triggers when a user saves the question. Only relevant when isSaveEnabled = true.
saveToCollectionId number (optional) The target collection to save the question to. This will hide the collection picker from the save modal. Only applicable to interactive questions.
initialSqlParameters Record<string, string \| string[]> (optional) A mapping of SQL parameters names to parameter values, such as { product_id: "42" }.

Passing SQL parameters to questions

You can pass parameter values to questions defined with SQL via the initialSqlParameters prop, in the format of {parameter_name: parameter_value}. Learn more about SQL parameters.


<StaticQuestion questionId={questionId} initialSqlParameters={{ product_id: 50 }} />

Customizing interactive questions

By default, the Embedded analytics SDK provides a default layout for interactive questions that allows you to view your questions, apply filters and aggregations, and access functionality within the query builder.

Here’s an example of using the InteractiveQuestion component with its default layout:

<InteractiveQuestion questionId={95} />

To customize the layout, use namespaced components within the InteractiveQuestion component. For example:


<InteractiveQuestion questionId={95}>
  <div
    style={{
      display: "flex",
      flexDirection: "column",
      alignItems: "center",
      justifyContent: "center",
    }}
  >
    <div style={{ display: "grid", placeItems: "center" }}>
      <InteractiveQuestion.Title />
      <InteractiveQuestion.ResetButton />
    </div>
    <div
      style={{
        display: "flex",
        alignItems: "center",
        justifyContent: "flex-start",
        overflow: "hidden",
      }}
    >
      <div style={{ width: "100%" }}>
        <InteractiveQuestion.QuestionVisualization />
      </div>
      <div style={{ display: "flex", flex: 1, overflow: "scroll" }}>
        <InteractiveQuestion.Summarize />
      </div>
    </div>
    <div style={{ display: "flex", flexDirection: "column" }}>
      <InteractiveQuestion.Filter />
    </div>
  </div>
</InteractiveQuestion>

Interactive question components

These components are available via the InteractiveQuestion namespace (e.g., <InteractiveQuestion.Filter />).

Component Info
BackButton The back button, which provides back functionality for the InteractiveDashboard
FilterBar The row of badges that contains the current filters that are applied to the question
Filter The Filter pane containing all possible filters
FilterPicker Picker for adding a new filter to the question
FilterButton The button used in the default layout to open the Filter pane. You can replace this button with your own implementation.
ResetButton The button used to reset the question after the question has been modified with filters/aggregations/etc
Title The question’s title
SaveButton Button for saving the question.
Summarize The Summarize pane containing all possible aggregations
SummarizeButton The button used in the default layout to open the Summarize pane. You can replace this button with your own implementation.
Notebook The Notebook editor that allows for more filter, aggregation, and custom steps
NotebookButton The button used in the default layout to open the Notebook editor. You can replace this button with your own implementation.
QuestionVisualization The chart visualization for the question
QuestionSettings The settings for the current visualization

Interactive question plugins

You can use plugins to add custom functionality to your questions.

mapQuestionClickActions

This plugin allows you to add custom actions to the click-through menu of an interactive question. You can add and customize the appearance and behavior of the custom actions.

// You can provide a custom action with your own `onClick` logic.
const createCustomAction = clicked => ({
  buttonType: "horizontal",
  name: "client-custom-action",
  section: "custom",
  type: "custom",
  icon: "chevronright",
  title: "Hello from the click app!!!",
  onClick: ({ closePopover }) => {
    alert(`Clicked ${clicked.column?.name}: ${clicked.value}`);
    closePopover();
  },
});

// Or customize the appearance of the custom action to suit your need.
const createCustomActionWithView = clicked => ({
  name: "client-custom-action-2",
  section: "custom",
  type: "custom",
  view: ({ closePopover }) => (
    <button
      className="tw-text-base tw-text-yellow-900 tw-bg-slate-400 tw-rounded-lg"
      onClick={() => {
        alert(`Clicked ${clicked.column?.name}: ${clicked.value}`);
        closePopover();
      }}
    >
      Custom element
    </button>
  ),
});

const plugins = {
  /**
   * You will have access to default `clickActions` that Metabase renders by default.
   * So you could decide if you want to add custom actions, remove certain actions, etc.
   */
  mapQuestionClickActions: (clickActions, clicked) => {
    return [
      ...clickActions,
      createCustomAction(clicked),
      createCustomActionWithView(clicked),
    ];
  },
};

const questionId = 1; // This is the question ID you want to embed

return (
  <MetabaseProvider authConfig={authConfig} pluginsConfig={plugins}>
    <InteractiveQuestion questionId={questionId} />
  </MetabaseProvider>
);

Embedding an editable interactive question

You can edit an existing question using the query builder by passing the isSaveEnabled prop on the InteractiveQuestion component.

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

const authConfig = {...}

export default function App() {
    return (
        <MetabaseProvider authConfig={authConfig}>
            <InteractiveQuestion questionId={1} isSaveEnabled />
        </MetabaseProvider>
    );
}

Embedding the query builder

With the CreateQuestion component, you can embed the query builder without a pre-defined question.

This component is built on top of the InteractiveQuestion component with namespaced components. It shares the same props as InteractiveQuestion, except it lacks the questionId prop and the ability to pass custom children.

To customize the question editor’s layout, use the InteractiveQuestion component directly with a custom children prop.

import React from "react";
import {MetabaseProvider, CreateQuestion} from "@metabase/embedding-sdk-react";

const authConfig = {...}

export default function App() {
    return (
        <MetabaseProvider authConfig={authConfig}>
            <CreateQuestion />
        </MetabaseProvider>
    );
}

Read docs for other versions of Metabase.