Skip to main content

Overview

The Lightdash React SDK (@lightdash/sdk) provides React components for embedding Lightdash content in your React or Next.js applications. The SDK offers advantages over iframe embedding:
  • Seamless integration with your React application
  • Programmatic filters for dashboards
  • Callbacks for user interactions (e.g., explore navigation)
  • Custom styling to match your application
  • TypeScript support with full type definitions
For iframe embedding, see the embedding reference.

Set up CORS

To use the React SDK, you need to update your “Cross-Origin Resource Sharing” (CORS) policy. This is done using environment variables. For Lightdash Cloud customers, contact the Lightdash team to update these for you.
LIGHTDASH_CORS_ENABLED=true
LIGHTDASH_CORS_ALLOWED_DOMAINS=https://domain-where-you-are-going-to-use-the-sdk.com
Why CORS is neededEnabling CORS (Cross-Origin Resource Sharing) is necessary because browsers enforce security policies that prevent web applications from making requests to a different domain than the one that served the app (known as the Same-Origin Policy).Since the Lightdash React SDK interacts with a Lightdash API, you need to configure CORS on your Lightdash instance to allow your frontend application to communicate with the Lightdash server without being blocked by the browser.
CORS is only required for the React SDK. iframe embedding does not require CORS configuration.

Installing the Lightdash SDK

In your frontend project, use your preferred package manager to install the SDK.
npm install @lightdash/sdk
# or
pnpm add @lightdash/sdk
# or
yarn add @lightdash/sdk
At the moment, we support React 18 and 19, so make sure your frontend is using React 18 or later. For Next.js, version 15 or later is required.

Components

The Lightdash SDK exports three components for embedding different content types:
  • Lightdash.Dashboard - Embed complete dashboards with multiple tiles
  • Lightdash.Chart - Embed individual saved charts
  • Lightdash.Explore - Embed interactive data exploration interface
All components share common props for authentication and styling.

Lightdash.Dashboard

Embed complete Lightdash dashboards with multiple visualizations, filters, and interactive features.

Props

type DashboardProps = {
  // Required
  instanceUrl: string;              // Your Lightdash instance URL
  token: string | Promise<string>;  // JWT token (can be async)

  // Optional
  styles?: {
    backgroundColor?: string;       // Background color or 'transparent'
    fontFamily?: string;            // Font family for all text
  };
  filters?: SdkFilter[];            // Apply filters programmatically
  contentOverrides?: LanguageMap;   // Localization/translation overrides
  onExplore?: (options: {
    chart: SavedChart
  }) => void;                       // Callback when user navigates to explore
};

Basic usage

import Lightdash from '@lightdash/sdk';

function MyDashboard() {
  return (
    <Lightdash.Dashboard
      instanceUrl="https://app.lightdash.cloud"
      token={generateToken()} // Server-side function
    />
  );
}

With filters

Apply filters programmatically using the filters prop:
import Lightdash, { FilterOperator } from '@lightdash/sdk';

<Lightdash.Dashboard
  instanceUrl="https://app.lightdash.cloud"
  token={token}
  filters={[
    {
      model: 'orders',
      field: 'status',
      operator: FilterOperator.EQUALS,
      value: 'completed',
    },
    {
      model: 'orders',
      field: 'created_date',
      operator: FilterOperator.IN_BETWEEN,
      value: ['2024-01-01', '2024-12-31'],
    },
  ]}
/>
See Filtering data for complete filter documentation.

With styling

<Lightdash.Dashboard
  instanceUrl="https://app.lightdash.cloud"
  token={token}
  styles={{
    backgroundColor: '#f5f5f5',
    fontFamily: 'Inter, sans-serif',
  }}
/>

With explore callback

Track when users navigate to explore:
<Lightdash.Dashboard
  instanceUrl="https://app.lightdash.cloud"
  token={generateToken({ canExplore: true })}
  onExplore={({ chart }) => {
    console.log('User exploring chart:', chart.name);
    // Track analytics, show help guides, etc.
  }}
/>

Lightdash.Chart

Embed individual saved charts for focused, single-metric displays with minimal UI.

Props

type ChartProps = {
  // Required
  instanceUrl: string;              // Your Lightdash instance URL
  id: string;                       // Chart UUID (savedQueryUuid)
  token: string | Promise<string>;  // JWT token with type: 'chart'

  // Optional
  styles?: {
    backgroundColor?: string;       // Background color or 'transparent'
    fontFamily?: string;            // Font family for all text
  };
  contentOverrides?: LanguageMap;   // Localization/translation overrides
};
Unlike Dashboard, Chart does not support filters or onExplore props since charts are read-only and cannot navigate to explore.

