> ## Documentation Index
> Fetch the complete documentation index at: https://lightdash-mintlify-ca973f84.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Embedding with React SDK

> Reference documentation for the Lightdash React SDK for seamless embedding in React applications

## 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](/references/embedding).

## 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.

```bash theme={null}
LIGHTDASH_CORS_ENABLED=true
LIGHTDASH_CORS_ALLOWED_DOMAINS=https://domain-where-you-are-going-to-use-the-sdk.com
```

<Info>
  **Why CORS is needed**

  Enabling 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.
</Info>

<Warning>
  CORS is **only required for the React SDK**. iframe embedding does not require CORS configuration.
</Warning>

## Installing the Lightdash SDK

In your frontend project, use your preferred package manager to install the SDK.

```bash theme={null}
npm install @lightdash/sdk
# or
pnpm add @lightdash/sdk
# or
yarn add @lightdash/sdk
```

<Info>
  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.
</Info>

### Import CSS styles

The Lightdash SDK requires CSS styles to render components correctly. Import the SDK's CSS file as the **first import** in your React application's entry point:

```tsx theme={null}
import "@lightdash/sdk/sdk.css";

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
```

<Warning>
  The CSS import must be the first import in your entry file to ensure Lightdash styles load before other styles and avoid conflicts.
</Warning>

## 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

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

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

#### Basic usage

