Deployment
Embedding dashboards

Embedding Dashboards

Once you’ve published your dashboard in Embeddable, you can embed it in any website or web app - simply load our web component and pass in a security token.

How it works

Publish Your Dashboard

In the Embeddable builder, click Publish. This prepares the dashboard for embedding.

Insert Our Web Component

Add the following to your page's <head> to load the Embeddable custom element:

<head>
  <link rel="preconnect" href="https://static-data.<region>.embeddable.com" crossorigin>
  <script
    type="module"
    src="https://embed.embeddable.com/js/v1/?region=<region>">
  </script>
</head>

This makes the <em-beddable> tag available anywhere on your page.

Learn more about region here.

Place the <em-beddable> Element

Anywhere in your HTML, include:

<em-beddable
  token="eyJhbGciOiJIUzI1NiJ9..."
></em-beddable>

token is a security token from our Tokens API, which is used for row-level security and more.

Test Embedding

The quickest way to test embedding is to use our test script here.

Example: In a Plain HTML Page

<!DOCTYPE html>
<html>
  <head>
    <link rel="preconnect" href="https://static-data.<region>.embeddable.com" crossorigin>
    <script
      type="module"
      src="https://embed.embeddable.com/js/v1/?region=<region>">
    </script>
  </head>
  <body>
    <em-beddable
      token="eyJhbGciOiJI..."
    ></em-beddable>
  </body>
</html>

Learn more about region here.

Learn how to retrieve a token here.


Embedding in a React App

If you’re using React, treat <em-beddable> like any other custom element. For example:

function Embeddable({ token }: { token: string }) {
  // Return a custom element
  return React.createElement('em-beddable', { token });
}
 
export default function DashboardPage() {
  const securityToken = 'eyJhbGciOiJI...'; 
  return <Embeddable token={securityToken} />;
}

Or using JSX directly:

import { Helmet } from 'react-helmet';
 
export default function DashboardPage() {
  return (
    <>
      <Helmet>
        <link
          rel="preconnect"
          href="https://static-data.<region>.embeddable.com"
          crossOrigin="anonymous"
        />
        <script
          type="module"
          src="https://embed.embeddable.com/js/v1/?region=<region>"
        />
      </Helmet>
      <div>
        <em-beddable token="eyJhbGciOiJI..." />
      </div>
    </>
  );
}

Learn more about region here.

Learn how to retrieve a token here.

Using TypeScript

When embedding in TSX, you may get the following error:

Property 'em-beddable' does not exist on type 'JSX.IntrinsicElements'. ts(2339)

To fix this, you need to add a JSX element type declaration. You can either add this directly above a react component in the same file, or put it in a global types module.

declare module 'react' {
  namespace JSX {
    interface IntrinsicElements {
      'em-beddable': DetailedHTMLProps<
        HTMLAttributes<HTMLElement>,
        HTMLElement
      > & {
        token: string;
        variables?: string;
        'client-context'?: string;
      };
    }
  }
}

This code ensures the <em-beddable> tag is recognized by TypeScript, and that you get correct type-checking on its props.

Using Next.js

Use the next/head component to add the preconnect and script to the document head:

import Head from 'next/head';
 
export default function DashboardPage() {
  return (
    <>
      <Head>
        <link
          rel="preconnect"
          href="https://static-data.<region>.embeddable.com"
          crossOrigin="anonymous"
        />
        <script
          type="module"
          src="https://embed.embeddable.com/js/v1/?region=<region>"
        />
      </Head>
      <div>
        <em-beddable token="eyJhbGciOiJI..." />
      </div>
    </>
  );
}

Learn more about region here.

Learn how to retrieve a token here.

Embedding in an Angular App

In Angular, you can use the <em-beddable> element in your templates. For example:

<em-beddable
  token=" eyJhbGciOiJI..."
></em-beddable>

Make sure you've added the following to your index.html's <head>:

<head>
  <link rel="preconnect" href="https://static-data.<region>.embeddable.com" crossorigin>
  <script
    type="module"
    src="https://embed.embeddable.com/js/v1/?region=<region>">
  </script>
</head>

Learn more about region here.

Learn how to generate a token here.

Angular by default sanitizes unknown attributes on elements, which can interfere with passing attributes to your embeddable (eg it may remove the client-context attribute). There are several ways to work around this, but we recommend either using Angular's DomSanitizer (opens in a new tab) to bypass security for the specific attributes you need, or creating a custom directive to handle setting the attributes on the <em-beddable> element, like this:

// App.ts
import { Component, CUSTOM_ELEMENTS_SCHEMA, signal } from '@angular/core';
import { RouterOutlet } from '@angular/router';
 
@Component({
  imports: [RouterOutlet],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  selector: 'app-root',
  templateUrl: './app.html',
})
export class App {
  /* Methods */
  protected readonly clientContext = signal(
    JSON.stringify({ theme: 'light' })
  );
}
<!-- app.html -->
<!-- ... -->
<em-beddable
  token="eyJhbGciOi..."
  [attr.client-context]="clientContext()"
  style="width: 100%">
</em-beddable>
<!-- ... -->

Embedding in a Vue App

In Vue, you can place <em-beddable> in your templates. For instance:

<template>
  <em-beddable
    :token="token"
  />
</template>
 
<script setup lang="ts">
import { ref, onMounted } from 'vue';
 
const token = ref('eyJhbGciOiJI...');
 
onMounted(() => {
  // Load the web component script if needed, or include in index.html
});
</script>

Make sure you've added the following to your index.html's <head>:

<head>
  <link rel="preconnect" href="https://static-data.<region>.embeddable.com" crossorigin>
  <script
    type="module"
    src="https://embed.embeddable.com/js/v1/?region=<region>">
  </script>
</head>

Learn more about region here.

Learn how to generate a token here.

Vue by default sanitizes user input, which can interfere with passing attributes to your embeddable (eg it may remove values you're passing to the client-context attribute). To avoid this, Vue offers several methods to bind attributes safely (opens in a new tab).

Common Pitfalls

  • Security Token: Must be retrieved server-side to avoid exposing secrets. See our Tokens API docs.

  • Z-Index Issues: When embedding multiple dashboards on a single page, z-index conflicts can happen if the value isn't explicitly set. To resolve this, ensure that each <em-beddable> element has appropriate z-index settings and is set to position: relative. The Embeddables that appear higher on the page must have a higher z-index value than those that appear lower on the page, like in this example:

<div class="container">
  <!-- First dashboard with higher z-index -->
  <em-beddable token="..." style="position: relative; z-index: 2"></em-beddable>
  <!-- Second dashboard with lower z-index -->
  <em-beddable token="..." style="position: relative; z-index: 1"></em-beddable>
</div>

Complete Working Example

See our web-component-example repo (opens in a new tab) for a live demonstration, including how to fetch a security token from the Tokens API and embed it in a fully functional page or app.