Basic usage

import Lightdash from '@lightdash/sdk';

function MyChart() {
  return (
    <Lightdash.Chart
      instanceUrl="https://app.lightdash.cloud"
      id="your-chart-uuid"
      token={generateChartToken()} // Server-side function
    />
  );
}

With styling

<Lightdash.Chart
  instanceUrl="https://app.lightdash.cloud"
  id="your-chart-uuid"
  token={token}
  styles={{
    backgroundColor: 'white',
    fontFamily: 'Helvetica, Arial, sans-serif',
  }}
/>

Token generation for charts

Charts require a JWT token with type: 'chart':
// Backend API endpoint
import jwt from 'jsonwebtoken';

export function generateChartToken(chartId) {
  return jwt.sign({
    content: {
      type: 'chart',
      contentId: chartId,  // savedQueryUuid
      canExportCsv: true,
      canExportImages: false,
      canViewUnderlyingData: true,
    },
  }, process.env.LIGHTDASH_EMBED_SECRET, { expiresIn: '24h' });
}
See Embedding charts guide for details.

Lightdash.Explore

Embed interactive data exploration interface with full query builder capabilities.

Props

type ExploreProps = {
  // Required
  instanceUrl: string;              // Your Lightdash instance URL
  token: string | Promise<string>;  // JWT token with canExplore: true

  // Optional
  styles?: {
    backgroundColor?: string;       // Background color or 'transparent'
    fontFamily?: string;            // Font family for all text
  };
  contentOverrides?: LanguageMap;   // Localization/translation overrides
};

Basic usage

import Lightdash from '@lightdash/sdk';

function MyExplore() {
  return (
    <Lightdash.Explore
      instanceUrl="https://app.lightdash.cloud"
      token={generateExploreToken()} // Must include canExplore: true
    />
  );
}

With styling

<Lightdash.Explore
  instanceUrl="https://app.lightdash.cloud"
  token={token}
  styles={{
    backgroundColor: '#f9f9f9',
    fontFamily: 'Inter, sans-serif',
  }}
/>

Token generation for explores

Explores require canExplore: true in the JWT token:
// Backend API endpoint
import jwt from 'jsonwebtoken';

export function generateExploreToken() {
  return jwt.sign({
    content: {
      type: 'dashboard',  // Can use dashboard type
      dashboardUuid: 'starting-dashboard-uuid',
      canExplore: true,   // Required for explore access
      canExportCsv: true,
      canExportImages: true,
    },
  }, process.env.LIGHTDASH_EMBED_SECRET, { expiresIn: '4h' });
}

Generating embed tokens

All SDK components require JWT tokens generated server-side. Here’s a complete example:

Backend API endpoint

// server/api/embed-token.ts
import jwt from 'jsonwebtoken';

export async function generateEmbedToken(req, res) {
  // Authenticate user
  const userId = req.user.id;
  const user = await getUserFromDatabase(userId);

  // Generate token with user-specific attributes
  const token = jwt.sign({
    content: {
      type: 'dashboard',
      dashboardUuid: 'your-dashboard-uuid',
      dashboardFiltersInteractivity: {
        enabled: 'all',
      },
      canExportCsv: true,
      canExplore: true,
    },
    userAttributes: {
      tenant_id: user.tenantId,  // Row-level filtering
    },
    user: {
      externalId: user.id,
      email: user.email,
    },
  }, process.env.LIGHTDASH_EMBED_SECRET, { expiresIn: '1h' });

  res.json({ token });
}

Frontend React component

import Lightdash from '@lightdash/sdk';
import { useState, useEffect } from 'react';

function EmbeddedDashboard() {
  const [token, setToken] = useState<string | null>(null);

  useEffect(() => {
    // Fetch token from your backend
    fetch('/api/embed-token')
      .then(res => res.json())
      .then(data => setToken(data.token));
  }, []);

  if (!token) return <div>Loading...</div>;

  return (
    <Lightdash.Dashboard
      instanceUrl="https://app.lightdash.cloud"
      token={token}
    />
  );
}
To ensure security, JWT token generation code must run in your backend, and the Lightdash embed secret must never be exposed in frontend code. This prevents unauthorized access and protects sensitive data.

Applying styles

Override styles within Lightdash components to match your application’s design.

Supported style overrides

