Are there any organizations out there that are using the Looker API as a data feed to end-user analysts?
We are looking to do just that in the near future. Currently, we are embedding SSO dashboards, creating users, setting up access filters. We will be working on creating and running queries and downloading data.
I’m implementing a .NET SDK for the Looker API. We have successfully generated the code using Swagger Codegen. You can see my post on Generating .NET Clients
Broadcasting Embedded Dashboard Events to the Parent Page
Looker provides a way to allow an embedded dashboard to broadcast events to the parent page using the embedded dashboard API. This works when the dashboard is embedded using the <iframe />
tag in HTML.
Getting set up
Get the embedded dashboard URL
First, we need to get the embed URL for the dashboard.
Navigate to a dashboard you want to embed.
Copy the URL from the browser navigation bar.
Add
/embed
to the URL just before/dashboards/
.
For instance, if the original URL was:https://mydomain.com/dashboards/...
then change the URL to:
https://mydomain.com/embed/dashboards/...
Make sure to leave the rest of the domain as it is.
You must add the URL parameter
embed_domain
with the domain of the parent page, for instance:
https://mydomain.com/embed/dashboards/52?embed_domain=https://parentpagedomain.com
or
https://mydomain.com/embed/dashboards/52?[some other parameters]&embed_domain=https://parentpagedomain.com
NOTE: This domain must match a whitelist of domains as entered by an admin for your Looker instance. An admin may go to
https://[yourinstance]/admin/embed
to access this setting.
Load the dashboard in an iframe
tag
Use an iframe to load the embedded dashboard into your parent page. Replace [embedded dashboard URL]
with the URL you created above:
<iframe id="looker" width="500" height="500" src="[embedded dashboard URL]"></iframe>
For example, to embed this dashboard:
https://lookerinstance.com/dashboards/23
on a page hosted at https://parentdomain.com
, the embed code would look like this:
<iframe id="looker" width="500" height="500" src="https://lookerinstance.com/embed/dashboards/23?embed_domain=https://parentdomain.com"></iframe>
Listen to message events on the window
The <iframe>
embedded page will use JavaScript’s postMessage
method to send event data which can be captured by listening to those events. To receive these events, add an event listener to the parent window like this:
window.addEventListener("message", function (event) {
if (event.source === document.getElementById("looker").contentWindow) { // confirm message came from Looker
console.log(JSON.parse(event.data));
}
});
If you are using jQuery this could look like this:
$(window).on("message", function (event) {
if (event.source === $("#looker")[0].contentWindow) { // confirm message came from Looker
console.log(JSON.parse(event.data));
}
});
NOTE: Other iframes could also be sending data to your page’s window. As shown above, make sure to confirm that the source of the message was the iframe with the embedded Looker dashboard before you parse the data.
Explore the data sent from the dashboard
The callback function will receive the event
object. To get to the data you want, you will need to parse event.data
which has all of the data of interest to you. As shown earlier, you use JSON.parse(event.data)
to get a standard JavaScript object with the data.
That data object will look something like this, for example:
{
type: "dashboard:tile:start",
dashboard: {
id: 23,
title: "My Dashboard",
absoluteUrl: "https://mydomain.com/embed/dashboard/...",
url: "/embed/dashboard/...",
filters: {
"Sale date": "Last 28 days",
"Sale amount": "Greater than 100"
}
},
tile: {
id: 65,
title: "Quarterly Sales",
listen: {
"Sale date": "order.date",
"Sale amount": "order.amount"
}
}
}
The attribute type
indicates the type of event. The value of type
determines what data objects are returned. The possible types, their meaning, and the accompanying data are shown below:
Type | Description | Accompanying data |
"dashboard:run:start" | Dashboard has begun loading. Tiles will start loading and querying for data. | dashboard |
"dashboard:run:complete" | Dashboard has finished running and all tiles have finished loading and querying. | dashboard |
"dashboard:tile:start" | Tile is loading and/or querying for data. | dashboard , tile |
"dashboard:tile:complete" | Tile has finished querying for data. | dashboard , tile |
"dashboard:download" | PDF of dashboard has been downloaded. | dashboard , fileFormat |
"dashboard:tile:download" | Tile data has been downloaded. | dashboard , tile *, fileFormat |
"dashboard:filters:changed" | Dashboard filters have been applied or changed. | dashboard |
\* The `tile` object for the `"dashboard:tile:download"` event only contains the `title` parameter.
The definitions of the possible data accompanying the type
attribute are as follows:
Data: dashboard
Format: Object
Description: Data about the dashboard that sent event data to the parent page.
Parameters:
Attribute | Format | Description |
id | Number | The ID number of the dashboard |
absoluteUrl | String | The full dashboard URL |
url | String | The relative dashboard URL (just the path) |
title | String | The title, as shown at the top of the dashboard |
filters | Object | The applied filters. This object has the format: {"Filter name 1": "value 1", "Filter name 2": "value 2", ...} |
Example:
dashboard: {
id: 23,
title: "My Dashboard",
absoluteUrl: "https://mydomain.com/embed/dashboard/...",
url: "/embed/dashboard/...",
filters: {
"Sale date": "Last 28 days",
"Sale amount": "Greater than 100"
}
}
Data: tile
Format: Object
Description: Data about an tile on the dashboard that triggered the event.
Parameters:
Attribute | Format | Description |
id | Number | The ID number of the event |
title | String | The tile title as shown at the top of the tile |
listen | Object | The global filters this tile is listening for. This object has the format: {"Filter name 1": "applied model 1", "Filter name 2": "applied model 2", ...} |
Example:
tile: {
id: 65,
title: "Quarterly Sales",
listen: {
"Sale date": "order.date",
"Sale amount": "order.amount"
}
}
Note: As previously mentioned, the tile object for the “dashboard:tile:download” event only contains the title parameter.
Data: fileFormat
Format: String
Description: The file-type extension for the downloaded file, such as "txt"
or "csv"
.
I am unable to make this work. Also, the example shows embed_domain
in a querystring that is not encoded which seems odd. I tried both encoded and unencoded and neither worked for me. I wired up an event listener, removed the safety check to debug, and no events are raised against my window
.
I’m able to see events come through if I manually fire them from the looker iframe, so I know the event is wired correctly. To do this, simply switch chrome to the looker iframe and do something like this:
window.top.postMessage('HERE IS THE MESSAGE', 'http://localhost:8000' || 'your app domain')
Is this functionality still supported? Thank you for the help.
Is there a way to use embed_domain with SSO login scenario. Adding the embed_domain parameter throws ‘This request includes invalid params: [“embed_domain”]’ error message in url validator
hello
embed_domain
parameter isn’t its own bonafide SSO parameter, but rather gets put directly in the embed_url
parameter like so:
embed_url: "/embed/looks/6384?embed_domain=http://localhost:8081"
Please give that a try.
Thanks,
Philip M.
Thank you Philip, that seems to have solved the problem. Started getting “Refused to embed in a frame because it set ‘X-Frame-Options’ to ‘sameorigin’” - will work on it.
I have not been able to get this working. I am using localhost/virtual directory. We have the iframe in a .aspx page,
Hey Traci!
What part specifically are you unable to get working? Is it a similar error to the above “X-Frame-Options” error, or something different?
Hi,
I am trying to implement this myself through SSO but the generated URI is giving me the message " * This request includes invalid params: [“embed_domain”]".
My URI without the embed_domain
parameter is valid.
Here is an example of how it looks:
https://localhost:4200/login/embed/%2Fembed%2Fdashboards%2F7?nonce=%22d7f37e89-b6b5-4275-aee5-5b29511299f0%22&time=1557757858&session_length=600&external_user_id=%22testuser01.testautomation%40craneware.com%22&permissions=%5B%22access_data%22%2C%22see_looks%22%2C%22see_user_dashboards%22%2C%22see_lookml_dashboards%22%2C%22explore%22%5D&models=%5B%22Issues%22%5D&group_ids=%5B1%5D&external_group_id=%22%22&user_attributes=%7B%7D&access_filters=%7B%7D&force_logout_login=true&signature=3lhglaGmWkq6ZXhoCFo%2BaRiU6DQ%3D&embed_domain=http%3A%2F%2Fhttp%3A%2Flocalhost%3A4200
I have tried both encoding and not encoding the embed_domain
parameter.
Any help would be appreciated.
Thanks
This is a sneaky trick that always gets me, too.
Even though “embed_domain” is kinda sorta technically a “parameter”, in the context of an SSO script, it’s more like a URL modifier. It goes in the actual embed_url parameter of your script like 'https://localhost:4200/embed/dashboards/7?embed_domain=http://localhost:8000'
.
You don’t want to add an extra parameter to the script, since that’ll both mess up the signature and confuse Looker with a parameter it’s not familiar with. Give modifying the embed_url a shot, and let us know!
Ty Izzy. That is now working. Followed your advice and added the embed query params after the embed_domain
Did you misnamed embed_path
as embed_url
?
Reply
Enter your username or e-mail address. We'll send you an e-mail with instructions to reset your password.