A Mode report can be embedded into another website, such as a private wiki, blog, or any other website or application with access to the internet. An embed will display the full contents of the underlying report including charts, tables, and other custom visualizations. Any report can be embedded as either an Internal Embed or a White-Label Embed (WLE), depending on your needs.

Internal Embed

An Internal Embed built using your private data is only visible to logged-in members of your Mode organization who would otherwise have access to the underlying report. Here’s an example of what an Internal Embed looks like:

Click the green Powered by Mode link at the bottom of the embed to open the underlying report in Mode.

NOTE: Generally, you must be logged in to Mode and have access to the underlying report in order to view an Internal Embed. However, the above embedded report is built on Mode’s Public Warehouse and is therefore viewable by anyone on the internet. Learn more about embedding reports built on Mode’s Public Warehouse.

White-Label Embed

A White-Label Embed (WLE) may be seen by viewers who are not logged in to Mode or members of your organization who do not have access to the underlying report. For a given embed, your host application securely controls who can see what using a signature process (and optionally, using parameters).

A White-Label Embed differs from an Internal Embed in a few key ways:

  • No Mode viewer authentication: With WLEs, the embed host application, instead of Mode, handles any required viewer authentication and programmatically controls access to the embedded reports by generating a unique, rapidly-expiring signed embed URL and (optionally) parameters.
  • No Mode branding: There is no Mode Analytics in the embed border or loading animation.
  • Reduced viewer interactivity: Some interactive features of Mode’s built-in charts and tables are not available, including some drill-down features and chart-specific URLs.
  • Reduced underlying data access: To prevent unintentional leakage of sensitive data, viewers cannot see any of the underlying report’s metadata, code, historical runs, or query results. You may, however, elect to expose the ability for viewers to download a CSV of the embedded report’s results in your host application.
Example implementation

To show a White-Label Embed in action, we built a lightweight analytics portal for a fictional paper company named Parch & Posey. The analytics in the portal are provided by two parameterized and White-Label Embedded Mode reports.

Access the Parch & Posey example portal using any of the following credentials:

Username Password
walmart pw
merck pw
utc pw

When accessed, the portal runs the embedded reports with a parameter value specific to the logged-in customer. This means that the embeds will display data only for the logged-in customer. If a viewer attempts to change the embed URL in any way (including the parameter value) and then access the URL, the signature will no longer be valid and the URL will return an error.

The report shown on the “Overview” tab is built entirely with built-in visualizations. The report on the “All Orders” tab is built with a custom D3 visualization.


To embed a report, the following requirements must be met:

  • The Mode organization containing the target report must be on a paid plan.
  • If you plan to implement a White-Label Embed, White-Label Embeds must be included in your organization’s paid plan.
  • The creator of the embedded report must be an active member of the same Mode organization that contains the report.

Implementation steps

Embed a Mode report into a host application by following the steps below.

Create an embed URL

An embed can point to either a standard report URL (which displays results from the most recent report run) or a static report run URL (which displays results from a specific run).

TIP: Static report run URLs always include /runs/[RUN_TOKEN]/ in the URL path.

Obtain the the URL that suits your specific case and add /embed to the end of the path, for example:

<!-- Report URL (always shows latest run) -->

<!-- Static Report Run URL (always shows a specific run from a point in time) -->

Set refresh frequency

Control how often your embed refreshes by specifying a max_age in the embed URL query string. The max_age specifies the maximum allowable age, in seconds, that a cached report run’s results may be:

  • If the report has never run or the most recent run of the report is older than the specified number of seconds, the report will be fully run when accessed. Otherwise, the most recent report run results from Mode’s servers will be returned.
  • If the URL query string includes values for parameters, Mode will return the most recent cached results using the same set of parameter values as long as those results are not older than the value of max_age. If the report has never been run with the specified parameter values, Mode will run the report using them.

This ensures the embedded report’s data is refreshed as regularly as necessary while allowing you to balance the load the embed places on your database. For example, including max_age=3600 in the URL query string ensures that the underlying report will refresh once the most recent results are more than 3600 seconds (i.e., one hour) old.

TIP: A valid embed URLs must include a max_age. To ensure the embedded report’s data is refreshed every time the embed is accessed, specify max_age=0.

The following example URL will update all queries and visualizations in the target report if it was last run over 3600 seconds (i.e., 1 hour) prior to being accessed:


Specify parameter values (if required)

A field-value pair must be provided for each report parameter, if any are defined in the underlying report. For example:

<!-- Example embed URL query string with a text parameter -->

To include one or more values for a multiselect parameter in your report’s URL query string, each individual value must be passed as it’s own key-value pair. For example:

<!-- Example embed URL query string with multiple values for a multiselect parameter -->

Important notes:

  • Remember to URL encode any special characters in the URL’s query string, including parameter values and the [] in multiselect parameter keys.
  • Parameter keys and values are case sensitive.
  • Parameter keys should be ordered alphabetically in the URL.

Sign the embed URL (WLE only)

IMPORTANT: The following steps only apply if you are implementing a White-Label Embed. If you are implementing an Internal Embed, skip to the next step.

To create a signed embed URL, follow the steps below to add three fields to the query string: a timestamp, a signature token access_key, and a unique signature that your host application generates each time the embed is rendered.

Before you begin, ensure your back-end environment has access to the following information:

  • Signature token: Generated by an admin of the organization that contains the target report. Ensure you have both the public access key and private access secret.
  • Embed URL: Includes the full path and query string (from the first two steps of this guide).
  • Dynamic parameter values: All parameter values, including dynamically generated ones from your application’s database, (e.g., customer ID, etc.) must be URL encoded. You’ll need these values to build the request URL (outlined in step 2 below).
  • Current timestamp: The current time, in seconds, in UNIX epoch time.

IMPORTANT: Your host application must create the signature using a process that is not transparent to embed viewers. Exposing your signature token’s access secret in front-end, client-side code will compromise the security of your Mode account.

1. Enable WLE for the report

White-Label Embedding must be explicitly enabled on a report-by-report basis. To enable it:

  1. Open the report that you want to White-Label Embed and click Edit in the header.
  2. Select Embed in the header.
  3. In the pop-up, click the White-Label Embed tab.
  4. Toggle the switch so it says White-Label embedding of this report is ON.

TIP: If you don’t see the White-Label Embed tab, your organization does not have White-Label Embeds enabled. Contact your organization’s Mode admins or Mode support to learn more about enabling White-Label Embeds.

2. Build request URL

To create a valid request URL from an embed URL:

  1. Add the timestamp and access_key fields to the query string, set equal to the current UNIX epoch time and the signature token access key, respectively.
  2. Sort the query string alphabetically by field name.

For example:

<!-- Embed URL (suitable for an Internal Embed) -->

<!-- Request URL (used to generate the signature) -->
                             ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^           ^^^^^^^^^^
                              Access key            Sorted alphabetically                    UNIX epoch time
3. Generate a signature

To sign your WLE embed URL, you must first construct a request_string. This request_string will be hashed to create the signature.

A request_string consists of a constant (GET,,1B2M2Y8AsgTpgAmY7PhCfg==), your request URL, and the current timestamp, separated by commas. For example:

<!-- Request string structure -->

<!-- Example request string -->

IMPORTANT: The fields in the request_url query string must be in the order given above (i.e., sorted alphabetically) or the signature will be invalid.

Now, generate a signature by creating a base64-encoded SHA256 hash of the request_string using the signature token access secret as the secret (i.e., hashing key). For example:

import hmac
import hashlib

signature = hmac.new(secret, msg=request_string, digestmod=hashlib.sha256).hexdigest()
const crypto = require('crypto');

var signature = crypto.createHmac('sha256', secret).update(requestString).digest('hex');
require 'openssl'

digest = OpenSSL::Digest.new('sha256')
signature = OpenSSL::HMAC.hexdigest(digest, secret, request_string)
$signature = hash_hmac('sha256', $request_string, $secret, false);
4. Create a signed embed URL

Create a signed embed URL by adding the signature field, set equal to the signature generated in the previous step, to the end of the query string of the request_url. For example:

<!-- Request URL (used to generate the signature) -->

<!-- Signed embed URL (suitable for White-Label Embed) -->
                       Unique signature generated at run time

The signed embed URL will now provide access to the specified report. If any part of the URL is changed or if the signature expires (which happens after 10 seconds), your host application must regenerate the signature.

Example code

The following examples show how to assemble a request_string and generate a signed embed URL given a signature token access_key and access_secret, a timestamp, and a request_url with all components of the query string already in alphabetical order:

