Distribute live dashboards in your websites and software

Domo Embed helps you distribute live dashboards in the websites and software where your customers and partners already spend time. These are supported methods to personalize embedded analytics so you can keep the data safe for you and relevant for them:



To ensure everyone only sees the authorized version of the data you have approved, Domo integrates SSO with any identity provider so users only have to login once.

Users are created in Domo to reflect the profiles that already exist in your systems. This can be done as a batch before launch of the embedded content. Otherwise, provisioning can be automated via the User API as viewers load the content for the first time.

Then PDP policies are created in the Domo platform. These policies narrow down the underlying datasets to only show the rows the viewer is authorized to see. That way, you can share a single version of the data and content while staying confident in the entitlement governance for each viewer.

This is the preferred method when users are more comfortable with the Domo web interface and less comfortable configuring server-side code.

Details on SSO integration can be found in the knowledge base:




Programmatic Filtering

If you prefer not to work through the licensing and provisioning of mirror users both in your systems and Domo, the main alternative is to persist the policies you have already setup in your systems by applying Programmatic Filters in server-side code. This way, you can still personalize embedded content for any number of viewers even if they do not have a Domo account.

This diagram summarizes the flow of tokens and data through the service account that acts as proxy for all other viewers. Steps 1-5 highlight the sequence of messages between your servers and the Domo API during Programmatic Filtering.


Drop-down filter examples:

Step 1. Point iframe to your server

A. Download the sample code from one of the example GitHub repositories to access even more detailed instructions in the readme file or check out example code:

  • The JavaScript version uses a Node.js repository


  • The ASP version is based on a .NET repository


  • Check out example Python code for Programmatic Filtering


  • Check out example PHP code for Programmatic Filtering


B. Open the “sample.html” file in the example code

  • Focus on this line: <iframe src=”http://localhost:3001/embed/item/1″ width=”1200″ height=”600″ scrolling=”no”></iframe>
    • When you are ready to move from testing to a production environment, replace localhost:3001 with the domain for your server
    • This can feel counter-intuitive at first since the default embed code is an iframe that points to the Domo instance
    • However, this temporary detour in your domain is how the server side code is processed before the final version of the embedded content is sent by Domo
  • Step 4 below will swap your domain with the Domo instance domain in the self-submitting HTML form

Step 2. Get access token

A. Activate an API client buy signing in to as the user who will serve as proxy for every other viewer:

Ensure this user has the relevant cards and pages shared with them before trying to embed content

B. Create an account by clicking My Account > New Client and filling out the fields as follows:

  • For more information about creating the CLIENT_ID and CLIENT_SECRET review the details in the following link:


C. Copy the IDs for the cards or dashboards from the embed dialog in Domo using the “private” authenticated option:

D. Create a file with a blank name and .env extension

  • Customize the configuration settings with your own values
    • Include “USE_XHR=true” only if cookie based authentication won’t work for the endpoint on your server.
    • The CLIENT_ID and CLIENT_SECRET is used to create the access token which will be used to then create an embed token for use with the private embed.
    • The EMBED_ID references the card or the dashboard you are embedding.
Best practices
This ID is NOT the one you can see in the URL of the Domo instance. It is the 5-character embed ID you can only copy from the embed dialog for that card or dashboard.
  • The EMBED_TYPE must be either the word ‘dashboard’ or ‘card’ (without the quotes).
  • Save the .env file in the same directory as the sample code

Step 3. Get embed token

A. Open the embed.js file

  • Notice it covers these functions:
    • “getAccessToken”
    • “getEmbedToken”
    • “returnEmbedInfo”
    • “handleRequest”
    • “refreshEmbedToken”
  • No customization should be required

Processing can be viewed from the command line when the testing environment is live (see step 5)

Deeper details on the possible requests and responses for the Embed API can be found here:


Step 4. Return html form

A. Open the file users.js in a text editor and modify the filter settings for each user to customize the filtering that each user will have applied to them.

  • Currently each user has an empty filter being applied to them “[]”.
    • There are some example filters in the file that are commented out that you can use that give you an idea of the format expected for the filters.
    • Once you make filter changes to the users.js file, you will need to save the file, restart the express server, refresh the page, and then log back in.

  • It is critical that the developer of the code understands the schema of the underlying dataset.
    • Otherwise, the query will fail and the api will respond with “Bad Request”.
    • This is to maintain the security of your server-side Programmatic Filters.
  • The complete list of available operators for use in filters are:
    • “IN”
    • “NOT_IN”
    • “EQUALS”
    • “NOT_EQUALS”