styles?: {
  fontFamily?: string;       // Sets all fonts within the component
  backgroundColor?: string;  // Sets the background color or 'transparent'
}
Both properties accept normal CSS values and are set on a styles object passed to any component.

Font family

Sets the font family for all text within the embedded content. Font sizes and other properties are preserved.
<Lightdash.Dashboard
  instanceUrl={lightdashUrl}
  token={lightdashToken}
  styles={{
    fontFamily: 'Inter, sans-serif',
  }}
/>
Some charts and components set font-family explicitly, so the fontFamily style is applied with higher specificity to override these.

Background color

Sets the background for the embedded content. Can be any color value or 'transparent'.
<Lightdash.Dashboard
  instanceUrl={lightdashUrl}
  token={lightdashToken}
  styles={{
    backgroundColor: 'transparent',
  }}
/>

Complete example

<Lightdash.Dashboard
  instanceUrl={lightdashUrl}
  token={lightdashToken}
  styles={{
    backgroundColor: '#f5f5f5',
    fontFamily: 'Helvetica, Arial, sans-serif',
  }}
/>

Filtering data

Filters can be passed to <Lightdash.Dashboard/> to filter dimensions by values. Filters are applied as AND operations, each further restricting results.
Filtering is only available for Dashboard components. Chart and Explore components do not support the filters prop.

Filter structure

type SdkFilter = {
  model: string;             // The model the dimension is part of
  field: string;             // The name of the dimension to filter by
  operator: FilterOperator;  // The filter operator (enum)
  value: unknown | unknown[]; // The value(s) to filter against
};

Basic example

<Lightdash.Dashboard
  instanceUrl={lightdashUrl}
  token={lightdashToken}
  filters={[
    {
      model: 'dbt_users',
      field: 'browser',
      operator: FilterOperator.INCLUDE,
      value: ['chrome', 'safari'],
    },
  ]}
/>

Multiple filters

Filters are applied as AND operations:
<Lightdash.Dashboard
  instanceUrl={lightdashUrl}
  token={lightdashToken}
  filters={[
    {
      model: 'dbt_users',
      field: 'created_date_week',
      operator: FilterOperator.IN_BETWEEN,
      value: ['2024-08', '2024-10'],
    },
    {
      model: 'dbt_users',
      field: 'browser',
      operator: FilterOperator.INCLUDE,
      value: ['chrome', 'safari'],
    },
    {
      model: 'orders',
      field: 'status',
      operator: FilterOperator.EQUALS,
      value: 'completed',
    },
  ]}
/>

FilterOperator enum

Import FilterOperator from the SDK:
import Lightdash, { FilterOperator } from '@lightdash/sdk';
Available operators:
OperatorDescriptionValue Type
FilterOperator.IS_NULLField is nulln/a
FilterOperator.NOT_NULLField is not nulln/a
FilterOperator.EQUALSField equals valuesingle value
FilterOperator.NOT_EQUALSField does not equal valuesingle value
FilterOperator.STARTS_WITHField starts with valuesingle value
FilterOperator.ENDS_WITHField ends with valuesingle value
FilterOperator.INCLUDEField includes any of valuesarray
FilterOperator.NOT_INCLUDEField does not include valuesarray
FilterOperator.LESS_THANField is less than valuesingle value
FilterOperator.LESS_THAN_OR_EQUALField is ≤ valuesingle value
FilterOperator.GREATER_THANField is greater than valuesingle value
FilterOperator.GREATER_THAN_OR_EQUALField is ≥ valuesingle value
FilterOperator.IN_THE_PASTDate in the past N unitssingle value
FilterOperator.NOT_IN_THE_PASTDate not in past N unitssingle value
FilterOperator.IN_THE_NEXTDate in the next N unitssingle value
FilterOperator.IN_THE_CURRENTDate in current periodsingle value
FilterOperator.NOT_IN_THE_CURRENTDate not in current periodsingle value
FilterOperator.IN_BETWEENField between two valuesarray with 2 values
FilterOperator.NOT_IN_BETWEENField not between valuesarray with 2 values

Available fields

Only fields that are available for filtering can be filtered. These are specified in the JWT token passed to the SDK.
To generate tokens with filterable fields, configure your embed in the Lightdash UI or include the appropriate fields in your JWT token structure.

Localization

The Lightdash SDK supports multilingual translation using standard i18n translation objects. To display a translated Lightdash dashboard, pass a correctly formatted translation object to the SDK.
  • Translation maps – The Lightdash CLI can generate translation maps when downloading content as code
  • Runtime translation management – Use a translation library like i18next
  • Translation production tools – Tools like Locize help manage translations efficiently