```tsx theme={null}
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:

```tsx theme={null}
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](#filtering-data) for complete filter documentation.

#### With styling

```tsx theme={null}
<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:

```tsx theme={null}
<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

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

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

<Info>
  Unlike Dashboard, Chart does not support `filters` or `onExplore` props since charts are read-only and cannot navigate to explore.
</Info>

#### Basic usage

```tsx theme={null}
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

```tsx theme={null}
<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 with `type: 'chart'`:

```javascript theme={null}
// 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](/guides/embedding/charts) for details.

### Lightdash.Explore

Embed interactive data exploration interface with full query builder capabilities.

#### Props

```typescript theme={null}
type ExploreProps = {
  // Required
  instanceUrl: string;              // Your Lightdash instance URL
  token: string | Promise<string>;  // JWT 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

```tsx theme={null}
import Lightdash from '@lightdash/sdk';

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

#### With styling

```tsx theme={null}
<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:

```javascript theme={null}
// 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 JWTs generated server-side. Here's a complete example:

### Backend API endpoint

```typescript theme={null}
// 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

```tsx theme={null}
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}
    />
  );
}
```

<Warning>
  To ensure security, JWT 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.
</Warning>

## Applying styles

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

### Supported style overrides

```typescript theme={null}
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.

```typescript theme={null}
<Lightdash.Dashboard
  instanceUrl={lightdashUrl}
  token={lightdashToken}
  styles={{
    fontFamily: 'Inter, sans-serif',
  }}
/>
```

<Info>
  Some charts and components set `font-family` explicitly, so the `fontFamily` style is applied with higher specificity to override these.
</Info>

### Background color

Sets the background for the embedded content. Can be any color value or `'transparent'`.

```typescript theme={null}
<Lightdash.Dashboard
  instanceUrl={lightdashUrl}
  token={lightdashToken}
  styles={{
    backgroundColor: 'transparent',
  }}
/>
```

### Complete example

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

## Color palettes

You can customize the appearance of embedded dashboards using color palettes. Define multiple color palettes in your organization settings, then apply them to embedded dashboards using the `paletteUuid` prop.

For more on customizing appearance, see [customizing the appearance of your project](/references/workspace/customizing-the-appearance-of-your-project).

### Setting up color palettes

1. Go to **Organization settings > Appearance** in Lightdash
2. Define one or more color palettes
3. Copy the palette UUID for the palette you want to use (or fetch from API `GET /api/v1/org/color-palettes`)

### Applying a palette

Pass the `paletteUuid` prop to the `Lightdash.Dashboard` component:

```tsx theme={null}
<Lightdash.Dashboard
  instanceUrl="https://app.lightdash.cloud"
  token={token}
  paletteUuid="your-palette-uuid"
/>
```

## Filtering data

Filters can be passed to `<Lightdash.Dashboard/>` to filter dimensions by values. Filters are applied as AND operations, each further restricting results.

<Info>
  Filtering is **only available for Dashboard** components. Chart and Explore components do not support the `filters` prop.
</Info>

<Warning>
  For the `filters` prop to work, your JWT must have `dashboardFiltersInteractivity` set to `enabled: 'all'`. Without this configuration, filters will not be applied.
</Warning>

### Filter structure

```typescript theme={null}
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

```javascript theme={null}
<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:

```javascript theme={null}
<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:

```typescript theme={null}
import Lightdash, { FilterOperator } from '@lightdash/sdk';
```

Available operators:

| Operator                               | Description                   | Value Type          |
| -------------------------------------- | ----------------------------- | ------------------- |
| `FilterOperator.IS_NULL`               | Field is null                 | n/a                 |
| `FilterOperator.NOT_NULL`              | Field is not null             | n/a                 |
| `FilterOperator.EQUALS`                | Field equals value            | single value        |
| `FilterOperator.NOT_EQUALS`            | Field does not equal value    | single value        |
| `FilterOperator.STARTS_WITH`           | Field starts with value       | single value        |
| `FilterOperator.ENDS_WITH`             | Field ends with value         | single value        |
| `FilterOperator.INCLUDE`               | Field includes any of values  | array               |
| `FilterOperator.NOT_INCLUDE`           | Field does not include values | array               |
| `FilterOperator.LESS_THAN`             | Field is less than value      | single value        |
| `FilterOperator.LESS_THAN_OR_EQUAL`    | Field is ≤ value              | single value        |
| `FilterOperator.GREATER_THAN`          | Field is greater than value   | single value        |
| `FilterOperator.GREATER_THAN_OR_EQUAL` | Field is ≥ value              | single value        |
| `FilterOperator.IN_THE_PAST`           | Date in the past N units      | single value        |
| `FilterOperator.NOT_IN_THE_PAST`       | Date not in past N units      | single value        |
| `FilterOperator.IN_THE_NEXT`           | Date in the next N units      | single value        |
| `FilterOperator.IN_THE_CURRENT`        | Date in current period        | single value        |
| `FilterOperator.NOT_IN_THE_CURRENT`    | Date not in current period    | single value        |
| `FilterOperator.IN_BETWEEN`            | Field between two values      | array with 2 values |
| `FilterOperator.NOT_IN_BETWEEN`        | Field not between values      | array with 2 values |

### Available fields

Only fields that are available for filtering can be filtered. These are specified in the JWT passed to the SDK.

<Info>
  To generate tokens with filterable fields, configure your embed in the Lightdash UI or include the appropriate fields in your JWT structure.
</Info>

## 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.

### Recommended tools

* **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

<iframe width="640" height="360" src="https://www.loom.com/embed/d664260545624198b9d4074401c6fb6f?sid=292691a9-5cd9-4504-80b3-bcd6cd874558" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen />

### 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:

```bash theme={null}
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:**

```yaml theme={null}
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:

```typescript theme={null}
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

```typescript theme={null}
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

<Info>
  Strings originating from your data warehouse cannot be translated by the SDK. They are presented as they exist in your database.
</Info>

## Complete example

Here's a full example integrating everything:

### Backend (Express + Node.js)

```javascript theme={null}
// 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)

```tsx theme={null}
// 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

<CardGroup cols={2}>
  <Card title="Embedding quickstart" icon="rocket" href="/guides/embedding/how-to-embed-content">
    Get started with embedding in 5 minutes
  </Card>

  <Card title="Embedding API reference" icon="book" href="/references/embedding">
    Complete JWT structure and configuration
  </Card>

  <Card title="iframe embedding reference" icon="code" href="/references/iframe-embedding">
    Complete iframe URL patterns and HTML embedding
  </Card>

  <Card title="Embedding dashboards" icon="grid-2" href="/guides/embedding/dashboards">
    Complete guide to dashboard embedding
  </Card>

  <Card title="Embedding charts" icon="chart-line" href="/guides/embedding/charts">
    Complete guide to chart embedding
  </Card>

  <Card title="User attributes" icon="shield-check" href="/references/workspace/user-attributes">
    Implement row-level security with user attributes
  </Card>
</CardGroup>