import md5
import hmac
import base64
import hashlib

def sign_url(url, key, secret, timestamp):
  request_type = 'GET'
  content_type = ''
  content_body = ''
  content_hash = md5.new(content_body).digest()
  content_digest = base64.encodestring(content_hash).strip()

  request_string = ','.join([request_type, content_type, content_digest, url, str(timestamp)])

  signature = hmac.new(secret, msg=request_string, digestmod=hashlib.sha256).hexdigest()

  signed_url = '%s&signature=%s' % (url, signature)
  return signed_url

sign_url(request_url, access_key, access_secret, timestamp)
const crypto = require('crypto');

function signUrl(url, key, secret, timestamp) {
    var requestType = 'GET';
    var contentType = null;
    var contentBody = '';
    var contentDigest = crypto.createHash('md5').update(contentBody).digest().toString('base64');

    var requestString = [requestType, contentType, contentDigest, url, timestamp].join(',');

    var signature = crypto.createHmac('sha256', secret).update(requestString).digest('hex');

    var signedUrl = url + '&signature=' + signature;
    return signedUrl

signUrl(request_url, access_key, access_secret, timestamp);
require 'digest'
require 'openssl'

def sign_url(url, key, secret, timestamp)
  request_type = 'GET'
  content_type = nil
  content_body = ''
  content_digest = Digest::MD5.base64digest(request_body)

  request_string = [request_type, content_type, content_digest, url, timestamp].join(',')

  digest = OpenSSL::Digest.new('sha256')
  signature = OpenSSL::HMAC.hexdigest(digest, secret, request_string)

  signed_url = "#{url}&signature=#{signature}"

sign_url(request_url, access_key, access_secret, timestamp)
function signUrl($url, $key, $secret, $timestamp) {
    $request_type = 'GET';
    $content_type = '';
    $content_body = '';
    $content_digest = base64_encode(pack('H*', md5($content_body)));

    $request_array = array($request_type, $content_type, $content_digest, $url, $timestamp);
    $request_string = implode(',', $request_array);

    $signature = hash_hmac('sha256', $request_string, $secret, false);

    $signed_url = "{$url}&signature={$signature}";
    return $signed_url;

> echo signUrl($request_url, $access_key, $access_secret, $timestamp);

Place the embed URL into an iframe

To finish creating your embed, add an iframe to your host application with the src attribute set equal to the embed URL (for an Internal Embed) or signed embed URL (for a White-Label Embed). For example:

<!-- iframe with Internal Embed -->

Remember to adjust the height attribute so that the embed results are visible. You can also use Mode’s JavaScript embed helper library to dynamically set the height.

If you are implementing a White-Label Embed, your back-end code will need to update the src attribute of the iframe with the dynamically-generated signed embed URL whenever the page loads or whenever the embed needs to be reloaded.

Testing and troubleshooting

Most issues with embeds stem from problems with generating the embed URL signature or other parts of the embed URL. Mode offers a number of resources to help you test and troubleshoot White-Label Embeds:

Common techniques

HTML embed snippets

To help you get started, Mode can generate code snippets including template code that you can customize and include in your host application. Open the report editor for the report you want to embed and click Embed in the header to generate code snippets for one of two types of embed methods:

Static iframe

Embeds using a static HTML iframe do not require the execution of any client-side JavaScript and therefore may be more suitable for use with certain blogs or content management systems. However, you must set the height of the iframe manually using the height attribute of the <iframe> (default is 300px). For example:

<iframe src="https://app.mode.com/modeanalytics/reports/e2e53f08ba18/embed" width="100%" height="300" frameborder="0"></iframe>

If your embed host application allows for client-side JavaScript, you can use the JavaScript embed method. The JavaScript snippet includes a helper library that automatically produces an iframe for the embed with the class mode-embed. For example:

<a href="https://app.mode.com/modeanalytics/reports/e2e53f08ba18/embed" class="mode-embed">Mode Analytics</a>
<script src="https://app.mode.com/embed/embed.js"></script>

The helper library adds the following inline styles to each iframe: width: 100%;, and height set dynamically based on the underlying report’s content.

TIP: If your host application has multiple embeds on a single page and you use this method, you only need to include the helper library once.

Parameter forms

The automatically-generated form at the top of a report containing parameters will not render in an embed. However, you can add interactive HTML elements to your host application (e.g., buttons, drop-down menus, etc.) that viewers can manipulate, and then use JavaScript to update the parameter values in the embed URL, re-sign, and subsequently refresh the embed.

An example of this can be seen in the Parch & Posey example portal.

CSV and PDF export

When a White-Label Embed loads successfully, it will post a JSON response. That response contains URLs that can be used to obtain a CSV or PDF of the data that was returned by the embedded report. Only the results returned by the database to the embed, not the underlying data, are included.

In your application, you can add an event listener to retrieve these URLs and expose them using any element on the page.

For example, the following JavaScript listens for the embed response from Mode, retrieves the CSV and PDF download URLs, and assigns them as the targets of a couple of corresponding <a> elements:

<a id="csv-export-link" href=""> CSV Export </a>
<a id="pdf-export-link" href=""> PDF Export </a>

  window.addEventListener('message', function (e) {
    // always check the origin and make sure it is from app.mode.com
    if (e.origin === 'https://app.mode.com') {
      if (e.data['type'] == 'reportExportPaths') {
        var modeBaseUrl = e.origin

        // CSV Export
        var csvExportUrl = e.data['report_csv_export_path']
        csvExportLink = document.getElementById('csv-export-link')
        csvExportLink.href = modeBaseUrl + csvExportUrl

        //PDF Export
        var pdfExportUrl     = e.data['create_report_pdf_export_path']
        pdfExportLink = document.getElementById('pdf-export-link')
        pdfExportLink.href = modeBaseUrl + pdfExportUrl

Unique CSV and PDF download URLs are generated every time a White-Label Embed renders and they expire after 24 hours. If the White-Label Embed fails to load for any reason, the embed will not post a response containing these URLs.

Filter panel toggle

Internal Embeds feature a branded Mode border, which includes a Filters button in the lower right corner that you can use to toggle the filter panel open or closed.

For White-Label Embeds, you can programmatically expose or hide the filter panel (if applicable) by posting a message to the embed iframe using JavaScript. For example:


function toggleFilterPanel(reportToken){
    var messageOptions = {
        type: 'reportFilterPanelDisplay',
        wleFilterPanelToggle: true
    window.document.querySelector('iframe[data-report="'+reportToken+'"]').contentWindow.postMessage(messageOptions ,'*');

You can also easily add a filters toggle button for a White-Label Embed to your host application. Simply attach the invocation to another UI element somewhere on the host application’s page:

<a href="#" onclick="toggleFilterPanel('[REPORT_TOKEN]')">Show Filters</a>

Styling and branding

You can use a custom theme or CSS to style an embedded report so its look and feel matches that of its host application.

Learn more about how to style reports using custom CSS.

Hide a report element

You can instruct an embed to hide individual report elements by adding the embed-hidden class to it using the HTML editor. The following example is the HTML for a report with two side-by-side charts:

<div class="mode-grid container">
  <div class="row">
    <div class="col-md-6">
      <!--This chart will be visible if the report is accessed in Mode and when rendered in an embed-->
      <mode-chart id="chart_c5eff481380d" dataset="dataset" options="chart_options"></mode-chart>
    <div class="col-md-6">
      <!--This chart will be visible if the report is accessed in Mode, but NOT when rendered in an embed-->
      <mode-chart id="chart_0d486a3942b3" class="embed-hidden" dataset="dataset" options="chart_options"></mode-chart>

The embed-hidden class is automatically added to the <div> that contains the report’s name and description. Accordingly, these are not rendered by default in an embed.

IMPORTANT: Attaching the embed-hidden class to an element hides it when an embed renders but does not prevent that element’s contents from being transmitted to the host application page. These contents will still be accessible if the host application viewer inspects the page.

Embedding reports built using the Mode Public Warehouse

Any Mode user can create an embed from a report built with data from the Mode Public Warehouse, even if the report is in an organization that is not on a paid Mode plan. However, the following limitations apply:

  • The underlying report must be in a community Space and therefore may only use data contained in the Mode Public Warehouse.
  • Parameter values cannot be set using the embed URL’s query string.
  • The run=now and max_age fields cannot be used in the embed URL’s query string. In other words, you cannot set these embeds to run upon view nor to refresh when they reach a certain age.

Anyone can view an embedded report built using Mode Public Warehouse data when it is in a community Space, even if they are not logged in to Mode or do not have a Mode account.

Last updated March 13, 2019