Video overview

Translation maps

The Lightdash CLI can produce translation maps for dashboards and charts. To include translation maps when downloading content, add the --language-map flag:
lightdash download --language-map
Alongside each downloaded dashboard and chart, there will be a <file name>.language.map.yml file containing translatable strings. Example translation map:
dashboard:
  sdk-dash:
    name: SDK dashboard demo
    description: "A dashboard demonstrating SDK features"
    tiles:
      - type: markdown
        properties:
          title: SDK demo dashboard
          content: >-
            This dashboard contains various tile types for showing SDK
            features.
      - type: saved_chart
        properties:
          title: "How do payment methods vary across different amount ranges?"
These translation maps can be imported into tools like Locize to begin translation.

Runtime translation

At runtime, pass a translation object to the SDK’s contentOverrides prop. We suggest using i18Next to load translations:
import i18n from 'i18next';

<Lightdash.Dashboard
  instanceUrl={lightdashUrl}
  token={lightdashToken}
  contentOverrides={i18n.getResourceBundle(
    i18n.language,      // Specify language
    'demo-dashboard',   // Specify namespace
  )}
/>

Setting up i18Next with Locize

import i18next from 'i18next';
import { initReactI18next } from 'react-i18next';
import Locize from 'i18next-locize-backend';

i18next
  .use(Locize)  // Add Locize backend
  .use(initReactI18next)  // Bind react-i18next
  .init({
    // Locize configuration
    backend: {
      projectId: 'your-locize-project-id',
      apiKey: 'your-api-key',
      referenceLng: 'en',
    },
    lng: 'en',
    fallbackLng: 'en',
    interpolation: {
      escapeValue: false,
    },
  });

What can be translated

Can be translated (UI strings specified in Lightdash):
  • Dashboard names and descriptions
  • Tile titles
  • Chart names
  • Axis labels
  • Series names
  • Markdown content
Cannot be translated (data from your warehouse):
  • String values in charts
  • Dimension values
  • Metric names from database
  • Raw data in tables
Strings originating from your data warehouse cannot be translated by the SDK. They are presented as they exist in your database.

Complete example

Here’s a full example integrating everything:

Backend (Express + Node.js)

// server.js
import express from 'express';
import jwt from 'jsonwebtoken';
import cors from 'cors';

const app = express();
app.use(cors());

app.get('/api/dashboard-token', authenticateUser, async (req, res) => {
  const user = await getUserFromDatabase(req.user.id);

  const token = jwt.sign({
    content: {
      type: 'dashboard',
      dashboardUuid: 'abc-123-def-456',
      dashboardFiltersInteractivity: { enabled: 'all' },
      parameterInteractivity: { enabled: true },
      canExportCsv: true,
      canExportImages: true,
      canExplore: true,
      canViewUnderlyingData: true,
    },
    userAttributes: {
      tenant_id: user.tenantId,
      region: user.region,
    },
    user: {
      externalId: user.id,
      email: user.email,
    },
  }, process.env.LIGHTDASH_EMBED_SECRET, { expiresIn: '2h' });

  res.json({ token, projectUuid: process.env.LIGHTDASH_PROJECT_UUID });
});

app.listen(3000);

Frontend (React)

// Dashboard.tsx
import { useState, useEffect } from 'react';
import Lightdash, { FilterOperator } from '@lightdash/sdk';

export function EmbeddedDashboard() {
  const [token, setToken] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('/api/dashboard-token')
      .then(res => res.json())
      .then(data => {
        setToken(data.token);
        setLoading(false);
      })
      .catch(err => {
        console.error('Failed to load token:', err);
        setLoading(false);
      });
  }, []);

  if (loading) return <div>Loading analytics...</div>;
  if (!token) return <div>Failed to load dashboard</div>;

  return (
    <div style={{ height: '100vh', width: '100%' }}>
      <Lightdash.Dashboard
        instanceUrl="https://app.lightdash.cloud"
        token={token}
        filters={[
          {
            model: 'orders',
            field: 'status',
            operator: FilterOperator.EQUALS,
            value: 'completed',
          },
        ]}
        styles={{
          backgroundColor: 'transparent',
          fontFamily: 'Inter, -apple-system, sans-serif',
        }}
        onExplore={({ chart }) => {
          console.log('User exploring:', chart.name);
          // Track analytics event
        }}
      />
    </div>
  );
}

See also