Step 5. Token and filter submitted in form

A. Navigate to the base folder where the repository was unzipped to install the necessary dependencies

  • Install nodejs


  • Install yarn


B. Start the express server by running the “yarn start” or “node express” command from the base folder of the project in Terminal / Command line.

  • Go to the url localhost:3001 in your browser and verify that you are able to see the card or dashboard after you login.
  • The available usernames are listed in the express.js file (“mike”, “susan”, “tom”, and “rachael”).
  • The password is not verified and so any will work.

App Embed Authentication

Safari has decided to block third party cookies:

In the past, we have worked around this through a “Safari Special Bouncepage” that used redirects to set the cookie. Safari now requires direct human interaction for the cookies to be set. Since embed authentication is meant to avoid such workflow interruptions, cookies are no longer a viable option in Safari.

The best way to conform with cookie restriction policies while still personalizing the embed experience is to use header-based authentication. The header can then access the tokens required to make the programmatic filter options for private embed effective even as other browsers eventually follow Safari’s example.

Although basic chart cards render if the programmatic filtering examples above are applied, embedded apps will also need this reference to the new token in their app.js code:

document.body.onload = () => {
  const token = window.__RYUU_AUTHENTICATION_TOKEN__;

  fetch(`/domo/environment/v1`, {
      method: 'GET',
      headers: {
        'X-DOMO-Ryuu-Token': token,
        'content-type': 'application/json'
    .then(res => res.json())

Best practices
For consistency, please ensure to maintain double underscores before and after the RYUU token as shown in the example code above.


NOTE: The app.js file that stores this code must be hosted in a folder called “public-assets” to be accessible by Domo. In the past that app.js file has usually been left in the root folder. After moving the file and references to this “public-assets” path, app creators will also want to check whether any sensitive business logic has been included in the app.js file. If so, simply move that logic to a different folder that requires authentication as documented here:

Dynamic Iframe Height

Setting the iframe height larger than the height of embedded dashboard is important to avoid scroll traps on mobile and double scroll bars on desktop. This is done by listening for the rendered height and setting the iframe container dynamically. Many embed customers choose to add a few more extra pixels to the height just to be sure the content is not pushed into a scrollable state. Here are two examples for how this can be done whether you have a single iframe or multiple iframes on the same page, as documented here.

Single iframe:

        window.addEventListener("message", receiveMessage, false);
        function receiveMessage(event) {
          //if we get some data back
          if ( && && document.getElementById("iframe1").style.height =;
        <iframe id="iframe1" src="" width="100%" height="1620" marginheight="0" marginwidth="0" frameborder="0"></iframe>

Multiple iframes:

         window.addEventListener("message", receiveMessage, false);
             function receiveMessage(event) {
                var frames = document.getElementsByTagName('iframe');
                for (var i =0; i <frames.length; i++) {
                   //loop through the responses and determine which came from which source
                    if (frames[i].contentWindow === event.source) {
                    if ( && && frames[i].style.height = + 15;
      <iframe id="iframe1" src=""width="100%" height="1620" marginheight="0" marginwidth="0" frameborder="0"></iframe>
       <iframe id="iframe2" src=""width="100%" height="1620" marginheight="0" marginwidth="0" frameborder="0"></iframe>

Dataset Switching

Dataset switching redirects dynamically change the underlying data of embedded dashboards. As long as column schema is consistent, server-side code can swap out the template dataset for the table relevant for the viewer. Most customers prefer to combine a master dataset across multiple customers and personalize the row access with PDP. However, dataset switching is helpful when that combined dataset simply is not an option.

Dataset switching redirect with no programmatic filters for rows

visualization1: {
  clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, embedId: process.env.EMBED_ID1,
    datasetRedirects: {

Dataset switching redirect layered with programmatic filters for rows

visualization1: {
    clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, embedId: process.env.EMBED_ID1,
       datasetRedirects: {
     filter: {"@type":"IN","leftExpression":{"@type":"COLUMN","columnName":"color"},"rightItemsList":{"@type":"EXPRESSION_LIST","expressions":[{"@type":"STRING_VALUE","value":"red"}]}}