From 990a4c7ca26b35eb217c8fb986d1bb8f55d80ef5 Mon Sep 17 00:00:00 2001 From: Steve Gardner Date: Fri, 5 Dec 2025 18:49:36 +0200 Subject: [PATCH] feat: update embedding docs --- docs.json | 17 +- guides/embedding/charts.mdx | 344 +++++++++ guides/embedding/dashboards.mdx | 458 +++++++++++ guides/how-to-embed-content.mdx | 164 ++-- images/guides/embed-add-chart.png | Bin 0 -> 61170 bytes images/guides/embed-iframe-interactivity.png | Bin 0 -> 54940 bytes references/embedding.mdx | 701 ++++++++++++++--- references/iframe-embedding.mdx | 568 ++++++++++++++ references/react-sdk.mdx | 767 ++++++++++++++++--- snippets/embedding-availability.mdx | 3 + 10 files changed, 2726 insertions(+), 296 deletions(-) create mode 100644 guides/embedding/charts.mdx create mode 100644 guides/embedding/dashboards.mdx create mode 100644 images/guides/embed-add-chart.png create mode 100644 images/guides/embed-iframe-interactivity.png create mode 100644 references/iframe-embedding.mdx create mode 100644 snippets/embedding-availability.mdx diff --git a/docs.json b/docs.json index d5aa33a8..b1a156f1 100644 --- a/docs.json +++ b/docs.json @@ -190,8 +190,21 @@ "group": "Embedding", "pages": [ "guides/how-to-embed-content", - "references/embedding", - "references/react-sdk" + { + "group": "Embedding guides", + "pages": [ + "guides/embedding/dashboards", + "guides/embedding/charts" + ] + }, + { + "group": "Reference", + "pages": [ + "references/embedding", + "references/iframe-embedding", + "references/react-sdk" + ] + } ] }, { diff --git a/guides/embedding/charts.mdx b/guides/embedding/charts.mdx new file mode 100644 index 00000000..2c48784e --- /dev/null +++ b/guides/embedding/charts.mdx @@ -0,0 +1,344 @@ +--- +title: "How to Embed Charts" +sidebarTitle: "Charts" +description: "Learn how to embed individual Lightdash charts with minimal UI for focused, single-metric displays" +--- + +import EmbedAvailability from 'snippets/embedding-availability.mdx' + + + +## Overview + +Chart embedding allows you to display single saved charts from Lightdash in your application with a minimal, focused interface. Unlike dashboard embedding, chart embeds are scoped to a specific chart and provide a clean, distraction-free view of a single visualization. + + +Chart embedding is **only available via the React SDK**. iframe embedding for charts is not currently supported. + + +### When to use chart embedding + +- **Single KPI displays**: Show one key metric or visualization +- **Embedded widgets**: Add analytics widgets to application pages +- **Marketing pages**: Display metrics on public-facing pages +- **Minimal UI requirements**: When you need a clean, focused display +- **Scoped access**: Grant access to specific charts only, not entire dashboards + +### Key differences from dashboard embedding + +| Feature | Dashboard Embedding | Chart Embedding | +|---------|-------------------|-----------------| +| **Embedding method** | iframe or React SDK | React SDK only | +| **Content** | Multiple tiles, tabs | Single chart only | +| **Filters** | Interactive dashboard filters | No filters (pre-configured) | +| **JWT scope** | Dashboard UUID | Scoped to chart UUID | +| **UI** | Full dashboard interface | Minimal chart view | +| **Explore** | Can navigate to explore | Cannot access explore | + +### Available features + +Chart embedding supports: +- All chart types (bar, line, pie, table, big number, etc.) +- Parameterized charts with pre-set values +- Export to CSV (if enabled) +- Export to PNG/images (if enabled) +- View underlying data (if enabled) + + +Chart embeds are **read-only**. Users cannot modify the chart configuration, apply filters, or access the underlying data model. + + +## Setup + +### Configure allowed charts + +Add the charts you want to embed to your project's embed settings. Navigate to **Settings → Embed** and add specific charts to the allowed list. + + + Add allowed charts + + +## Embedding with React SDK + +Chart embedding requires the Lightdash React SDK for seamless integration in your React application. + + +See the [React SDK reference](/references/react-sdk) for installation, setup, and complete configuration options. + + +### Basic usage + +```tsx +import Lightdash from '@lightdash/sdk'; + +function MyChart() { + return ( + + ); +} +``` + +### Component props + +```typescript +type ChartProps = { + instanceUrl: string; // Required: Your Lightdash instance URL + id: string; // Required: Chart UUID (savedQueryUuid) + token: string | Promise; // Required: JWT token + styles?: { + backgroundColor?: string; // Chart background color or 'transparent' + fontFamily?: string; // Font family for text + }; + contentOverrides?: LanguageMap; // Translation/localization overrides +}; +``` + + +Unlike the Dashboard component, Chart does not support `filters` or `onExplore` props since charts are read-only and cannot navigate to explore. + + +#### Advanced example with styling + +```tsx +import Lightdash from '@lightdash/sdk'; + + +``` + +## Configuring features + +Control what users can do with your embedded chart by configuring feature options. These options work for both iframe and React SDK embedding methods and are set in the JWT token. + +### Export CSV + +Export CSV allows users to download the raw data behind the chart as a CSV file, useful for further analysis in spreadsheet applications. + +**Configure in JWT token:** + +```javascript +{ + content: { + type: 'chart', + contentId: 'your-chart-uuid', + canExportCsv: true, + } +} +``` + +When enabled, users see a "Download CSV" option in the chart's menu. + +### Export images + +Export images allows users to download the chart visualization as a PNG image file, useful for presentations and reports. + +**Configure in JWT token:** + +```javascript +{ + content: { + type: 'chart', + contentId: 'your-chart-uuid', + canExportImages: true, + } +} +``` + +### View underlying data + +View underlying data shows users the raw data table behind the chart, making it easy to inspect the actual values and records that create the visualization. + +**Configure in JWT token:** + +```javascript +{ + content: { + type: 'chart', + contentId: 'your-chart-uuid', + canViewUnderlyingData: true, + } +} +``` + +### Complete configuration example + +```javascript +import jwt from 'jsonwebtoken'; + +const token = jwt.sign({ + content: { + type: 'chart', + projectUuid: 'your-project-uuid', + contentId: 'your-chart-uuid', + + // Export capabilities + canExportCsv: true, + canExportImages: true, + canViewUnderlyingData: true, + }, + + // User information (for analytics) + user: { + externalId: 'user-123', + email: 'user@example.com', + }, +}, LIGHTDASH_EMBED_SECRET, { expiresIn: '24h' }); +``` + +## Limitations + +Chart embeds have the following limitations compared to dashboard embeds: + +### Cannot modify charts +Charts are always read-only. Users cannot: +- Change dimensions or metrics +- Apply filters +- Modify chart configuration +- Change visualization type + +### No filter support +Charts use their saved filter configuration. You cannot: +- Add interactive filters +- Apply filters programmatically via SDK +- Change filter values at runtime + +### No explore access +Users cannot: +- Navigate to the explore view +- Access the underlying data model +- Run custom queries +- View or edit SQL + +### Scoped permissions +The JWT token is scoped to the specific chart UUID in `contentId`. Users cannot: +- Access other charts not in the token +- View project configuration +- Access explore metadata + + +If you need filter interactivity or exploration capabilities, consider using [dashboard embedding](/guides/embedding/dashboards) instead or contact us with your use-case. + + +## Use cases and examples + +### Single KPI widget + +Display a key performance indicator in your application dashboard: + +```tsx +
+

Monthly Revenue

+ +
+``` + +### Embedded metric in marketing page + +Show a public-facing metric on your website: + +```html +
+
+

Active Users

+ +
+
+``` + +### Parameterized chart + +Display a chart with pre-set parameter values: + +```javascript +// Chart is saved with a parameter for "region" +// Pass parameter value in the chart configuration +const token = jwt.sign({ + content: { + type: 'chart', + contentId: 'sales-by-region-uuid', + canExportCsv: true, + }, +}, LIGHTDASH_EMBED_SECRET, { expiresIn: '1h' }); +``` + + +Parameter values are set when the chart is saved. Chart embeds display the chart with its saved parameter configuration. + + +## Advanced features + +### User metadata for analytics + +Pass user information to track who's viewing your embedded charts. + +```javascript +{ + user: { + externalId: 'user-123', // Your internal user ID + email: 'user@example.com', // User's email + } +} +``` + +This metadata appears in [query tags](/references/usage-analytics#query-tags) in Lightdash usage analytics. + +### Custom styling (SDK only) + +Apply custom styling to match your application's design. + +```tsx + +``` + +### Localization (SDK only) + +Translate embedded charts using the `contentOverrides` prop. See [React SDK localization](/references/react-sdk#localization) for details. + +## Next steps + + + + Embed multiple charts with filters and interactivity + + + + Complete iframe URL patterns and HTML embedding + + + + Complete JWT token structure documentation + + + + Complete SDK component documentation + + diff --git a/guides/embedding/dashboards.mdx b/guides/embedding/dashboards.mdx new file mode 100644 index 00000000..c0691802 --- /dev/null +++ b/guides/embedding/dashboards.mdx @@ -0,0 +1,458 @@ +--- +title: "How to Embed Dashboards" +sidebarTitle: "Dashboards" +description: "Complete guide to embedding Lightdash dashboards with full configuration options for both iframe and React SDK methods" +--- + +import EmbedAvailability from '/snippets/embedding-availability.mdx'; + + + +## Overview + +Dashboard embedding allows you to display full Lightdash dashboards in your application with multiple visualizations, filters, and interactive features. This is ideal when you want to provide comprehensive analytics views to your users. + +### When to use dashboard embedding + +- **Executive dashboards**: Display multiple KPIs and metrics in admin panels +- **Customer-facing analytics**: Provide analytics portals for SaaS customers +- **Embedded reporting**: Integrate comprehensive data views into your workflows +- **Multi-chart views**: Show related visualizations together with shared filters + +### Key features + +- Multiple chart tiles and markdown content +- Dashboard-level filters (interactive if enabled) +- Multiple tabs for organizing content +- Parameters support +- Export options (CSV, images, PDF) +- Date zoom for time-series charts +- "Explore from here" to navigate to query builder +- View underlying data for any visualization + +## Setup + +### Configure allowed dashboards + +Only dashboards explicitly added to the "allowed dashboards" list can be embedded. Navigate to **Settings → Embed** and add your dashboard. + + + Add allowed dashboards + + +Alternatively, toggle "Allow all dashboards" to enable embedding for any dashboard in your project. + +## Configuring interactivity + +Control what users can do with your embedded dashboard by configuring interactivity options. These options work for both iframe and React SDK embedding methods and are set in the JWT token. + +While the SDK options are configured via React props, iframe options are configured in the admin UI where you setup the embedding: + + + Configure iframe interactivity + + +### Dashboard filters + +Dashboard filters allow users to slice and filter data across all charts in the dashboard. You can control whether users can interact with these filters, which filters they can modify, and whether the filter UI is visible. + +**Configure in JWT token:** + +```javascript +{ + content: { + type: 'dashboard', + dashboardUuid: 'your-dashboard-uuid', + dashboardFiltersInteractivity: { + enabled: 'all', // 'all', 'some', or 'none' + }, + } +} +``` + +**Options:** +- `'all'` - All dashboard filters are interactive and visible +- `'some'` - Only specified filters are interactive (use `allowedFilters` array) +- `'none'` - Filters are applied but not visible or editable + +**Allow specific filters only:** + +```javascript +{ + content: { + type: 'dashboard', + dashboardUuid: 'your-dashboard-uuid', + dashboardFiltersInteractivity: { + enabled: 'some', + allowedFilters: ['filter-uuid-1', 'filter-uuid-2'], + }, + } +} +``` + +**Hide filter UI:** + +```javascript +{ + dashboardFiltersInteractivity: { + enabled: 'all', + hidden: true, // Filters work but UI is hidden + } +} +``` + +### Parameters + +Parameters are dynamic values that can be referenced in your queries and filters. When enabled, users can modify parameter values to change what data is displayed across the dashboard. + +**Configure in JWT token:** + +```javascript +{ + content: { + type: 'dashboard', + dashboardUuid: 'your-dashboard-uuid', + parameterInteractivity: { + enabled: true, + }, + } +} +``` + +### Export options + +Allow users to export data and visualizations from the embedded dashboard. You can control which export formats are available. + +**Configure in JWT token:** + +```javascript +{ + content: { + type: 'dashboard', + dashboardUuid: 'your-dashboard-uuid', + canExportCsv: true, // Export chart data as CSV + canExportImages: true, // Export charts as PNG/images + canExportPagePdf: true, // Export entire dashboard page as PDF + } +} +``` + +**Available export options:** +- **CSV** - Download raw data from individual charts +- **Images** - Export charts as PNG images +- **PDF** - Export the entire dashboard page as a PDF document + +### Date zoom + +Date zoom allows users to dynamically change the time granularity of time-series visualizations (e.g., view by day, week, month, quarter, year) without modifying the underlying query. + +**Configure in JWT token:** + +```javascript +{ + content: { + type: 'dashboard', + dashboardUuid: 'your-dashboard-uuid', + canDateZoom: true, + } +} +``` + +### Explore from here + +"Explore from here" allows users to navigate from a dashboard chart into the full query builder interface, where they can modify dimensions, metrics, filters, and create ad-hoc analyses starting from the chart's configuration. + +**Configure in JWT token:** + +```javascript +{ + content: { + type: 'dashboard', + dashboardUuid: 'your-dashboard-uuid', + canExplore: true, + } +} +``` + +When enabled, users see an "Explore from here" option on chart tiles that opens the explore interface. + +### View underlying data + +View underlying data shows users the raw data table behind any visualization, making it easy to inspect the actual values and records that create the chart. + +**Configure in JWT token:** + +```javascript +{ + content: { + type: 'dashboard', + dashboardUuid: 'your-dashboard-uuid', + canViewUnderlyingData: true, + } +} +``` + +### Complete configuration example + +```javascript +import jwt from 'jsonwebtoken'; + +const token = jwt.sign({ + content: { + type: 'dashboard', + projectUuid: 'your-project-uuid', + dashboardUuid: 'your-dashboard-uuid', + + // Filter controls + dashboardFiltersInteractivity: { + enabled: 'all', + }, + + // Parameter controls + parameterInteractivity: { + enabled: true, + }, + + // Export capabilities + canExportCsv: true, + canExportImages: true, + canExportPagePdf: true, + + // Interactive features + canDateZoom: true, + canExplore: true, + canViewUnderlyingData: true, + }, + + // User information (for analytics) + user: { + externalId: 'user-123', + email: 'user@example.com', + }, + + // User attributes (for row-level filtering) + userAttributes: { + tenant_id: 'tenant-abc', + }, +}, LIGHTDASH_EMBED_SECRET, { expiresIn: '1h' }); +``` + +## iframe embedding + +iframe embedding is the simplest way to embed dashboards. No special libraries or dependencies required. + +### URL structure + +``` +https://your-instance.lightdash.cloud/embed/{projectUuid}/dashboard/{dashboardUuid}#{jwtToken} +``` + +Or using dashboard slug: + +``` +https://your-instance.lightdash.cloud/embed/{projectUuid}/dashboard/{dashboardSlug}#{jwtToken} +``` + +The JWT token is passed in the URL hash fragment for security. + +### Generate JWT token + + + +```javascript Node.js +import jwt from 'jsonwebtoken'; + +const LIGHTDASH_EMBED_SECRET = process.env.LIGHTDASH_EMBED_SECRET; +const projectUuid = 'your-project-uuid'; + +const token = jwt.sign({ + content: { + type: 'dashboard', + dashboardUuid: 'your-dashboard-uuid', + }, +}, LIGHTDASH_EMBED_SECRET, { expiresIn: '1h' }); + +const embedUrl = `https://app.lightdash.cloud/embed/${projectUuid}/dashboard/your-dashboard-uuid#${token}`; +``` + +```python Python +import jwt +import datetime + +LIGHTDASH_EMBED_SECRET = os.getenv('LIGHTDASH_EMBED_SECRET') +project_uuid = 'your-project-uuid' + +payload = { + 'content': { + 'type': 'dashboard', + 'dashboardUuid': 'your-dashboard-uuid', + }, + 'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1) +} + +token = jwt.encode(payload, LIGHTDASH_EMBED_SECRET, algorithm='HS256') +embed_url = f"https://app.lightdash.cloud/embed/{project_uuid}/dashboard/your-dashboard-uuid#{token}" +``` + +```ruby Ruby +require 'jwt' + +lightdash_embed_secret = ENV['LIGHTDASH_EMBED_SECRET'] +project_uuid = 'your-project-uuid' + +payload = { + content: { + type: 'dashboard', + dashboardUuid: 'your-dashboard-uuid' + }, + exp: Time.now.to_i + 3600 +} + +token = JWT.encode(payload, lightdash_embed_secret, 'HS256') +embed_url = "https://app.lightdash.cloud/embed/#{project_uuid}/dashboard/your-dashboard-uuid##{token}" +``` + + + +### Embed in HTML + +```html + +``` + +## React SDK + +The React SDK provides seamless integration with additional features like programmatic filters, callbacks, and styling. + + +See the [React SDK reference](/references/react-sdk) for installation, setup, and complete configuration options. + + +### Basic usage + +```tsx +import Lightdash from '@lightdash/sdk'; + +function MyDashboard() { + return ( + + ); +} +``` + +### Component props + +```typescript +type DashboardProps = { + instanceUrl: string; // Required: Your Lightdash instance URL + token: string | Promise; // Required: JWT token + styles?: { + backgroundColor?: string; // Dashboard background color or 'transparent' + fontFamily?: string; // Font family for text + }; + filters?: SdkFilter[]; // Apply filters programmatically + contentOverrides?: LanguageMap; // Translation/localization overrides + onExplore?: (options: { chart: SavedChart }) => void; // Callback when user navigates to explore +}; +``` + +### Advanced example with filters + +```tsx +import Lightdash, { FilterOperator } from '@lightdash/sdk'; + + { + console.log('User exploring chart:', chart.name); + }} +/> +``` + +## Advanced features + +### User metadata for analytics + +Pass user information to track who's viewing your embedded dashboards. + +```javascript +{ + user: { + externalId: 'user-123', // Your internal user ID + email: 'user@example.com', // User's email + } +} +``` + +This metadata appears in [query tags](/references/usage-analytics#query-tags) in Lightdash usage analytics. + +### Custom styling (SDK only) + +Apply custom styling to match your application's design. + +```tsx + +``` + +### Localization (SDK only) + +Translate embedded dashboards using the `contentOverrides` prop. See [React SDK localization](/references/react-sdk#localization) for details. + +### Row-level security with user attributes + +Filter data based on the viewing user's properties. See the [user attributes reference](/references/user-attributes) for complete details. + +## Next steps + + + + Embed individual charts for focused displays + + + + Show different data to different users + + + + Complete iframe URL patterns and HTML embedding + + + + Complete JWT token structure documentation + + diff --git a/guides/how-to-embed-content.mdx b/guides/how-to-embed-content.mdx index 59162a52..56de7bff 100644 --- a/guides/how-to-embed-content.mdx +++ b/guides/how-to-embed-content.mdx @@ -1,18 +1,58 @@ --- title: "How to embed content" sidebarTitle: Embedding quickstart -description: Lightdash allows you to embed your dashboards using expirable URLs and tokens (embed URLs from now on). This is a great way to enable self-serve analytics in your own application and platform by leveraging the insights you've got in Lightdash and making them available to your own users. +description: Lightdash allows you to embed your content using expirable URLs and tokens. This is a great way to enable self-serve analytics in your own application and platform by leveraging the insights you've got in Lightdash and making them available to your own users. --- +import EmbedAvailability from '/snippets/embedding-availability.mdx'; - + + +## What can you embed? + +Lightdash supports embedding two types of content, each designed for different use cases: + +### Dashboards + +Embed complete dashboards with multiple visualizations, filters, and tabs. Perfect for providing comprehensive analytics views in your application. + +**Use cases:** +- Executive dashboards in admin panels +- Customer-facing analytics portals +- Embedded reporting for SaaS applications + +[Learn more about embedding dashboards →](/guides/embedding/dashboards) + +### Charts + +Embed individual saved charts for focused, single-metric displays. Charts provide a minimal UI for clean integration. -Embedding is available to all Lightdash Cloud users, [get in touch](https://lightdash.typeform.com/to/BujU5wg5) to have this feature enabled in your account. +**Use cases:** +- Single KPI widgets in applications +- Embedded metrics in marketing pages +- Focused analytics in workflows + + +Chart embedding requires the React SDK. iframe embedding is only available for dashboards. -## Quick start to embed dashboards +[Learn more about embedding charts →](/guides/embedding/charts) + +## How can you embed content? + +Lightdash offers two embedding methods: + +**[iframe embedding](/references/iframe-embedding)**: Embed Lightdash **dashboards** using a simple iframe with a JWT token in the URL. No special integration required. iframe embedding is only available for dashboards, not charts. + +**[React SDK](/references/react-sdk)**: Use the `@lightdash/sdk` package for seamless integration in React applications. The React SDK supports both dashboards and charts with additional features like programmatic filters and callbacks. + +Both methods use the same JWT-based authentication and security model. + +## Quick start: Embed a dashboard + +This quick start will walk you through embedding your first dashboard using an iframe. -### Create an embed secret +### Step 1: Create an embed secret First, you need to generate a secret per project. This secret is like a password that will help you encrypt the URLs so we know the access is valid. @@ -20,109 +60,89 @@ First, you need to generate a secret per project. This secret is like a password - You can regenerate the secret by clicking on the `Generate new secret` button. If you do this, people with an old URL will automatically lose access to any previously shared embed URL. -### Allowed dashboards +### Step 2: Add allowed dashboards -Only selected dashboards can be accessed via embed URLs +Only selected dashboards can be accessed via embed URLs. Add the dashboard you want to embed to the allowed list. +### Step 3: Configure and preview -### Preview - -Under preview you can generate a one-off shareable embed URL for a single dashboard. +Under the "Configure" section, you can: +- Select which dashboard to embed +- Set token expiration time +- Configure interactivity (filters, exports, etc.) +- Add user attributes for row-level security -Click on `preview` to see the embed content and click on `Generate & copy URL` to generate an embed URL for this dashboard +Click on `Preview` to see how the embedded content will look, and click on `Generate & copy URL` to get a one-off embed URL for testing. -### Developer flow and code snippet +### Step 4: Generate tokens programmatically -Although you can generate URLs directly from Lightdash with a long expiration it is recommended to generate your own JWT tokens in your backend with a short expiration using your `secret`to make sure people can't be using embed URLs outside your app. +Although you can generate URLs directly from Lightdash with a long expiration, it is recommended to generate your own JWT tokens in your backend with a short expiration using your `secret` to make sure people can't be using embed URLs outside your app. -To make this easier to integrate, we included some code snippets you can copy and use in your app to generate a valid embed URL +Lightdash provides code snippets you can copy and use in your app to generate valid embed URLs: - -For more information on embed settings, see the [embedding reference doc](/references/embedding) - +## Next steps -## Do I need a Lightdash account to be able to view embedded content? + + + Complete guide to dashboard embedding with all configuration options + -No, embedded Lightdash content is available to view by anyone (not just folks with a Lightdash login). + + Learn how to embed individual charts for focused displays + -So, for example, you could embed a dashboard in your product, and anyone who has access to your product would have access to that dashboard. No need to login to Lightdash. + + Show different data to different users with user attributes + -We make sure that the links are secure and have a set expiry time that you pick. + + URL patterns and HTML embedding details + -## I want to have my embedded dashboard show different values for different users in my app. + + Seamless React integration with advanced features + -Imagine a scenario where I have a dashboard embedded in my application showing an overview of orders. Ideally, when a user looks at this dashboard, they should only see the orders for their shop (not all of the other shops using my application). You can do this with embedded dashboards using user attributes. Here's how to do it: + + Complete JWT token structure and configuration options + + -### Create a user attribute in Lightdash +## Common questions -First, we need to create a [user attribute](/references/user-attributes) in Lightdash that we can use to assign our users to a specific shop. I create an attribute called `shop_id` and I set the default value to `all`. +### Do I need a Lightdash account to view embedded content? - - - - -### Filter the tables used in your dashboard with `sql_filter` - -We need to filter the access to all of the tables we use in our dashboard using this attribute. For example, in my `Order Summary` dashboard, I use the `orders` and the `shops` tables to build all of the charts. So, in these two tables, I'm going to add a [row-level filter](#../references/user-attributes#1-row-filtering-with-sql%5Ffilter) using my `shop_id` attribute, like: - -```yaml -models: - - name: orders - meta: - sql_filter: ${lightdash.attributes.shop_id} = 'all' OR ${TABLE}.shop_id = ${lightdash.attributes.shop_id} -``` +No, embedded Lightdash content is available to view by anyone (not just folks with a Lightdash login). -### Add the user attribute to your dashboard embed +So, for example, you could embed a dashboard in your product, and anyone who has access to your product would have access to that dashboard. No need to login to Lightdash. -Now that we have our user attribute set up and filtering our data properly, we want to head back to our dashboard embedding configuration. +We make sure that the links are secure and have a set expiry time that you pick. -There are two ways to use user attributes in your embedded dashboard: +### How does security work? -**Option 1: assign a constant value for your attribute** +Embedded content is secured using JWT (JSON Web Tokens) that you sign with your embed secret. The token includes: -You can assign your dashboard a single, constant value for your attribute by adding it in the `user attributes` section of your embedded dashboard setup. +- What content to display (dashboard or chart) +- Expiration time +- User attributes for row-level filtering +- Permissions for interactivity (filters, exports, etc.) -For example, if I wanted the embed link to only show data for `shop_id = Thyme to Shine`, then I would add a user attribute `shop_id` with the value `Thyme to Shine`. +Tokens are short-lived and should be generated server-side to prevent exposure of your embed secret. - - - +### Can I show different data to different users? -**Option 2: assign a variable value for your attribute** - -You can adjust the value of the user attribute based on a variable coming from your app so, for example, the user attribute for `shop_id` in the Lightdash embedded dashboard would change depending on which `shop_id` the user belonged to in my app. - -To do this, I would pass Lightdash an external value for `shop_id` in the embed code snippet. This could look something like: - -```yaml -import jwt from 'jsonwebtoken'; -const LIGHTDASH_EMBED_SECRET = 'secret'; // replace with your secret -const projectUuid = '21eef0b9-5bae-40f3-851e-9554588e71a6'; -const userShopId = await getUserShopIdFromDatabase(); -const data = { - content: { - type: 'dashboard', - dashboardUuid: 'a392ed6d-4c53-4102-89b7-1c57a87df391', - }, - userAttributes: { shop_id: userShopId }, -}; -const token = jwt.sign(data, LIGHTDASH_EMBED_SECRET, { expiresIn: '1 hour' }); -const url = `https://analytics.lightdash.cloud/embed/${projectUuid}/#${token}`; -``` - -And voila! you now have an embedded dashboard that shows different values for different users in your app. +Yes! You can use [user attributes](/references/user-attributes) to implement row-level security in your embedded content. This allows you to filter data based on the viewing user's properties (e.g., tenant ID, region, etc.). diff --git a/images/guides/embed-add-chart.png b/images/guides/embed-add-chart.png new file mode 100644 index 0000000000000000000000000000000000000000..d0565eec299e96000a53962f067eb8ee594c9d42 GIT binary patch literal 61170 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 literal 0 HcmV?d00001 diff --git a/images/guides/embed-iframe-interactivity.png b/images/guides/embed-iframe-interactivity.png new file mode 100644 index 0000000000000000000000000000000000000000..a67027ffa92173b9bc43ecdec8460bdb9b32d296 GIT binary patch literal 54940 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%0Av{m8GGs;UTM6Y6aV1+*Oji6c=7 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
*-FON*H2&xJD(S;f= zU-Q~FS-f%GT2st+Z|gkHgSjU)vEzB)*o^sAuw?7yN*aR#T6Q&viVSwW9PY|_;@@YX z&fa^lEnzX1oxnl2Nm1!^{K0J#7KX6=z_jIfi=kz#o;k)3&#kZTY>U9V-$_xiZ~UGc zaR%hA?qKi7JjZjFYq>K>%{RS|5u16a$!%Z)nbZjhmpqwkux8od+^xf%f53}&(af)&ZZXJ66|-APx$`NzW$q<)uRKX( zgcoxr4C44zCp5*FkirCgo&ac2(QC>1Y}49QdV^gXBphUFkZOXKO;QzDYXSA;o{JWy zB5*8kQ+ot%UBCn5ddMy^Sq8R;3<52o^wC=;q3usBOs-ICX*}Bd!ko0Rr%31AuNqscxHJ|f z3w|j6tz2J$*yDjm#Fb$P7Lyt-5(c>=VcIsN?nOH0_&(izw@%DtH#2B5 z%P-5Rr#AiZQ2aSw@cIi}Hdaz1_?KDhQN>r5T5R?f{d$jZG+3l%V2_^CGy?ze*w+a7|gA6Vv})P;BAN1>L2@n*eT zB97drQfn7BR&lk7iqDLk3e^otF%Fas>~`6naWkj#Tz!|?AQo8Z4@LM@GPCtFMY`fd zsfo+BOK3ZP{;PFaQh8MJ3$e(>afcQip=fN@sPwQnhmk(c{E@ZS9>#VIUurooBJF-- z6u6HCTY`o;HH+Y%Qfii{K{^L-8W{OE<7lp>ZR~4Xh$$@xF9CXF@MN94(H^T&=*d}N z8|9BkCeN!@!8a~1m_-`uSvz%$uO**KHJ@5LpuwLdW_=4qih49%y7r??efvu6-sMRM zLYMac#NK@X)HEFUA|#S7jBt6TRV1#7PI;gF(KHA~-?0X#e44I*E5@MoyUWyfJMwx_ zhNRPavLXJiAn13Jk$*6=c%F4!Z>UrhKS1?%V?5@7X)z#yzuMDEHe*9D#pU*3rl007 zw3+aBtH$4b;;NRdg5i*_IxZXT_SEUGZ}Ky=wIB#wPPWpaMj}Uo)_U1v92@zz8Q-xf zVn6(^n(doA&_T=&22%^C4zrgOF&#Q-s!ZaS6H-DbUe*oU}%k{;-aPdE1Rv$J8b%pBJ{y&cR zc{$1B$$ybu;&3T&l9QK=et%6D{~+dpmUnRfM;m##fNgSsYzX_WUizOlf(EkuY1+TX z{r}OxNmoq2ws0O#WML7B7`a<3Ju4(KD|>tERfOHYKzI5JKrGPwUEByjrLriYS>9Tr;o{O*-d?u85~=vRPZUo8*vUm*$HK0s zaVS2X^<{`ZqZbz8lz@kt`VpC>K+cJVFHuEmWF#S?^zeFabZOXS+%dJ&p;O1-`;-8@ zp#vze@Mv~W+KAFf8Qd287R&qVIf%w&x@;nqDcJ!Q*u6VmTq!9jA>C36h`6{I)Bs*W z!bZ_r51(8q|APVJdu9rJUT!p+ryXE^4*i4ng(bWcyp=Rva?$W+yAL#0D+|9vL4XGl zQmB6&QD9Kurzt6&739_3t9LIm9yvf8{7&oSff5J=c>HV2$*oaCVk!8VZ7zd`c;+A>P3J3n?~`>~LEhGU z%|#5iZ%znbwS(`#Qm5F-!7izzqeC-Fe;{c&4G9WPJB%dGb6c_|QD8y8E7Qvd>5%8v z@!d(+P8`YRs!e+AM%Wodsix66Jq%)#?Dz&swWZKU-i#&G|Onzd6Q z7rC2NXAqOIOTOVd)y*=Lv%RC9sc10x9i8$(Cb2?QrRcS}ulG$O0i+zZRW)593SYJo z?6e}&qQ=K6@b3ddEpQE2H0^XjcLDRss7rML*z;s+P?iW8C&Pbw!%3A25xY z0k#86MGSO-v7{kb`fT+4_q)@Yy**L6t9RE2$mkO4&tbpF<0B!?->t=Il8}=N&u|S1 z7AThHoJoP5VMiZ|J+8E)FF?Mh*kHe9RzztykQ`ImawiBf-$?CtCSpQyW)ea?71Aca zrl7g{19SC}>A-c+?=AVhrEsiJR%pL2D>c7HcSG`OzwrwaDyn`->)CB_(faz?uM9qV zhXp9M+~JGaojDr78BW6a8@FtyDU=}5O3~`VD%Wj3uU~@fWE+O4)POaqIiTck$p)!$C={w85$FG*{JU_p1lSG$| zOJX1VA3H`3hEPMBRv@?`g~OVVLSIlA2aIqeQ=vk4Kg%RNugP+6>CbOuetDCuyrI~f zl+6$h^0$h`^yBcjtmL{~A#vJ7f<0iDfmN`eAIV+hqm4#~Q39U+3+u*KcTst2f#w6(|YY zZjbQQSS}JEMnuq?U6MOFjhJpFVG#7O+i#PC>`Z!I8*nW~DG{Vy%)1-lC{#vh zHzRKQN}ku350MMp{A+*A{-2>mNx_U=S$6;m3&B^w;zc@&iTYOVT^B)iN$a^v!pRv` z{?|-w{mbrQdfBWxi6ln4h_Ruek6Uy3Sy$h$a{XS%(J~b*fU?T9DO-HfpNW4HxEK37 z2Zn~;5tW2!@$oBG+CKpG7%cYDawTfhReMD`s5_hxqxqh!)WR zuokJe*4Llt!&pBd2obL}JNsN^KKh+608SM_D()=a z2F)}LdV^D8S;HOL*3BDd(JaBUwbaG~g$z!W{g!JQr-PIp(!gfRMR()zoZ{3*u?G9S zBFIEf_L9rqxCo~Cc@+EhxGe18O2w()myxm$Zpad)4vJ5v4^ITQd?EJHdezBFi1vC6 zRyMs?X)HyQ>$6Y&EmN|HU^3?&H^ZKsH529ZbNwYrkHa6Z&u>0FUMcMp`w`0Wj!p!W z1jOjB*UjP}7Vv7P)EsI!7;5;{lFOvJLk>%;1T{r>vKP5gXNA)!nsKoL^4ly?Ev?Tg z{4-*aGvqSWwBX;?Xk)I5n9dk3z0}=BPww$S>pe^nC3!bRNVjFCpr`cmSYWx;r~$Oy zS`gT*21ozaH!Xx(cXXXPM^d4+<}t$}#nxzFUuX3BTkCn^wu)s| zKy=&oNTpD%tynLU^S&hN6u0^%DZW7I)%i>{9Br_wNXH%1cwuh{%bZru($3CX)Sq!t zHXEZQWQFzm&K%wbHDtbU26Zd{(|r;D5{6=fhkI|0_NB~n3c+h!3Ro)##0~v~VzTff z+4irFDxA+$Jo8@5SUSpB>oi>YBzwcpDdVwQp!OalkzN*M8JCs?f$jU$tP#?N;eFhF zR8*hAV^CgS;DxJHTSPv(e}oKI3u(&EaQ6=jW5_?(LY%HKZv?Wwa|z?cmSV(yj2+c9 zkJ~er1dygff3^ZoLQG6utrKkV?(EYA0(_X*9`@bc9a0w832SxFuf&^MG3ELA$w%ru z$=rC(OYwp&=7b|k$-f%J^%e^<5SNQeHX=hATt92hZo?0oQt^+-z#8Pm_XuSZjj1{b ztQd@_=lB)X6U@T=X9gk$z-Yf)S7*|dqrRVDcqH?yDH-i_FNl+QdG2c3Jdcg?S3-T6M0obl8k*)LP zxYN)5@=!ZpE!BTask45lNW$Vs&5CH`n{wxR~I+2!thrC+_cTJ2u7VdwLWQvP%omwMAh6Eu3l$#FB9kcqLNxVL4S z{DPfRYly9CX$dL+UvYmKlt;Hjfx-!a1PQ_2JrE?gySoH;cXubaLvV-S?(Xgu+}+*X z?r_eVygA=@f8Dy0qEb%{53~2|+0wmw_3GYE*QU$BxPR9PQ5>*U%q_aiQnaLA`Etna zI1RUrEh$n)ev8ab&w)-p?Qql~slT2#(cSFRB4g5sQ_%3>J#M-9w6_c-rpn zsh`{4hKpi}zl$%&WU}O{FCSWcD@3W)2)IiT`>|LI2@iG&pPXhH}@0DNcV z)1AS$EA+wmhE6{Yv-31g4$Gg3D#=$E-f!+UGhsHJ#YqD|phDxsk>O#6*CQif9*-6I zW>wnI84%c};7`ie&KK`2t;WeC92@lX!AK!Slc5kus=aVA0y80z5x*vF(!rnPIhASr zc6B_xh*q=mcY+ovD?_BE4`@Lp0FuVGNmy(J9{0ZZNaJUMa~uBy;{Jh{FKXJ{<>ol} zon!akBy7IxV4q^}Dz38^p*dP8p_h%p!+dWqFM{j|3Jj#5hOg@E>94YNG@@9AmYj6Q za~8j6IYOvGEL??1M#ZQ>DCFbgOAKH~MmkM5kpJ~QL7hA&FVoYR;1X`F7IGZ6r|>hC zLQYXXuQ^t&y4DnTi`CGmy}G97LHYea2uzP4;ffsXk6D%V4TP=9xeNUkd1Fq#8ulxz zix%|sUN3$UO@^|b&l84vA-P)fQE1)E%$`ItZ13+M_VD|k`F)!={vz1_!|Z}Ku=fQ$ zMeM&whtogv73}Q{@`A4DZzyXUkt<@5^GFh7fV~a7)KuwMm|6Jd1#q=agJwg16Ni4* z!Ip7WDXNwv&q$j>+!pA8jotq`725C+l*JfxSTJ;VS7mF7Xk)~Uhsjv}cP0b7-Ega? zw(y(lPq(djZD(0hilVS!{#)G@FPm4s1R1FX()Nc?T+vuHajS1Uu1a^vH$>D&{h$7D zrw};+wvq2is-=Jv-<#Bzifr$Y74+xhE+0N&*$0S>^{~%90~uZmylz{kJ1z&|1QZlu zb?^T;JcO&SH9o?&2A84Y-()PRlX;zaN8(H)2=Y%up%T6N^#Ac%;rreJUvqjBp@xVB zg4n~qqi&V+8~w+GV4^IyvdZc<`CH)!*Hab9JsSaIWB8wXxo=&7Siu5s@IRQxKRz@r z3g9c-ybTxsV+*|gq755p^ZJ*z+V5%lU&<92;D4*O>3sX2t7Sk5k6QNs2rvED#sAO$ z*4%(kk8(O2{re^T=jtKgwwl3EO#e^E{vYh_jB1tMYi}_?NJ&W}6BEhu8G6spixF6C ztl?2e)M%4noaR^`{tR9p4Di@@+zC2}Dj@x2b(uQaL<|h-k&%&LX;@0hDJfl3-TZ9q zOWnN-qKm3`lCu#_bBzB$Ae;1WpW|3d11nnLdEaEP(y@*6HR1)Rsi}1h_se-tgh7es z8tSqWG4tbRY7^1W2s}QzcC|)_zwf|e)DNsrZ<6}`wm-af;Y|WBA}0v!Qbfeq`tdO_ zC0P?*ofa#%Czl_hy$`sdGQSc+2ReBEAxPfl&h+U?YfVU|?`I&fL{a(l__(D`_#vBAnL> z+`qy?0Qc_eg7BwfHij{*ryGq|izS)K3jYHIq(KaUVAw$IiW?OK1ca})7pwhoboO8@ zN>Kf#Ej)F(74iDf-kQ0OIgfTEAt5pPi(SGG+^($1c~$F(pgR!V}v!!ZX;-Sy~(V=R;+1WNr9V6BVZ^ z&n^oLPDbm5OPHuCpNVU&w~Q0mwwBmZL}g{8hcr%$U#mb!KJXhT`uO?^1|}sHDzhbv zSFsY&^W!$WdwS~PrTARtj(Z=%lI`l21-R#x+~Z>)m^y-d`C$A6r+?y^)zpy{CCO8ngWu-N9*%&369>QCnMEhGM7{(f}SoCESutV?522i`mGx zXYAIOip);?lQCkX3k>B}iDP^Ob0x+^o+~U$D{-Gbea&Dk^qUP(Vqy9PZe3+3`&JaI zOIO`$67>)eGyCtF!o7LLX#LhuXbpsm^s8Q3X9aM1<)Ccaf6YcaQ#2w#OjMD^|?`~pmN8~ zovy9Hoo9yuqAJ++dpYRijS7-yQ=j)ey+4TKxIJ9Pwza*Pu|ic!90- z%PGh)z|8{;g(L>x@1pmo3iKF4m}>wyx8l~Hh>S2Q%jrUYyn^4x22)yn2q=}Xp!;x* z^%^^*IZVJ?KRK}|aXD_fGu9A}2Iv;T8!i}nbDVtp0DVRGVtZJog$K;&fy?C86`we8 zsjKflW_Q_4ve-`4!D6Y3Q>M2N;e;^(<{w4$Y1!BMixJi=wS^Dk-6tp-BazO4>eU^f zq$C8;q)00D-HIcgnC@0P!#4p3D>9Y6A*n^vLa9jgEF{)EFq zJ}T)bEMP=;y*ri}`7>z)+s*X5>(v#byhB`*z|SXw@BuH2Rs;>CAX)=AqHs=XApnk| z%jEyz+G<$dbiRL(1I>5v6>Fwee4f+y8N^WsDkvc za;yfDTq$qsPB#aB49BLGP*1+C80i&%e!QSEnn@2XQf}^<6zut=+Lnt(aiXnzz- z$+D6{RwpgLmjQMKbKuq8JEK6nXBVyz>lgry{NdZOn`El%xzU~ZT1HhsOKMv!;^)3M zUVU^KPZr{-_z3FBpWE@;tp#?L%550$?sh_R08jw8uKleJiAe*e1=T1fqrX&dl+~|k zX)qg6nFV2ypp72O$;COUe>UN0#8-^PDtBX2+w%C)sXkvIRLle*;q_n&>egPH)e4`a zvTrpUl+gFGEvCiHk(HR&1~OY5)oyoPm?zd*|7~ zQ;diDd=48q6rpX0bInOjw0Ghg?5!s)$merAv{^Q}Vd&-NiPOry#7(;w+pa`-5KQcrdqSKpCMmv#O z57SRoA3YGye-!O4gUi&*6KH$ov+bQUo}i%NI6ClGl$`*0#$sV^?3QsuP2 zr={;o&L{Qahfx}Lv+Tqw?rKtO;KxR^QizIkJ{cwRjbImcRWbS_`lZjM2cg->U|cDz zg@wgL?(6GVvTfHya>2Ir&Z}C+CTPKmi2!}#aa2i=FLFAM`MqELJbg7m*44Q_r*nPR zS6Hp~-Fk-{F{j~{iSaaoCh5qf5LaysgzgVj=hm z;D6co!BHW3Au<+sK;kawItIS|?XO(=hUdIVfI=YP!{YD^40H#+8M{hK>8NK;sM%VT3 zHY$G`)%C1w9FxU$lXKk#s3&ASILw#}WkH9^ZtMdGP~7q&HZjbbxKSu()_}nBjG9L= zCbM;yYl%v2*jl|*=2IU{C7{C;INt4Btu;9{H>Fxy9FCQs3acg%jSjYx$Y4ZnanLgo zMIwPdwxU{!MhbF7q40~)E#MKp>smwZ9`Wu^1OgZ5mC^AQt%IJBkk39(Xt)Ts;3IXg z&_>>vj_$@bg@ERV4<7;x1&WGyi9f#C9lQ@|FTg<0*7qp0eT#8LQ~`u2Zd;yoN30 zbBpHi?R^q+kFj-f}pvD*-{%KMKhAC7BVc9Z$n@?$9h}YSO2xSB zn3+$by=gd?Ev;QRyKzyhTAyJaeHjx-)uKs1gE?|W<~-2_B#Ua!@?(1(N-GsgpX0=m z$4uYUHb^nbJ>Q$CII}k0J>76-16a7gCQovD8;5kg3=sqrR2)Fu&T^R#H?h6z>i=ea zL_ZVne5=QLbG|j0uhuDw?R1NmZ{u=w$)eSOHa>bHGZr3Iw&u#<<`?whcy{Tvqm;Sh zax+k_(>uXvG=FVDwu%y6jO}{hM zAoM&W`AVlgoKjepZe^mGnf+E)PosWfsX=VcQf zuNxD`@Fj@FU8Pe|Pvb+}uAK;eT8(!u@w(q#DL6f(+-$xA@d~u5L$}sB`l5SU^U5}! z^zYma9rOJ6-wy-Dv^r;{Qqfp=Dhn44D|{5~DByxW70Bn~r?A>1PChtI5Lf$S(z~Ak zMuExmfhDcqQKX0CHy`Z8!Y&Pn zmPp3F)bT94J|Pi2J74W;bulxjhhebJ2aKt+yYxYX>en9pno|@{MQ4+0a5yl2-%i{q zg7n2$ce0ZTC9A&_rk#-4;P?3SzR5|SyIekzUx z(#K`t8f&Ydur$&hhV7?3=I!bPGQ;ZrhRt4&@T|MQM;C#U-VfW{tP?rzKXx`9B^@ z%3t)2fmOi&-YmX%LNIlAlPG>t_J@g8c&8g;ubei4pZ{M*$yL5L_P)_bp%=7=5CJ$h zq>50F7x{#;Jnni6?!ZA5yd3bq;<7@1H3~hV4OQERigDWg}orU<{@&KMRCjJs^2O4ei>~#6E z&SGT)9MZEbRcSB-bSL*H9zuXzkx<>%mVgRd@wmoCk&X@7wvP>L;@mKd*e_0G&d<9$ zO#l<%Rv~h)D^a52T}r!v|!hxJ@0=#|8sv}Vlr=rfSdJvE;joXz$Uu8R!3BW2VZ<6|5OB8 zY=>PMP^7%~v3LXRq221zBG3k0;_)Z0aay@9LtN4Rx}*MvlH2>;4BT9>jaUIbR$gjM z8q7+*T02xTULMMvuT?2gM=pgeSCH;CU{9O6>6#0~l{bpNz`$<%@5;b!!oPkn2<;*v zB2LmN@D?9i8|nZXvv!?W&5I;%La^oD6<<60-1o=%0fH0V4%i*!yCni4sImEd6uVAH zwP$WrifSYN{31cY_pMXzfR~&zcJ=tQaxr1-i65l(p3VADblT9Z+X7 zs8el|9ufTQZ9T8t_fGruj4?BV>P{w>VH}17ZC>LFW#d&h|J|A$;UqASAn!k^WmyP) zD^hCrWv;v+{Aq87j{}yK^)x(`5 zq%y`oP|1JT2V9ikT(G>L8y~tATd=Bql|I-cyDW;Owf-SAV2T0RU+v%L-1_k~yQq<@ z`y2L}l>fO$nKw|{Rp$e_{QsgSi?5azG<(heTz$*>3iiAWmix08y*7c%_zL#$hMWD* z)wWLnXE%&FduOIrL0kCKBmyXK+Tm|~jU5izw_{Y%uFW3Xn?pPTwXJdbxfByx0 z07+J}{};PEvq+~8^cEl_;1Ut>%gB5qlJmfnOYRa*PC4tWZq7ul{4eV2nE|BOHSR96 zjwFLxi{UabNMz`&6XH<|0}wXWmzI=qpIQJZxOH?2s(ohKqy9tLc?$=;L!=*E)Wkoc zqX~C-2?!ZDxK#m!XNuqBaw6kcfD&z79MvBq+A+yUhC9v3iK`#rSV0-T?Hr z*>Z%b92o+U8RU$tPBN95Dp0t8eQVFCi>e6sYclGCFeIP#vIepbdk^>K!r%mNuSm>< z0WXn2=E-j~LTVhSYoRv&0^<189m%DwosrCpLOen_vVOd84C>&@laWP85*&43e&#{e zEbcQ8u2;N~XIPh%l*DvUw=?1&{H-hsZnGPng(~Quw`I)*5P&ebMC8{1-6Z!pzz(S0`cFEkr?xmi@1&`90OU}B z(?+5G#nb-$G&5WnsQa`T$n8x;M|Vj>aq(VdV~ z#bHz6;r^qw3_d===G;!|OrPs=u!Uk>W`+&`Ni)FfGM-(ZN51iBHO<{V*r0gMb`5zm zTBA)V*ulKtr_W)9iUy=qB&Nzl;HlDJw4e3F9hcT%m;smq!?xwh4~I*I zxs>`%(%rLkIbu$d?vHyUow?RqBHOnB$wiE{RmRsM{+!imH_I)AXJ%$X{51g0 zE2*$=x>E&HGU={&w!zX@`%~iwvn@bSzIAK3-vWcOotxWwwe9UN8GHd$=5@||LZyLT z;)p>H3auV6Z>+E6V!BsWRwg^2?p0n&MvSql>g7)0@H=i7?p8Cy_4X>ZKt>r#Ce(54 zGlGu#J|nG^nD>mPL?`RwFHkZoR@DJgwJgNbAx0;4HKr9V;qGTA-Altuzx$L z#;_`^^w(C`Ub!T}t7uHe4MNoHE6cswoqx(vjZXGnAVqNVt}pBpp9Yo z!wD20ab_)>xlEcvj#c`lHw_jAMPXtmzI-DDcGUFoFpS&v3z2kV?U}re)mCgLe;)02 z7E~``Gfo(Jojp0%Z~o0sLioP9n@yr0V#(%GP|#3O=!{G8dsDo&>1_lHWm@l?9?za- zws@*A@VAqgFS5iB9^}O84GC#Pu=i&ajsaiA=-ud1a{WcN#R>;XRvxqI{`KLQT63pH zU%(nKz1J~bA)vi7cHLlSE*XwX5Cky><2l`8rs8DPagpO~zSJNjh~%c$Xv+|xO%7Tn zO;@M>qe$bWlFn>djG)nEs0kNb)E{&Z8XaO(@vDJuUKvH1D-&~eJg;Loojrjcw0Nz( zEz5-3HpT69Sv=#53bXZPp3+YrAD?)k9p3#o&YUp^(*|!tH#y&P!IRc6;)#nU_m8_9 z`2uW==B}mgI%{MQ^B$wA>{)T=WkFZN?~6!)G{Be>+3zq;`@*y{0Fx|spUl=|s!8~H zu6cnRvS^p$SbDBPZ>yO!3VOrd4Ce=Ou`&h&<4gf5RSTW)J?D8D+ryzD?d0>*hb*fJ zWPR-E*_zVQ=IfkAx1AL9xo1B9k|-eR!h=q4R3c}q_k9K34Tt&=t$C%mYs>4j_}dAk zQma-bkbWrt9@?1)d3P~wQh{$(`c%Bn%V{O+f-egbD!Lay64P9?&~?wgEL9d?c&#jm zpJcOx?Y#w3;zhHn3d?h^whl5hbd}q^-GAp(0I&HK#49PZmyY?V5s@UMjU03N)km}N zL3tp}nD^Fn>SL6a&QSxjOoMHJ5h%56iz{>e)wIeuYyDXd20ch~cYq8dQesUuf3QA! zgu8-$LFprdnRlL5V@+}B8{QfOL~s^9g`2}AgF}jwriYet6-{!!Cauys`OJ%ISEp<-K=bFD_4(G;MUmG0W^g7CHd-0ii$-IWkQ(D&RwoP zX4%r-??Ki=L8zC~)l}{_ZaC>756E7_Qxmz8gMOi$gDVTQ37=1omt3~e)EdQXQ4dA) z`7=G|T`I_mPb~BpYLda)PSqIz>0kcmwJ5FMo#2C4MReJxmND1C|;5?a=Q za%8%?S~g@8wMJL8wvk4|Usw&7&`h*!^_t6&{_%7X)n56VRwuA_l$q;R57$Qt)8AqJ zzVi4y26}qywY8B{AAj1IqVOFy6KKxmhtV45sv0FjSy2+CZ0R^rtChe~YIzhS==g-i zK@L-8p4uI+Kt8V{S)@B4^UE}d$P4w`rRuYwh7cRkCrh`F`6#Q zPguc5@@d^W(;rS$9WT9Fv-X0XpB8^=uK^jjX6MTbFAbkcaq`W64`+usv?Po|F}5$> z)1(DMn%i=L=bc99Zp#)8w(?1rF}$#}MI^I}v2bZa5W(qL0R^S_D#>pMa{D?h_sc%@ znH`f7Mseli`DVdZy*kO|ms4Jy6VF@0{@E0Y z$~a<)NXjLb0p#k(uKo4CDaV>I;>K3wg@o*8$qV~jH4J3GQ`ZHAj-L187sCS{jU$x= zeN@NmrW$-4qwfs_f1hw|pp?*!$fvrH3#Tx7@h*}V{GHya5@t~HfKcVnkFM5bVhNA2 z=EosX*@JO|L3*N_^CqR#a(?^e{!<_BxXxB}b z+R(n#9&C3HLCy>A5wzn;P@MT!xy=R`#tiwCBTW@aZwOR+juiwekiUV4M+g!Bpro>z zi9=`jT{Sz2xY#S8G);rF@@H9?-c3*umCzhOAcO{Zat!qPa-5ZS>q%ZT1LYO>ZCY0e zkJAU+Ngo}TJ(jD4&FjwYUu<_yG(-R{%9qyX`y@KEai*gtbtYuy**8Hnf{e4y&dz%R zOHSLgJ$L&D%#j7bkcFC_TEh?+Vw_1FygA}e8V%4pQTY?Par3~EHc0&ceB*&OpU~MHuBDt7NW^7jl(YT4W0Qv=P|(W?&Tq3id^vJy8cyjl?l7bj z_KW5L-v`(Fdj)H3kQKSssWxx7zm5t^(}2PN1b$9A0x~Pxy00L#II}zJKrpALO}KU#Hll6AdcNB5R22fWkNSi4+9c2gCDlPTOSlN z4w_Y4#JFJ4i`06?BQUg@Pap#r<@j)td z385+QQI`EV+it6&ck0I$tty{GCuz-)bm7`-VdY)2xcFGO3UxOF===bU&B$!g zxWcq$IWvx%LD2>XgxJ&}5ga`$W!i$K%kwV+y8xSd#PqQWJ8`1e1f|jt?fg=zQplxD z0|$tKV?;^7J+&in*k1}oQNpcoeV>Z%x9D?xV)Z_K|00OvBsE>4mbSGbq<>Knc6WCd zFF4qkqq$L3DA2lbWs~OvdT-!73K#fk>cdM{PtVS09`jHeqS9I3HI0FrpppZT9vzI| zOUx8B`O?HFDc)2oNqzgGA2p(igMcit2z#b1z|bvG<41pOiWAH=PWO93HcT*S@qoq< zu!u=iB$-qBOihWJ2*rcusgdg@J93iJgzC=sB9B~?J9^yF=DbS)SnZox$pVQ%8O{^H4>(V4;3B6tHG_F3Mg4jgU!?yZsf5RbkdBl?O?>;&K4@b z*r4M#C=EV{_atB^$`KWUtZ?3!KLT=b8RAtOhwqoKhMv_eu{}y}+wmd5jtKDa>2VyD zb=h=0a%4Vvq_E@UET7ReLOgrsnjPE1<5)=QaPnNDT@%g9XlsvSJ9``2_Owo5eu~R9 zcJw07xYHB;z-*h0Def2Z4{-DIJK(jWz&d_PVg*T}(_kiNbc`Qfw9qeHc_{dD3_G?B zN6;$-kVCUV%pZNG-bdWPEGI>_oYt+6K;_}_J?&MdZ!dtGRFZZv9DZiXmC^7>7VAM~ z3mKUIc#yZpH+o(nM$p(mrv6@pq9CEDH|MMZrBg|pN(Xs^bF4DVyW->(6azZ4ChO&wlx0e1_5 zX~%-c)RYn5E)lHxE$E#A;3ql3=C~4%y3YuITOHgWC=PFt+xu+>fMaqF;d`Io>DAR44Ys9e3*RRj zMJY_Vuf*6nKGe-@?5Icfh=%`YYD*CU$!{qA3q8V7-`zl0_xw7ML`af|j-~$*?Pp@%x)<*X)kkS(#kSTBUS+Z3B6El3(8*2x0y(pQk zF%$m6D1Z9AUesbtj{Bqa4J3X^Spq02R2aM9-*RK0wSbGFv(P(Re?Va%mkjZ>PT>Ey zT~&oLHw+W|Ee;NJ{|A!iq-+G@)7VQnA`i%j1paM#Er11!hFtwSo^9=*>yh7xh@}ac zyW8KDKYSs611OpkuWuQrf#lw{Xm6VSCBWt+`KE)FhU4TxFWgD=&58&g@y}7&Mo=d9 z6(<**S&ZMYmNyWp)Nd8VwL^Y3u2ar_#eu-xHfu>Q>%`zYO9^KT;Qd3J{J~`pO1DdK zt3}EJYS}7tSoT5M6(z-GFyVhj)(QZn`5)g~-~au-`2nt>!&tpSGU>mq{@{WG^ySpL zEO2vwOS!!MiInZ@noV)({=azJXdw^@z;>;WqFqOzgt|If+x!F43*kC|{#3cZx2p^G zGfj~N+u-IhB9c3e?hQ^W-f((=TnlBJN5$Ddy5c!gn>@kY`Kw!K;7o;@c6L@W<>c^b z@y5#=s9h!%97x+DbcYE6x`830$W)95R`Pg<8CdUc>jDZ}Bx^SCXwh;Kj|4B-9YpI6 zS+GgoCHe}Lr3I_ORQ1eiuGUZ4Pxf(H zm~4sP8Y?7k4_0?FBDZuEBNMzSNhtT$#wEjkCfvBmxbCojyZ&pcfbqN;+g*X_8HhU= z9SkhvtCt76x!Pg}pxu?$!|>Spq|PigEDs|W7t*r}+mZ6nchiwTLOOaQ+OI3v9^w1OUp?Q5!LYFh{GMjv(U z>(u~Amf%T$&B^bX;Es8Di%nDl%Zj$j=6Sn#RQ9A)a-xlcdjW)J(&=gggZwr7cY7wI z3E_T()X5?(@>WSXAK~!q z3Y>(K7DW2bei7b1&wORJWsr7dOU~{WZ?V3yBeW+AIjtXmHl>EKE8TeGUP|#%^>o4#dx_%44kvKr9?OgBkr$5^Dz(QFC2RYT` z)%8e+vj~{C!W!tmLSmEsm=?E28$Osf2PpBT8X8%8*M=A=$Y;<6v41rbtv7t1N; zFj#)r^U_WgxX3MKw%GQqCx80F^C>w@L5t#iCtXqL%)zH<5l%1TV2$NEoa|RQD%T}P zt1lzdH&<_vKglh?UM&p*+ury7ynnz(-)1XQ+)GxGr9YiEutJ{yfZ)E~8O=ed0ECfJ zIxDf|#7^=%`E=i<-;y-(ebR)ef6P04CV4Y*fBK+icZKM>1I1I<%r+3O@mlU5O$((N z<+bF`6g>860a04TqJwqU*<01vTiGILFbU1nlZuk)OS@loG9x#C?ST@+J79*=b~HR+ zapX{eTPyOb%8B7jvRu^q2v;h*)0CSqC;Z9}xg0BZm-T#_S!2qV?ib~me6Bdr^(xOg zWI?uY-7~P$vSy$eQ`GISrIxB~s8wQ%e|vt1Vn%ZJF}d@vO;#PAiw@oBwxHnWQclN} zMkwJ-!vKHtq>=V*IIorQf)HJVC10O3PQ=Q%dkK2I{c!mShEB4=+lO<9+z=*?TrXxC zhHgbR^U2RHvZ_IW9C0v~aSM~%5vCoR5*079Ui~2zhoeGD#c+nV<9Ic2z8vWoq!tP$ zK_>zzci$LomaRf-or*EnOWf^XssmLCee)Pyw*&h#B91_v?AFk1;Gfz!TTXPF7L~h2 z$$abj0l_Y>Lvq1U5}||n=X39Q*-r=Bgt7+>CXg}vdP~s$!Oc4>tU)J_I>QnF?!#?( zps*3guKumb;Nm|VVpFK6;lYRSibV=%SX2w5?W2zOy(Pwig5^MUHnt{;dFW&gjWV{F z6A-IxmHiMLbmmTFTN#_SYSoVPGWwk75y1gUwlrrq=~RFvxI-3%&kBZ(@5_9rc$Wfa zXAsC)%Y|aHa}|QPZKD%~hG#3L+bnW`6`=^9ZDUbuA>4x_KXTkb6%1dmg>36xtlQXm z?Yx|3ICu2JjW=}#??bP4y6ewE*^joODwwnOsgft8|Gz2ff^c6u6nQ(@?Y!3;MMnn) zS5hOl86NSFrY_R^dvPJEYGpLtr2(w9U`#J;#;N{(^cr1-{x> z9X7tkVlQekV~rozNM5R2V?CZdm2Q+|-Qf1%#6Mk@iC|Pu20Tq^#c(Qn6Th$rveCbqGpt#9>KhIS}Z&$7e zng_~K2wJiFF=4{5`sBb8jqF$?zR6l+XkQH$_O>YiQ%RH ze`f*#1lJ9Z0zL)K_+84l;SKlj<65B-_dr4OyE$PH`c81R@oPlB-12-H`O3suflRZ9 zwlgv^*CqPk0J$GMu-cAw<~2ay)95C^&&_LpK}TU7fW_zPbclHI^Lk^rZYm7NT9*p+ ztqs=T?{C?SoJMt?d$BEtFJkC+U0E0t36EJic5^xGtkU7UMF10tb<$YTcbq!-4 z946Zz^8gDCT2UWX(WW1SVo1j4QJ3l_rBtsiLN1R?Tx*0runCG3laPo6d^b`IctUJ! zBUX#x*)6MvKL!<1^cx>-L)B#=+5jz6b013qPgfp7bdV*{FjQl$WtO7k8R_wb}0uNrd*Jqa0P@njgioF=}{CVrl#g_KGP?lKqr-qNd z2tZFp2MC$PM|Jc$NPI5;^sjw_NDTs;Kx!{gSJ}viVV0y$+Nh|Skh)s(B{ ze_NSvAZ7uU!veN)(ciuT7f3z8a!7%4{I@>Oe{OsYkTPogkq`bgX}`aN$kHpZUww1P zG77Ppnvi?DS!NJ)g6XAA|L@ANqCcHGvA{xlAJ2*Lv#C2hxVPQriR!Z!*S z=d~uPwcvXQ8(o`5&j-RAgRf-Ll|%tEtgS7ezPH7d;JsjwJ|@&n7F@dq)Rcq zKJUmwhtmHv_FA>N`!we~^6%$`Bmthc!%2hb%ioP@3jvLxF3YO_A*j7R@7nA0GMzvf z{9V%h|E9sktEU1)Vk59v?FWEVe#q{SS9BC8jYtBB;F2O7PunmK2{*)^<$* zfvLKoq*|_;#|k<8%#1A41e)>vme}!zt0zE@B!Z-qlh)MdHQ=6##i}d-WRj4$sT+~> z_xIC0`^M=`jGAZ+Ew_tZWq_A)$Ipg||sv zU7ZjBe?SoC;tJ0BRN(o=~e`FBzSf~`M~2$NWS0&Z4w zQzMod9R`Q1jr(^dIAi3##P$bMg~S1M9})n)0 zK7T*IpsXA$zdQ$fdxrJr$e?>Xa&pxNR-(W_W|VEz2SBp}tuZos6LA72W8w4I*w`zD zR9LwAYXlSpwsTn;dHhZ2t0>*Jkch}R(b2Evp%)&v1F#uiC*>ytxzU2~89;x)#!XmQ zxW-=`r>q&^v*A>Dyu599x*Yw>WPh(Z&7A)v#n_J!I?hr!q~R0vLw=o(r2-8BzlD7ti)pL9Ejmu4XIPDh9)_fnCT;D}qQ zReZw5(#i754$euk)99UT%=ds3wi3+X1E5$`+x$HG+Z76d@Z)7mYvZ8)DB{%%h>d7i z)n;PMIC#o@rSXZ0vu>}_)$K9#5z1prE0e(VPQmr{ZXZ>HxduDdd1rebs2h31iI#Vt zFqy!4-+8N2KYID@02vOeiyc_Qs;XlZcC1AoA)UAnci2vUtr6^w5Bsk#O#*ld{< zLaKi7LH66h)!j|6Ih!4=!PsJBa|LBVlG2fYySqAjvXN_mK8;z}AzyeCOWx06KH_?K zYem9lNYV8CDTRYu_EP=GDmacj`z}dmMAgF#b9B^dZ0w=R>QT_umCe=v<2Mt_oU0n+ zjr@^bli{HuzVKAHa`R4scoYi1&MGPr1BIfGpZe+jn_xkBxWK{R;^Bh&e5ZtiT@c1r z_+mX{PE>|5Sqjs5e`U>oeYzL6-Yxn=d=u|3BRJ3Wq;8ZLA6JuksEV`zJ4B0-zVhM5G$wy_GRX`|k+rD^J_0Y>wQ&ahVM6ghE)K;SAviq2BIMILv z4^J8OgFU1%8V!a7hc&$GV8$x8;-NO`M03IqN7Gy#6sSVh@$B|6R_>h}R4=6Q^|sE1 zlvMW}ge;o#NM9P;6_iABK=uZ{6p%D>#qaHV-W)AU{^AaH3AvX)#NON8liDQ^mieSA zD&|uwNd<&nKUSN}comyDVX`B8zxDRReQJMqxi^IXLxY`X%J@RohIV;*Nw=QN%36X< z^779x!oH5FAh^)>0}@IQ)Dw_t83QnRvd5vM$&(xHjzZMg-J~jXAu!o&QSs8XzS7fn zD?n}Q+>9LEYMC(=l<3hqzj*^8EX>C(t57HcLi>JD0knV_B-SmQ5Po@T_bK4T2k$;t z?ey%dM-G19lyxj*^@rSS?aLb=mlL+yfTYHJ`Mcg*QB7S#AO7H$ZVSSZG#nRUat-1L z)0Z>B0B{&yM@8^yAFz!H>P#siDwE?5-zzOX-(XY51l9+ffMtY0r%O{~?V#Bx64Hg# zm~O_OVojbA>F}qn*c`|25D@gF(df0AGVBGl?F_$?&Cid|Bb=RVDLs7ijX-p`*cK1L zruUl04lMhHOH|?%K3KT{^3L0G_f)#Bv0j^sdbUQ70NJBaD8*u}gCD3pUBWVQaFX(a zho?n2sz>$>y6>1}4%t$~=%p}mP; z1u^~%slhCq#+v@q#mWVTjsE_P_aN=5`wP*59#f8dN&q>1Uo+qYH=0!Eoq_^NmBop0 za_VZ_L~fvBA zlatYhpHX6Z7Xn!N%dq^-K9lbQRYux1Aa(zqT?!Cv7tFi+pO(iOLPI&F%&zO=BZHq( zama_58y^Bd3*|_^$kFvpMFD#0gH!OMJw52r918M~Bij|Hn;#wS&bO++CH}}GS8u9= z-%DgXktuo$ajRJ2K{(V}#G#X}?9){Xp%+U_OG}qNZxFXV63?uI4!p&7^~=>CQt&ge zmX?M>b4NiH6}iD*haSDwOq`qw4gt_tNtNkiO8VPqpR4%O4(=oGj3T z1CV;R%Ek;g`eZu5@>O96cv!Y?t&+oAe?DdC2)BM#RE*zv+kN({NbusZpt}Fz-(3mz z7Z}K>Y&2!jHI*tsaG&4x^=vbVh*M0xi!f06tNP38(9tShr!X#t=EgnvRBSlE{dh4U zQI)tb?nRyJUC_RvwgB4FI^hs>|3G`kQ-?3qeEspalhdSHbD*~A91I*kDFZD5!qdZL z4M7_=-8Fd^rN|(Pp^z37+LPZ64~u= zR=TRSSET5`fc7f^4m->+%bj!I-`j8rf@99LtsBXS=93zWOZz}UG<;ZQZ-|1!PcgBk zFo5-x*T|Xrbd}t&7DgXv?eY+=CE<1U@#-B6B&0Nd_(OkXbBqra3KoOCrBp_xc?ye& zl%KS|^FtU89Et9J|`CN%LIr00O{*jJrXv*=+Bx zw0Igb79~fSDQ9NZl2VO;TUDvYiScn83uSeP{~k;K*$w=G{ggF4xLb|sF-HPFogHk= zWJX(37LlBSB0?yIg-Jy%lx@0FUqa#e_`Utr7_fW0UX&88mXIutpWI)q?Ao6R8_riz zJKyZ5kI)%%aRQZ0)s&Q)SR4p~gQ!KKKflK~7-vF3$!&14{2A`RXgXh|1mRX2Yo@94 z%zOXHRwDDjz0&U8w=8q%8*?%2J}toaxv`%N{>F5Ti4RKz=*8+%b#R4GUeYaFzf^+l zFle&cNEXPq5kr%ELmQMh!DuIg!a)5pl4RBx%f`;q{9W46hHy(v2eLguH0NO{D|(Y3 zPekA^kM|ghl8urar-FG>>1_A9y;u8l?~?MT@Ls%D_m>l!_Vn`8?wJYIoBbj({R*ou zTo0)Y9w39A%+r`UEy(`>iVLsl2QuCOV5|DTYkG zt1EDW8c?jNwg@W}^UcGF{7NMzkK8iVoT;NTSrD_Owln%aBN_+3tEbE1YUjK3vL`{u zp*eg`SITViu-UJ(C@$=cq!$(1r}5N^DXhD++Q9>LQIyfvv@MbDK3jS)(w-6LHeZTy zc(aYqe@yb6vw??o!KzoRK|H=<8F(nC*mq~0l2%-NDU|Koq`wf`QIO{1V)_UFh7wV-x{={1BFwm!^AOfBY3fv4Nd zvo}M463>2Ef`yZq`bA|7s3eWeoSb^iGh^tW6J_d-p3PQBM62)jKL_q92Q2K_6NhSd zt0v51N!bgR#?)Kl(g|iJIvJ}_bcUfXVjKv7b@PwK$mL0hTN4H1G^aQ5=i2MN?zp*> zp|?NSG3WldF<@W5etW%VGb~15KvjOl~Fr&pp5*0dxKT^wwQK3^~pQ@~_PS s98m}azXfVjFHRil@5`GXJUQP;8;Z<^Ig!781N;-_m*6Ym(e(O10FjpqcmMzZ literal 0 HcmV?d00001 diff --git a/references/embedding.mdx b/references/embedding.mdx index 31a97cce..e6376c17 100644 --- a/references/embedding.mdx +++ b/references/embedding.mdx @@ -1,215 +1,714 @@ --- title: "Embedding reference" -description: "You can embed Lightdash content in your website or application securely using Lightdash embedding." +description: "Complete API reference for embedding Lightdash content securely using JWT tokens" --- - - Embedding is available to all Lightdash Cloud users, [get in touch](https://lightdash.typeform.com/to/BujU5wg5) to have this feature enabled in your account. - +import EmbedAvailability from '/snippets/embedding-availability.mdx'; -Embedded Lightdash content is available to view by anyone (not just folks with a Lightdash login). + -So, for example, you could embed a dashboard in your product, and anyone who has access to your product would have access to that dashboard. No need to login to Lightdash. +## Overview -We make sure that the links are secure and have a set expiry time that you pick (more on that below). +This document provides complete API reference for JWT token structure and configuration options used by both embedding methods (iframe and React SDK). -For more of a deep dive into setting up and using embedding in Lightdash, check out our [How to embed content guide](/guides/how-to-embed-content). +**For method-specific implementation details, see:** +- [iframe embedding reference](/references/iframe-embedding) - URL patterns, HTML embedding +- [React SDK reference](/references/react-sdk) - React components, props, TypeScript -## Known limitations +**For step-by-step guides, see:** +- [Embedding quickstart](/guides/how-to-embed-content) +- [Embedding dashboards](/guides/embedding/dashboards) +- [Embedding charts](/guides/embedding/charts) -There are a couple of known limitations today with embedding: +Embedded Lightdash content is available to view by anyone (not just folks with a Lightdash login). Content is secured using JWT (JSON Web Tokens) with configurable expiration times. -- Embedding only works for dashboards, not table explores or single charts (unless the single chart is pinned to a dashboard first). +## Known limitations + +- Embedding only works for dashboards and charts directly. To embed explores, use the `canExplore` flag in a dashboard. - The **Filter dashboard to** option when clicking on individual chart segments will not work on embedded dashboards. -If you're interested in embedding and one or more of these items are blockers, please reach out - we can activate them quickly. +If you're interested in embedding and one or more of these items are blockers, please reach out. ## Embed secret -The embed secret is used to generate tokens for embedding dashboards. - -This secret is like a password that will help you encrypt the URLs so we know the access is valid. +The embed secret is used to generate JWT tokens for embedding content. This secret acts like a password that encrypts and signs your tokens. ![](/images/references/embed-create-secret-fbb86d6bcb70f4d004c48adb3c107922.png) -You can regenerate the secret by clicking on the `Generate new secret` button. If you do this, people with an old URL will automatically lose access to any previously shared embed URL. + +Keep your embed secret secure! Store it as an environment variable and never expose it in frontend code. Always generate tokens server-side. + -## Allowed dashboards +You can regenerate the secret by clicking `Generate new secret`. If you do this, all previously generated embed URLs will be invalidated immediately. -Only dashboards included in the `allowed dashboards` can be accessed using embed URLs. To embed a dashboard, you need to first add it to the `allowed dashboards` list. +## JWT token structure -You can use the `Allow all dashboards` toggle to skip the dashboard selection process. When enabled, it overrides the `allowed dashboards` setting, allowing embed URLs to be generated for any dashboard in your project. +All embedding methods use JWT tokens to authenticate and configure embedded content. The token structure includes three main parts: - - ![](/images/references/embed-add-dashboard-feb6ef5fde69ba9d6eaeb693744d750f.png) - +### Common fields -## Configure +All tokens share these fields: -Configure the embed URL. Then preview your settings and copy it to your clipboard. +```typescript +{ + content: { + // Content configuration (required) + type: 'dashboard' | 'chart', + projectUuid?: string, + // ... type-specific fields + }, + user?: { + // User information for analytics (optional) + externalId?: string, + email?: string, + }, + userAttributes?: { + // User attributes for row-level filtering (optional) + [attributeName: string]: string, + }, + // Token expiration (handled by JWT library) + exp?: number, + iat?: number, +} +``` - - ![](/images/references/embed-preview-6add607fe9348ed49483ae487235bd50.png) - +### Dashboard token + +For embedding dashboards with multiple tiles, filters, and interactive features: + +```typescript +{ + content: { + type: 'dashboard', + + // Dashboard identifier (required, use one) + dashboardUuid?: string, + dashboardSlug?: string, + + // Project identifier (optional) + projectUuid?: string, + + // Filter interactivity + dashboardFiltersInteractivity?: { + enabled: 'all' | 'some' | 'none', // Required + allowedFilters?: string[], // Required if enabled: 'some' + hidden?: boolean, // Optional: hide filter UI + }, + + // Parameter interactivity + parameterInteractivity?: { + enabled: boolean, + }, + + // Export capabilities + canExportCsv?: boolean, // Allow CSV export + canExportImages?: boolean, // Allow image/PNG export + canExportPagePdf?: boolean, // Allow PDF export + + // Interactive features + canDateZoom?: boolean, // Allow date granularity zoom + canExplore?: boolean, // Allow "Explore from here" + canViewUnderlyingData?: boolean, // Allow viewing raw data + }, -### Dashboard + // Optional: User information for query tracking + user?: { + externalId?: string, + email?: string, + }, -Select the dashboard that you want to embed. Only dashboards included in the `allowed dashboards` list appear here. + // Optional: User attributes for row-level filtering + userAttributes?: { + [attributeName: string]: string, + }, +} +``` -### Expires in +**Example:** -Set the amount of time it takes before your embed token expires. +```javascript +import jwt from 'jsonwebtoken'; -Although you can generate URLs directly from Lightdash with a long expiration using [generate and copy URL](#generate--copy-url), it is recommended to generate your own JWT embed tokens in your backend (using the [code snippet](#code-snippet)) with a short expiration using your `secret` to make sure people can't be using embed URLs outside your app. +const token = jwt.sign({ + content: { + type: 'dashboard', + dashboardUuid: 'abc-123-def-456', + dashboardFiltersInteractivity: { + enabled: 'all', + }, + canExportCsv: true, + canExportImages: true, + canExportPagePdf: true, + canDateZoom: true, + canExplore: true, + canViewUnderlyingData: true, + }, + user: { + externalId: 'user-789', + email: 'user@example.com', + }, + userAttributes: { + tenant_id: 'tenant-abc', + }, +}, SECRET, { expiresIn: '1h' }); +``` -### User attributes +### Chart token -Use user attributes to limit access to certain data in the embedded dashboard. You can use any [user attribute](/references/user-attributes) that you've defined in your organization in the embedded dashboard. +For embedding individual saved charts with minimal UI: -To learn about getting your embedded dashboard to show different values for different users in your app, [check out the guide here](/guides/how-to-embed-content#i-want-to-have-my-embedded-dashboard-show-different-values-for-different-users-in-my-app). + +Chart embedding is **only available via the React SDK**. iframe embedding for charts is not currently supported. See the [React SDK reference](/references/react-sdk) for details. + -### Interactivity +```typescript +{ + content: { + type: 'chart', -There are options to enable certain dashboard interactivity features on your embedded dashboard in this section. This includes filters as well as granular control over Lightdash features and capabilities. By default, all interactivity is disabled on an embedded dashboard. + // Chart identifier (required) + contentId: string, // savedQueryUuid - - ![](/images/references/embedding-interactivity.png) - + // Project identifier (optional) + projectUuid?: string, + + // Preview mode (optional) + isPreview?: boolean, + + // Permission scopes (optional) + scopes?: string[], // e.g., ['view:Chart'] + + // Export capabilities + canExportCsv?: boolean, // Allow CSV export + canExportImages?: boolean, // Allow image/PNG export + canViewUnderlyingData?: boolean, // Allow viewing raw data + }, + + // Optional: User information for query tracking + user?: { + externalId?: string, + email?: string, + }, +} +``` -#### iframe + +Chart tokens use `contentId` (the saved chart UUID) instead of `dashboardUuid`. Chart embeds are scoped to the specific chart and cannot access other content. + -To control interactive features for an embedded iframe, simply use the toggles in the settings page. +**Example:** -#### React SDK +```javascript +import jwt from 'jsonwebtoken'; -Use the React [SDK docs](/references/react-sdk#token-configuration). +const token = jwt.sign({ + content: { + type: 'chart', + contentId: 'saved-chart-uuid-789', + scopes: ['view:Chart'], + canExportCsv: true, + canExportImages: false, + canViewUnderlyingData: true, + }, + user: { + externalId: 'user-456', + email: 'user@example.com', + }, +}, SECRET, { expiresIn: '24h' }); +``` -#### Allow users to change dashboard filters +## Interactivity options reference -You can choose which filters are displayed in your embedded dashboard. +### Dashboard filters interactivity -The filters shown in the embedded dashboard will act like they do in Lightdash. Users interacting with the embedded dashboard will be able to change the value and operator of your filters. They cannot add new filters, remove existing filters, change the field used in the filter, or change the tiles the filter is applied to. +Controls whether users can interact with dashboard filters. + +```typescript +dashboardFiltersInteractivity?: { + enabled: 'all' | 'some' | 'none', + allowedFilters?: string[], // Filter UUIDs, required if enabled: 'some' + hidden?: boolean, // Hide filter UI but keep filters active +} +``` -- **No filters** - No filters will be shown in the embedded dashboard. All dashboard filters are still applied. +**Options:** + +- `enabled: 'all'` - All dashboard filters are visible and interactive +- `enabled: 'some'` - Only filters listed in `allowedFilters` are interactive +- `enabled: 'none'` - Filters are applied but not visible or editable +- `hidden: true` - Filters are configurable at runtime, but UI is hidden (works with 'all' or 'some') + +#### All filters available as interactive: + +All filters configured on the dashboard will be shown in the embedded dashboard and interactive. + +```javascript +dashboardFiltersInteractivity: { + enabled: 'all', +} +``` - ![](/images/references/embedding-preview-no-filters-ced58145c215a0b17d86b50634a09057.png) + ![](/images/references/embedding-preview-all-filters-bf5d00a3ef24a2370bc5ca56c8785e2d.png) -- **Some filters** +#### Specific filters only + +Only the filters you select will be shown in the embedded dashboard for users to interact with. All dashboard filters are still applied. + + +```javascript +dashboardFiltersInteractivity: { + enabled: 'some', + allowedFilters: ['filter-uuid-1', 'filter-uuid-2'], +} +``` + +Configuring in the UI: ![](/images/references/embedding-settings-some-filters-1658fe2f72623f85dee2eff322833ea8.png) -Only the filters you select will be shown in the embedded dashboard. All dashboard filters are still applied. +Will result in some filters in the dashboard for users to interact with: ![](/images/references/embedding-preview-some-filters-9f13263ec3800c3e7f5e6079fa78cd66.png) -- **All filters** - All dashboard filters will be shown in the embedded dashboard. +#### Filters applied but hidden: + +Filters are applied to the dashboard, but users cannot see or modify them. + +```javascript +dashboardFiltersInteractivity: { + enabled: 'none', +} +``` - ![](/images/references/embedding-preview-all-filters-bf5d00a3ef24a2370bc5ca56c8785e2d.png) + ![](/images/references/embedding-preview-no-filters-ced58145c215a0b17d86b50634a09057.png) -#### Can download CSV -Enabling this option allows users to download all chart results as CSV files. +### Parameter interactivity -On the embedded dashboard, this `download button` is accessible from the `...` options menu located in the top right corner when hovering over the chart tile. +Controls whether users can modify dashboard parameters. + +```typescript +parameterInteractivity?: { + enabled: boolean, +} +``` + +When enabled, users can change parameter values in the dashboard UI. + +### Export options + +Control what users can export from embedded content. + +```typescript +{ + canExportCsv?: boolean, // Download chart data as CSV files + canExportImages?: boolean, // Download charts as PNG images + canExportPagePdf?: boolean, // Download entire dashboard page as PDF (dashboards only) +} +``` + +**CSV Export:** +- Enables "Download CSV" in chart tile menus +- Each chart can be exported individually +- Exports the data shown in the visualization ![](/images/references/embedding-download-csv-2a4cbcfa350c6cefed880971090c117b.png) -#### Can Explore +**Image Export:** +- Enables "Download as image" in chart tile menus +- Exports charts as PNG files +- Captures current chart state + +**PDF Export (dashboards only):** +- Enables print icon in dashboard header +- Exports entire dashboard page as PDF +- Includes all visible tiles + + + ![](/images/references/embedding-print-61cb9f9107c6e4ae00fa3cde99dd572d.png) + + +### Date zoom -This option allows users to open a dashboard chart in the [Lightdash Explore view](https://docs.lightdash.com/get-started/exploring-data/using-explores#select-your-fields). Within an embedded context, users can only interact with the chart from which they clicked "Explore from here". Any changes to a chart in this context will not be saved. Embedded users also are not able to run raw SQL for any Explores. +Allows users to zoom into time-series data by changing granularity. + +```typescript +canDateZoom?: boolean +``` -On the embedded dashboard, "Explore from here" is accessible from the `...` options menu located in the top right corner when hovering over the chart tile. +When enabled on time-series charts, users can click on data points to zoom to finer granularities (year → quarter → month → week → day). + +### Explore from here + +Enables navigation from dashboard charts to the explore view. + +```typescript +canExplore?: boolean +``` + +When enabled, users see "Explore from here" in chart tile menus. This opens the full query builder with the chart's configuration pre-loaded. ![](/images/references/embedding-explore-from-here.png) -#### Can View Underlying Data +Users can: +- Modify dimensions and metrics +- Apply different filters +- Change chart types +- Run custom queries + +Users cannot: +- Save charts +- Share results +- View SQL -[View Underlying Data](/get-started/exploring-data/exploring-your-content#view-underlying-data) allows users to open a table for a given dashboard tile, and view a table of the data powering that tile. In the embedded context, users can only view the underlying data—that underlying data cannot be exported or opened in an Explore view. +### View underlying data -The "View underlying data" option can be opened by clicking on a chart or big number to see the "View Underlying Data" menu option. +Allows users to view the raw data table behind visualizations. + +```typescript +canViewUnderlyingData?: boolean +``` + +When enabled, users can click on charts to open a modal showing the underlying data table. Data cannot be exported separately (use `canExportCsv` for that). ![](/images/references/embedding-view-underlying-data.png) -### Preview +## Allowed content -Clicking on `preview` allows you to preview the configuration for your embedded dashboard. This what people viewing your embedded dashboard will see. +### Allowed dashboards -### Generate & Copy URL +Only dashboards added to the "allowed dashboards" list can be embedded. -Clicking `generate & copy url` will generate an embed URL based on the configuration that you've set. + + ![](/images/references/embed-add-dashboard-feb6ef5fde69ba9d6eaeb693744d750f.png) + -You can embed this one-off URL directly into your application, but you will manually need to update the URL each time the embed URL expires. Alternatively, you can add the [code snippet](#code-snippet) to your app to automatically generate embed URLs in your application. +You can use the "Allow all dashboards" toggle to bypass dashboard selection. When enabled, any dashboard in your project can be embedded. -## Code snippet and demo +### Allowed charts -Although you can generate URLs directly from Lightdash with a long expiration, it is recommended to generate your own JWT embed tokens in your backend with a short expiration using your `secret` to make sure people can't be using embed URLs outside your app. +Charts must be explicitly allowed for embedding. Add charts to the allowed list in your embed settings. -To make this easier to integrate, we included some code snippets you can copy and use in your app to generate a valid embed URL. + +Chart embeds provide more granular access control than dashboards. Each chart must be individually allowed. + - - ![](/images/references/embed-developer-dcdab9d9082069f5ade377284254319c.png) - +## User attributes -Here is a demo of how to add the code snippet to your app: +User attributes enable row-level security by filtering data based on user properties. -

