Skip to main content

Embedded Analytics

Introduction

Embedded Dashboard

Embedded Analytics helps you integrate a Holistics dashboard into your own web application, as if the dashboard is a part of your application itself. This is a popular use case for B2B companies where you need to deliver analytics to your customers.

  • Your engineers do not need to build custom analytics dashboard from scratch.
  • Your viewers/users can have access to their app statistics from your app without logging into Holistics.
  • Prevent data leakage: your viewers can only see data that you allow them to see.
  • White-labeling: Remove Holistics’ logo so you can keep your brand consistent in your applications.

How it works

On the front-end side, Holistics dashboard is embedded into your application using iframe. The iframe's URL contains an identification code (embed_code), and a time-sensitive token which define how viewers see the dashboard.

On the backend side, you need to generate the token based on the settings of your dashboards, the permissions that you want to grant to your logged in user, the filters that you want them to use... With our Embedded Sandbox, you can interactively produce the backend code to generate the token.

High-level Mechanism

The high-level workflow to embed a Holistics dashboard is as follow:

  1. Create Embed Link for the dashboard: This step will generate an embed_code to identify your dashboard, and a secret_key which will be used to generate a token
  2. Generate token in backend: Using Embedded Analytics Sandbox, you can interactively generate backend code to produce a token. The token is contains information about your dashboard, like dashboard settings, filter's default values, user's permissions... These information is encoded with JSON Web Token (JWT).
  3. Embed dashboard in frontend: With embed_code and token, you can construct the dashboard's embed URL, and embed it to your frontend via an iframe. Code for the iframe is also provided in the Embedded Analytics Sandbox.

Step-by-step Guide

Notes:

We will use Ruby in this guide, but the basic concepts will be the same no matter what language you use for your websites/applications.

0. Enable Embedded Analytics

By default, Embedded Analytics feature is not enabled in your account. To enable it, click on Tools -> Embedded Analytics -> Turn on Embedded Analytics feature.

Once enabled, you can also set the amount of embed workers that you want to employ.

To embed the dashboard, you will need an Embed Link which looks something like this:

https://secure.holistics.io/embed/<%= embed_code %>?_token=<%= token %>

This link will be included in the final HTML iframe snippet to be added to your websites / applications. Explanation for the variables in the link:

  • embed_code: the unique identification code for the dashboard you want to embed.
  • token: the embed token controls what users can see, and what permissions they have.

To obtain the embed_code value, from your Dashboard select Settings -> Dashboard Preferences -> Embedded Analytics, and click on Generate Embed Link. You will be presented with the Embed Code and Secret Key:

The Secret Key will be used to generate the embed token later.

Next, we can start generating the embed script with the Embedded Analytics Sandbox

2a. Build Payload Code (Backend)

The Embedded Analytics Sandbox is where you can interactively generate the basic embed script.

In the Embed Settings section, you can toggle and add various configurations to the embedded dashboard. Please refer to the dedicated documentations for details on these settings:

Your configuration here will be reflected to the script in the Embed code section. The following videos demonstrate the process:

Permission Settings

For example, if you added a permission rule that only show data from Vietnam:

The following code snippet will be generated:

permissions = {
row_based: [
{
path: {
dataset: "ecommerce",
model: "countries",
field: "name"
},
operator: "is",
modifier: nil,
values: [
"Vietnam"
]
}
]
}
Controls Settings

For example, for the Created At filter, if you set the default value to matches last 6 months:

The following code snippet will be generated:

filters = {
created_at: {
hidden: false,
default_condition: {
operator: "matches",
values: [
"last 6 months"
],
modifier: nil
}
},
...
# Other controls settings
}

Your settings in this section will take precedence over the filter's default values in the original dashboard.

The generated script is not production-ready

You will need to customize it to suit your business needs before adding it to your websites / applications.

2b. Generate Token (Backend)

After configuring all settings, you need to generate a token to be included in the final embed link. You can do so by adding the following snippet to the embed script:

backend.rb
# Will expire after 1 day, change it to the value you want.
# Note that expired_time is of type Unix Time. E.g 1498795702

expired_time = Time.now.to_i + 24 - 60
secret_key = '43fec4fXXXXXXX'

payload = {
settings: settings,
permissions: permissions,
filters: filters,
exp: expired_time
}

token = JWT.encode(payload, secret_key, 'HS256')

Variables used in this snippet:

  • expired_time: The time you set the token to be expired
  • secret_key: Obtained from earlier of the dashboard
  • settings, permissions, filters: Defined in the previous section

3. Integrate iFrame to App (Frontend)

Finally, we have a full script that can be added to your websites / applications.

Full Ruby script (Example)
country = []
store = []

# current_user is to get the current user logged in

if current_user.email == "[email protected]"
country = []
store = []
elsif current_user.email == "[email protected]"
country = ['Vietnam']
store = ['6', '7', '8']
end

# Define permissions
permissions = {
row_based: [
{
path: "ecommerce.ecommerce_countries.name",
operator: 'is',
values: country
},
{
path: "ecommerce.ecommerce_cities.name",
operator: 'is',
values: city
},
{
path: "ecommerce.ecommerce_merchants.id",
operator: 'is',
values: store
}
]
}

# Configure filters
filters = {
city_name: {
hidden: false,
default_condition: {
operator: "is",
values: [],
modifier: null
}
},
country: {
hidden: false,
default_condition: {
operator: "is",
values: [],
modifier: null
}
},
merchant_id: {
hidden: false,
default_condition: {
operator: "is",
values: [],
modifier: null
}
},
order_date: {
hidden: false,
default_condition: {
operator: "matches",
values: [
"last 6 months"
],
modifier: null
}
},
order_status: {
hidden: true,
default_condition: {
operator: "is",
values: [
"delivered"
],
modifier: null
}
}
}


# Generate token
expired_time = Time.now.to_i + 24 - 60
secret_key = '43fec4fXXXXXXX' # Obtained from dashboard's embed settings

payload = {
permissions: permissions,
filters: filters,
exp: expired_time
}

token = JWT.encode(payload, secret_key, 'HS256')

The HTML iframe to be included in your HTML file will look something like this:

embedded_frontend.html.erb - Your frontend code
<iframe src="https://secure.holistics.io/embed/<%= embed_code %>?_token=<%= token %>"
style="width: 100%; height: 600px;"
frameborder="0"
allowfullscreen>
</iframe>

Configure User-level Permission (Advanced)

If you want to show the user only the data they should have access to, you can make use of the current_user variable to write your permission rules. For example, in an E-commerce company, we want:

  • General Manager can see data of all stores
  • Vietnam Manager can see data of stores in Vietnam only

We will need make sure that that each user (logged in with a unique email) is associated with a different set of values for country and store:

Ruby script
country = []
store = []

# current_user is to get the current user logged in

if current_user.email == "[email protected]"
country = []
store = []
elsif current_user.email == "[email protected]"
country = ['Vietnam']
store = ['6', '7', '8']
end

permissions = {
row_based: [
{
path: "ecommerce.ecommerce_countries.name",
operator: 'is',
values: country
},
{
path: "ecommerce.ecommerce_cities.name",
operator: 'is',
values: city
},
{
path: "ecommerce.ecommerce_merchants.id",
operator: 'is',
values: store
}
]
}


Let us know what you think about this document :)