- +``` + +### Recommended attributes + +```html + +``` + +**Attributes explained:** +- `width="100%"` - Makes iframe responsive to container width +- `height="600"` - Fixed height (adjust based on content) +- `frameborder="0"` - Removes default border (legacy) +- `style="border: none;"` - Removes border (modern CSS) +- `loading="lazy"` - Defers loading until iframe is visible +- `title="..."` - Accessibility: Describes iframe content for screen readers +- `allowfullscreen` - Enables fullscreen mode (if your dashboard uses it) + +### Responsive iframes + +To make iframes maintain aspect ratio and scale responsively: + +**Method 1: Aspect ratio wrapper (16:9)** + +```html +
+ +
+``` + +**Method 2: Modern CSS aspect-ratio (16:9)** + +```html + +``` + +**Method 3: Fixed viewport percentage** + +```html + +``` + +### Dynamic height + +iframes have fixed height by default. For dynamic height based on content: + + +Lightdash embeds do not currently support automatic height adjustment via postMessage. Use a fixed height or viewport-based height (e.g., `80vh`). + + +Recommended approach for dashboards with unknown content: + +```html + +``` + +### Security considerations + +iframes provide natural security isolation, but you can add additional restrictions: + +```html + +``` + +**sandbox attributes:** +- `allow-scripts` - Required for Lightdash to function +- `allow-same-origin` - Required for Lightdash to function +- `allow-forms` - Required for filter interactions +- `allow-downloads` - Required if you enable CSV/image exports + + +The `sandbox` attribute provides additional security but may restrict functionality. Test thoroughly if you use it. + + +## Common patterns + +### Server-side rendering + +Generate embed URLs in your server-side templates: + +**Express (Node.js)** + +```javascript +app.get('/dashboard', authenticateUser, async (req, res) => { + const user = await getUser(req.user.id); + + const token = jwt.sign({ + content: { + type: 'dashboard', + dashboardUuid: 'dashboard-uuid', + }, + userAttributes: { + tenant_id: user.tenantId, + }, + }, process.env.LIGHTDASH_EMBED_SECRET, { expiresIn: '1h' }); + + const embedUrl = `https://app.lightdash.cloud/embed/${projectUuid}/dashboard/dashboard-uuid#${token}`; + + res.render('dashboard', { embedUrl }); +}); +``` + +**Template (EJS)** + +```html +
+ +
+``` + +### Single-page apps (SPA) + +Generate URLs via API when component mounts: + +**React example** + +```jsx +function EmbeddedDashboard() { + const [embedUrl, setEmbedUrl] = useState(null); + + useEffect(() => { + fetch('/api/dashboard-embed-url') + .then(res => res.json()) + .then(data => setEmbedUrl(data.url)); + }, []); + + if (!embedUrl) return
Loading...
; + + return ( + '; +} +add_shortcode('lightdash', 'lightdash_embed_shortcode'); +``` + +## Token refresh + +JWT tokens expire after the time specified in `expiresIn`. Handle token expiration: + +### Option 1: Long-lived tokens + +For public or semi-public dashboards, use longer expiration: + +```javascript +jwt.sign(payload, secret, { expiresIn: '7d' }) // 7 days +``` + + +Long-lived tokens are convenient but less secure. Use only when appropriate for your use case. + + +### Option 2: Regenerate URL on expiration + +Detect when iframe shows "Token expired" error and reload with new URL: + +```javascript +function refreshEmbed() { + fetch('/api/dashboard-embed-url') + .then(res => res.json()) + .then(data => { + document.getElementById('dashboard-iframe').src = data.url; + }); +} + +// Refresh before expiration (e.g., every 50 minutes for 1-hour tokens) +setInterval(refreshEmbed, 50 * 60 * 1000); +``` + +### Option 3: Backend proxy + +Create a backend endpoint that serves a static iframe URL but generates fresh tokens: + +```javascript +app.get('/embed-proxy/dashboard/:dashboardUuid', authenticateUser, (req, res) => { + const token = jwt.sign({ + content: { + type: 'dashboard', + dashboardUuid: req.params.dashboardUuid, + }, + }, process.env.LIGHTDASH_EMBED_SECRET, { expiresIn: '1h' }); + + const embedUrl = `https://app.lightdash.cloud/embed/${projectUuid}/dashboard/${req.params.dashboardUuid}#${token}`; + + // Redirect to actual embed URL + res.redirect(embedUrl); +}); +``` + +Then use: + +```html + +``` + +## Troubleshooting + +### Token not working + +**Issue:** iframe shows "Invalid token" or "Token expired" + +**Solutions:** +- Verify embed secret matches between token generation and Lightdash +- Check token hasn't expired (`expiresIn` in jwt.sign) +- Ensure JWT payload structure matches [embedding reference](/references/embedding#jwt-token-structure) +- Test token expiration: `jwt.decode(token)` and check `exp` field + +### Content not displaying + +**Issue:** iframe is blank or shows loading indefinitely + +**Solutions:** +- Check browser console for errors +- Verify dashboard/chart UUID is correct +- Ensure content is added to "allowed dashboards/charts" in Lightdash settings +- Check project UUID is correct +- Try accessing embed URL directly in browser to see error message + +### CORS errors + +**Issue:** Browser console shows CORS errors + +**Solution:** +- iframes should NOT have CORS issues (CORS only affects React SDK) +- If you see CORS errors with iframes, you may be using fetch/XHR to load content instead of iframe +- Use standard iframe src attribute, not JavaScript-based loading + +### URL encoding issues + +**Issue:** JWT token or URL appears malformed + +**Solutions:** +- Don't URL-encode the JWT token in the hash fragment +- If constructing URLs in templates, ensure proper escaping: + ```html + + + + + + ``` + +### Dashboard filters not working + +**Issue:** Users can't interact with filters despite `dashboardFiltersInteractivity: { enabled: 'all' }` + +**Solutions:** +- Verify JWT token includes correct interactivity settings +- Check browser console for JavaScript errors +- Ensure iframe isn't using `sandbox` attribute without `allow-forms` + +## See also + + + + JWT token structure and configuration options + + + + Alternative: React component embedding + + + + Step-by-step dashboard embedding guide + + + + Step-by-step chart embedding guide + + + + Row-level security with user attributes + + diff --git a/references/react-sdk.mdx b/references/react-sdk.mdx index a6823d70..c3894ffd 100644 --- a/references/react-sdk.mdx +++ b/references/react-sdk.mdx @@ -1,37 +1,54 @@ --- -title: "React SDK" -description: "Reference documentation for the Lightdash React SDK, used for Embedding. " +title: "Embedding with React SDK" +sidebarTitle: "React SDK" +description: "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 make the React SDK work, you need to update your "Cross-Origin Resource Sharing" (CORS) policy. +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, you'll need to contact the Lightdash team to update these for you. +This is done using environment variables. For Lightdash Cloud customers, contact the Lightdash team to update these for you. ```bash LIGHTDASH_CORS_ENABLED=true -LIGHTDASH_CORS_ALLOWED_DOMAINS=https://domain-where-you-are-going-to-use-the-sdk.com   +LIGHTDASH_CORS_ALLOWED_DOMAINS=https://domain-where-you-are-going-to-use-the-sdk.com ``` - **Why this is needed?** + **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 an 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. + 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. ```bash -npm install @lightdash/sdk   +npm install @lightdash/sdk # or -pnpm add @lightdash/sdk   +pnpm add @lightdash/sdk # or -yarn add @lightdash/sdk   +yarn add @lightdash/sdk ``` @@ -39,165 +56,524 @@ yarn add @lightdash/sdk   For Next.js, version 15 or later is required. -## Using the Lightdash SDK +## 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. -In your frontend project, import and use the `Lightdash.Dashboard` component in your desired location to mount the Lightdash dashboard. +#### Props + +```typescript +type DashboardProps = { + // Required + instanceUrl: string; // Your Lightdash instance URL + token: string | Promise; // 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 ```tsx import Lightdash from '@lightdash/sdk'; +function MyDashboard() { + return ( + + ); +} +``` + +#### With filters + +Apply filters programmatically using the `filters` prop: + +```tsx +import Lightdash, { FilterOperator } from '@lightdash/sdk'; + ``` -## Generating an embed token +See [Filtering data](#filtering-data) for complete filter documentation. -### Development +#### With styling -When developing you can quickly and easily [generate tokens through the Lightdash UI](https://docs.lightdash.com/references/embedding#embed-secret). Since this requires manual steps we don’t recommend you do this in production. +```tsx + +``` -### Production +#### With explore callback -To run the Lightdash SDK in production you need: +Track when users navigate to explore: -1. A frontend to embed the Lightdash dashboard. -2. A backend (or other privileged environment) where you can safely generate embedding tokens. This component will be able to generate access to any content, so this shouldn’t be accessible to your end users. +```tsx + { + console.log('User exploring chart:', chart.name); + // Track analytics, show help guides, etc. + }} +/> +``` -### JWT Authentication Flow +### Lightdash.Chart -![images/jwt-auth-flow.png](/images/jwt-auth-flow.png) +Embed individual saved charts for focused, single-metric displays with minimal UI. -To generate a signed JWT token, you need to use your **embed secret**, which is located in **Settings → Embed** in Lightdash. There, you can [generate or regenerate the secret](/references/embedding#embed-secret). This secret is used to sign JWT tokens, allowing secure use of the SDK. +#### Props -You can use the form to configure which **Dashboard** you want to show in the SDK, [enable specific features](/references/embedding#interactivity), and set up **User Attributes** for advanced security controls. For more details on **User Attributes**, check out the guide [here](https://docs.lightdash.com/references/user-attributes). +```typescript +type ChartProps = { + // Required + instanceUrl: string; // Your Lightdash instance URL + id: string; // Chart UUID (savedQueryUuid) + token: string | Promise; // 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 +}; +``` -#### Token Configuration + +Unlike Dashboard, Chart does not support `filters` or `onExplore` props since charts are read-only and cannot navigate to explore. + + +#### Basic usage -After you configure the form you should end up with the snippet which looks like this: +```tsx +import Lightdash from '@lightdash/sdk'; + +function MyChart() { + return ( + + ); +} +``` + +#### With styling + +```tsx + +``` + +#### Token generation for charts + +Charts require a JWT token with `type: 'chart'`: + +```javascript +// 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 +type ExploreProps = { + // Required + instanceUrl: string; // Your Lightdash instance URL + token: string | Promise; // 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 + +```tsx +import Lightdash from '@lightdash/sdk'; + +function MyExplore() { + return ( + + ); +} +``` + +#### With styling + +```tsx + +``` + +#### Token generation for explores + +Explores require `canExplore: true` in the JWT token: + +```javascript +// 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 ```typescript +// server/api/embed-token.ts import jwt from 'jsonwebtoken'; -const LIGHTDASH_EMBED_SECRET = '{{ keep this secret and do not expose it in the frontend }}'; -const projectUuid = '{{ your project uuid }} '; -const data = { +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: "none", - allowedFilters: undefined, - }, - canExportCsv: false, - canExportImages: false, - canExportPagePdf: true, - canDateZoom: false, - canExplore: false, - canViewUnderlyingData: false, + type: 'dashboard', + dashboardUuid: 'your-dashboard-uuid', + dashboardFiltersInteractivity: { + enabled: 'all', + }, + canExportCsv: true, + canExplore: true, + }, + userAttributes: { + tenant_id: user.tenantId, // Row-level filtering }, user: { - externalId: undefined, - email: "{{ authenticated user email }} " + externalId: user.id, + email: user.email, }, - userAttributes: {"":""}, -}; -const token = jwt.sign(data, LIGHTDASH_EMBED_SECRET, { expiresIn: '1 hour' }); + }, process.env.LIGHTDASH_EMBED_SECRET, { expiresIn: '1h' }); -console.log({ projectUuid, token }) - -// ^^^ use generated projectUuid and token in the ` - The Lightdash SDK works the same way as our embedding feature, which embeds the Lightdash dashboard as an “iframe”. We recommend reading the [documentation on Embedding](https://docs.lightdash.com/references/embedding/#code-snippet), which provides a detailed explanation of how token generation works and how to securely use Lightdash content using the SDK. - +### Frontend React component + +```tsx +import Lightdash from '@lightdash/sdk'; +import { useState, useEffect } from 'react'; + +function EmbeddedDashboard() { + const [token, setToken] = useState(null); + + useEffect(() => { + // Fetch token from your backend + fetch('/api/embed-token') + .then(res => res.json()) + .then(data => setToken(data.token)); + }, []); + + if (!token) return
Loading...
; + + return ( + + ); +} +``` - To ensure security, the JWT token generation code should run **in your backend**, and the **Lightdash embed secret** must never be exposed in frontend code. This prevents unauthorized access and protects sensitive data. + 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 -It’s possible to override some styles within the `` component to match the surrounding page better. Some styles will cascade, but some charts and components set things like `font-family` explicitly, so it is necessary to pass them to the component. Supported style overrides are: +Override styles within Lightdash components to match your application's design. + +### Supported style overrides + +```typescript +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. -- `fontFamily` - which will set all fonts within the dashboard to the specified font family. Note that only font family will be updated; font sizes and other properties will be preserved. -- `backgroundColor` - sets the background for the dashboard (not the tiles). This can be set to any color or `transparent` . +```typescript + +``` + + +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'`. + +```typescript + +``` -Both of these properties accept normal css values and are set on a `styles` object passed to the dashboard. For example: +### Complete example ```typescript ``` ## Filtering data -Filters can be passed to the `` to filter dimensions by values. Filters are passed as an array to the dashboard like this: +Filters can be passed to `` 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 + +```typescript +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 +``` + +### Multiple filters + +Filters are applied as AND operations: + +```javascript + ``` -Each entry in the array specifies +### FilterOperator enum -- `field` - the name of the dimension to filter by -- `model` - the model the dimension is a part of -- `operator` - the fitler operator, specified with the `FilterOperator` enum -- `value` - the value or values to fitler against. Some opperators, such as `IN_BETWEEN` expect an array, others take only a value +Import `FilterOperator` from the SDK: -Filter objects will each be applied as AND operations, each further restricting results. +```typescript +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 -Note that only field that are available for filtering will be filterable. These are specified in the token passed to the SDK. To generate such a token, see the Lightdash embed configuration. +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, an app simply needs to pass a correctly formatted translation object to the SDK. We recommend using the following tools (or similar) to create and manage translations efficiently: +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. These maps include keys and original text for all translatable strings in a dashboard, making them easy to use with translation tools like **Locize** or for manual translation. See below for details. -- **Runtime translation management**– In apps using the SDK, we recommend using a translation library like `i18next` to handle translation parameters and generate translation objects dynamically. See below for an example. -- **Translation production tools** – Tools like **Locize** help translators manage translations efficiently during production. Locize, for instance, can process translation objects from the Lightdash CLI translation maps and generate the dictionaries required by the SDK. These dictionaries can be included statically in the app or fetched dynamically from Locize servers. See the demo video below for an overview. +### Recommended tools -### Video overview of Localization +- **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