Embed Dashboards Using Iframes

To embed a dashboard into your web application, copy the following iframe snippet into your web app and subtitute your own values for <host_url>, <workspace_id> and <dashboard_id>:

<iframe
    title="My Embedded GoodData Dashboard"
    id="embedded-app-frame"
    src="<host_url>/dashboards/embedded/#/workspace/<workspace_id>/dashboard/<dashboard_id>"
    height="500px" 
    width="100%"
    frameborder="0"
></iframe>

You may be prompted to authenticate yourself. Once authenticated, you should be able to see your embded dashboard:

Dashboard embeded with iframe

To hide or display different parts of the dashboard, see Configuration Options.

To use alternative ways of authentication, see Authentication.

To monitor and control the behaviour of the dashboard using JavaScript, see PostMessages.

Configuration Options

You can configure your embedded dashboard by adding one or more of the following URL parameters:

URL ParameterDescription
?hideControl=[controlElement1,controlElement2]Hide one one or more of the following control elements: filterBar, topBar, widgetsCatalogue, deleteButton, saveAsButton
?showNavigation=falseHide the navigation panel that lists dashboards
?showEmbedButton=falseHide the Embed button
?includeObjectsWithTags=[tag1,tag2]Display only objects that contain a tag listed in this parameter
?excludeObjectsWithTags=[tag1,tag2]Hide objects that contain a tag listed in this parameter
?hidefilters=filter1,filter2Hide specific attribute filters
?redirect-drill-url-to-message=allCreate a postMessage with drilling parameters instead of opening the URL in a new window when drilling to a URL from a visualization*

For example to embed a dashboard without the navigation panel and the Embed button, you would use the following URL:

<host_url>/dashboards/embedded/#/workspace/<workspace_id>/dashboard/<dashboard_id>?showNavigation=false?showEmbedButton=false

* To intercept the postMessage generated by adding the URL parameter ?redirect-drill-url-to-message=all, use the following JavaScript function:

window.addEventListener("message", function(e){
        console.log('Drill: Received post message', e);
    }, false);

When user attempts to drill to URL, they will receive 2 messages in the console log, drillToUrlStarted and drillToUrlResolved. The resolvedFilterValues part of the message contains information on the attribute filters, date filters.

Authentication

If you are using an OpenID Connect (OIDC) identity provider for authentication, the authentication process should be automatic. However, if you want to use API tokens for authentication, you will need to handle this type of authentication manually.

Use API Token

To set up authentication using API token for an embedded dashboard:

  1. Embed the dashboard using the iframe.

  2. Add URL parameter ?apiTokenAuthentication=true.

  3. Implement a message listener in the embedding page to listen to events sent by the dashboards. The listener must wait for a listeningForApiToken event.

    When the event is received, the dashboard is ready to receive the API token.

  4. Send a postMessage command to the iframe with the API token value.

    The dashboard will continue with initialization and use the token for authentication of all API calls from now on.

See the Example below for implementation details.

Example of Authentication Using Injected API Token

You may reuse the following code snippet, do not forget to replace <host_url>, <workspace_id>, <dashboard_id>, and <api_token_value> with your own values:

<iframe
    title="Embed GD Application"
    id="embedded-app-frame"
    src="<host_url>/dashboards/embedded/#/workspace/<workspace_id>/dashboard/<dashboard_id>?apiTokenAuthentication=true"
    width="1300"
    height="800"
></iframe>
<script>
    console.log("Setup parent frame message listener")

    window.addEventListener(
        "message",
        function (event) {
            console.log("Post message received", event);

            if (event.data.gdc?.event.name === "listeningForApiToken") {
                const postMessageStructure = {
                    gdc: {
                        product: "dashboard",
                        event: {
                            name: "setApiToken",
                            data: {
                                token: "<api_token_value>"
                            }
                        }
                    }
                };
                console.log("Sending token to embedded window");

                const origin = "*";
                const iframe = document.getElementById("embedded-app-frame").contentWindow;
                iframe.postMessage(postMessageStructure, origin);
            }
        },
        false
    );
</script>

Use JSON Web Token

If you are using JSON Web Token (JWT) instead of an API token for authentication edit your event data payload in the following way:

event: {
    name: "setApiToken",
    data: {
        token: "<jwt_token_value>",
        type: "jwt",
        secondsBeforeTokenExpirationToEmitReminder: 60
    }
}

When the token is 60 seconds from expiring, the apiTokenIsAboutToExpire event is emitted to notify you and give you a chance to post a fresh token. Note that 60 seconds is the default value, but you can change it.

We recommend you check out the Create JWK and JWT in JavaScript to get started on handling JWTs inside JavaScript.

Example of Authentication Using Injected JWT

This is a modified example of the API token injection example shown above that has been modified to better suit the JWT use case:

<iframe
        title="Embed GD Application"
        id="embedded-app-frame"
        src="<host_url>/dashboards/embedded/#/workspace/<workspace_id>/dashboard/<dashboard_id>?apiTokenAuthentication=true"
        width="1300"
        height="800"
></iframe>
<script>
    console.log("Setup parent frame message listener")

    window.addEventListener(
        "message",
        function (event) {
            console.log("Post message received", event);

            const eventName = event.data.gdc?.event.name;

            // Send new token when embedded application ask for it for the first time and then subsequently
            // each 60 seconds before the previous token expires. 
            if (eventName === "listeningForApiToken" || eventName === "apiTokenIsAboutToExpire") {
                // Fetch token from JWT generator endpoint, for example Node.JS Express application.
                // The application must ensure that the call is authenticated, for example via request cookie
                // or through SSO
                fetch(`/api/jwt-generator?user=john.doe`, {
                    method: "GET"
                }).then(function (response) {
                    if (response.ok) {
                        return response.json();
                    }
                    throw response;
                }).then(function (data) {
                    const postMessageStructure = {
                        gdc: {
                            product: "dashboard",
                            event: {
                                name: "setApiToken",
                                data: {
                                    token: data.jwt, // example expects the response is {"jwt": "<jwt_value>"}
                                    type: "jwt",
                                    secondsBeforeTokenExpirationToEmitReminder: 60,
                                }
                            }
                        }
                    };

                    console.log("Sending JWT to embedded window");

                    const origin = "*";
                    const iframe = document.getElementById("embedded-app-frame").contentWindow;
                    iframe.postMessage(postMessageStructure, origin);
                });
            }
        },
        false
    );
</script>

PostMessages

Dashboards embeded in your application using iframes communicate with the GoodData backend using postMessages. You can intercept these postMessages, or send your own, to control the behaviour of the dashboard.

Supported postMessages can be broken down into two categories:

  • Events are outgoing messages that the embedded dashboards send to your application to notify you about the status of commands (for example, success or failure). Events are sent automatically.

  • Commands are incoming messages sent from your application to the embedded Dashboard to apply actions.

Events

The following events are supported:

loadingStarted

The embedded content starts loading.

{
	"gdc": {
		"product": "dashboard",
		"event": {
			"name": "loadingStarted",
			"data": {
				"dashboard": "dashboard_identifier",
				"dashboardId": "dashboard_id"
			},
			"contextId": "<context_id>"
		}
	}
}

loaded

The content is fully loaded, and the user has permissions to access the dashboard.

{
	"gdc": {
		"product": "dashboard",
		"event": {
			"name": "loaded",
			"data": {
				"dashboard": "dashboard_identifier",
				"dashboardId": "dashboard_id"
			},
			"contextId": "<context_id>"
		}
	}
}

noPermissions

The user does not have permissions to view or edit the content. The ‘data’ section contains information about whether view or edit permissions are missing.

Possible reason values: viewDenied and editDenied.

{
    "gdc": {
        "product": "dashboard",
        "event": {
            "name": "noPermissions",
            "data": {
                "reason": "viewDenied"
            },
            "contextId": "<context_id>"
        }
    }
}

resized

An operation increasing the height of the hosting iframe is performed. The ‘data’ section contains information what height the iframe needs (in pixels).

{
    "gdc": {
        "product": "dashboard",
        "event": {
            "name": "resized",
            "data": {
                "height": 600
            },
            "contextId": "<context_id>"
        }
    }
}

dashboardCreated

A dashboard has been created and saved. The ‘data’ section contains, among other information, the dashboard ID. You can store it on your side and use later for managing multiple dashboards for this particular user.

{
	"gdc": {
		"product": "dashboard",
		"event": {
			"name": "dashboardCreated",
			"data": {
				"project": "project_id",
				"dashboard": "dashboard_identifier",
				"dashboardId": "dashboard_id"
			},
			"contextId": "<context_id>"
		}
	}
}

Note that in GoodData, terms workspace and project denote the same entity. For example, project ID is exactly the same as workspace ID.

dashboardCreationCanceled

The user cancels the creation of the dashboard.

{
    "gdc": {
        "product": "dashboard",
        "event": {
            "name": "dashboardCreationCanceled",
            "contextId": "<context_id>"
        }
    }
}

dashboardUpdated

The existing dashboard has been updated. The ‘data’ section contains, among other information, the dashboard ID. You can store it on your side and use later for managing multiple dashboards for this particular user.

{
    "gdc": {
        "product": "dashboard",
        "event": {
            "name": "dashboardUpdated",
            "data": {
                "project": "project_id",
                "client": "client_id",
                "dashboard": "dashboard_identifier",
                "dashboardId": "dashboard_id"
            },
            "contextId": "<context_id>"
        }
    }
}

Note that in GoodData, terms workspace and project denote the same entity. For example, project ID is exactly the same as workspace ID.

dashboardDeleted

The dashboard has been deleted. The ‘data’ section contains information about the deleted dashboard.

{
    "gdc": {
        "product": "dashboard",
        "event": {
            "name": "dashboardDeleted",
            "data": {
                "project": "project_id",
                "dashboard": "dashboard_identifier",
                "dashboardId": "dashboard_id"
            },
            "contextId": "<context_id>"
        }
    }
}

Note that in GoodData, terms workspace and project denote the same entity. For example, project ID is exactly the same as workspace ID.

setFilterContextFinished

A confirmation that the filters that you sent have been applied.

{
    "gdc": {
        "product": "dashboard",
        "event": {
            "name": "setFilterContextFinished",
            "contextId": "<context_id>"
        }
    }
}

filterContextChanged

A set of filters has been changed. Includes the new definitions of all filters that have been changed.

{
    "gdc": {
        "product": "dashboard",
        "event": {
            "name": "filterContextChanged",
            "data": {
                "filters": [
                    {
                        "relativeDateFilter": {
                            "granularity": "GDC.time.date",
                            "from": -6,
                            "to": 0
                        }
                    }
                ]
            },
            "contextId": "<context_id>"
        }
    }
}

drillableItems

Lists the identifiers of metrics and attributes that can be drilled into.

{
    "gdc": {
        "product": "dashboard",
        "event": {
            "name": "drillableItems",
            "data": {
                "identifiers": ["identifier123"]
            },
            "contextId": "<context_id>"
        }
    }
}

drillToUrlStarted

Drilling to a URL address starts. The message contains the ID of the window.

You must enable the redirect-drill-url-to-message=all in the embedded mode URL. If not enabled, no postMessages are sent and drilling is managed by the application.

{
    "gdc": {
        "product": "dashboard",
        "event": {
            "name": "drillToUrlStarted",
            "data": {
                "id": "windowId123"
            },
            "contextId": "<context_id>"
        }
    }
}

drillToUrlResolved

Contains the window ID and the target URL that opens in the specified tab/window.

You must enable the redirect-drill-url-to-message=all in the embedded mode URL. If not enabled, no postMessages are sent and drilling is managed by the application.

The filters section includes all dashboard filters applied to the insight that you drill from. It also includes information if the filter values are included or excluded from the filter.

The resolvedFilterValues section includes all actual values of dashboard filters applied to the insight that you drill from:

  • The attribute filters: text values of the filter elements.
  • The date filters: values from and to in the MM/dd/yyyy format
{
    "gdc": {
        "product": "dashboard",
        "event": {
            "name": "drillToUrlResolved",
            "data": {
                "id": "48769ef3-ef36-4532-baa7-b46294386117",
                "url": "https://www.company.com/my_products",
                "filters": [
                    {
                        "attributeFilter": {
                            "displayForm":"label.f_owner.salesrep.ownername",
                            "negativeSelection": false,
                            "attributeElements":["Cory Owens","Dale Perdadtin","Dave Bostadt"]
                        }
                    },
                    {
                        "dateFilter": {
                            "type": "relative",
                            "granularity": "GDC.time.year",
                            "from": -7,
                            "to": -1
                        }
                    }
                ],
                "resolvedFilterValues": {
                    "dateFilters": [
                        {
                            "from": "01/01/2014",
                            "to": "12/31/2020"
                        }
                    ],
                    "attributeFilters": {
                        "/gdc/md/auiwj6pa2cs3twpjr98gtjfb34x3i0gv/obj/1252": {
                            "/gdc/md/auiwj6pa2cs3twpjr98gtjfb34x3i0gv/obj/1251/elements?id=169661": "In Person Meeting"
                        }
                    }
                }
            },
            "contextId": "<context_id>"
        }
    }
}

Commands

The following commands are supported:

setApiToken

Set the API token you want to use for authentication. See the example above.

{
    "gdc": {
        "product": "dashboard",
        "event": {
            "name": "setApiToken",
            "contextId": "<context_id>",
            "data": {
                "token": "<api_token_value>"
            }
        }
    }
}

switchToEdit

Opens the dashboard for editing (in view mode only).

{
    "gdc": {
        "product": "dashboard",
        "event": {
            "name": "switchToEdit",
            "contextId": "<context_id>"
        }
    }
}

cancelEdit

Closes the dashboard (in edit mode only).

{
    "gdc": {
        "product": "dashboard",
        "event": {
            "name": "cancelEdit",
            "contextId": "<context_id>"
        }
    }
}

addWidget

Adds an item to the dashboard (in edit mode only).

Example: Add visualization

{
    "gdc": {
        "product": "dashboard",
        "event": {
            "name": "addWidget",
            "data": {
                "widget": {
                    "type": "insight",
                    "ref": {
                        "identifier": "c67470a1-a9dd-4a1e-980a-f51d947a195a"
                    }
                }
            },
            "contextId": "<context_id>"
        }
    }
}

addFilter

Add a filter to the dashboard (in edit mode only).

{
    "gdc": {
        "product": "dashboard",
        "event": {
            "name": "addFilter",
            "contextId": "<context_id>"
        }
    }
}

setFilterContext

Applies a set of filters to the embedded dashboard. You can define, one or more filters in the filter definition.

When the received filter configuration is applied, the following happens:

  • The filter configuration overrides any filters that the dashboard may already have, such as existing attribute and date filters, URL filters, previous filter configuration, and so on.
  • The filter configuration is applied even if the dashboard does not yet have any filters at all.
  • The filter configuration takes into account existing user permissions or variable filters: if they restrict some filters or filter values in the received configuration, those filters and values are not applied.
  • All display forms (not only default) are supported in the filter configuration.
{
    "gdc": {
        "product": "dashboard",
        "event": {
            "name": "setFilterContext",
            "data": {
                "filters": [
                    {
                        "positiveAttributeFilter": {
                            "displayForm": {
                                "identifier": "identifier123"
                            },
                            "in": ["someValue"],
                            "textFilter": true
                        }
                    }
                ]
            },
            "contextId": "<context_id>"
        }
    }
}

Notes:

  • To add a new filter, you must be in the Edit mode.
  • You can add max. 30 filters
  • If you receive an error, no filter from the postMessage is applied.

Example: Attribute filter - using an identifier

{
    "positiveAttributeFilter": {
        "displayForm": {
            "identifier": "identifier123"
        },
        "in": ["someValue"],
        "textFilter": true
    }
}

Example: Negative attribute filter

{
    "negativeAttributeFilter": {
        "displayForm": {
            "identifier": "identifier123"
        },
        "notIn": ["someValue"],
        "textFilter": true
    }
}

Example: Attribute filter with all values

{
    "negativeAttributeFilter": {
        "displayForm": {
            "identifier": "identifier123"
        },
        "notIn": []
    }
}

Example: Single selection filter

{
    "positiveAttributeFilter": {
        "displayForm": {
            "identifier": "identifier123"
        },
        "in": ["someValue"],
        "selectionMode": "single",
        "textFilter": true
    }
}

Example: Absolute date filter

{
    "absoluteDateFilter": {
        "dataSet": {
            "identifier": "identifier123"
        },
        "from": "2023-01-01",
        "to": "2023-12-31"
    }
}

Example: Relative date filter

You can use the following granularities: GDC.time.week_us, GDC.time.month, GDC.time.year, GDC.time.quarter, GDC.time.date.

{
    "relativeDateFilter": {
        "dataSet": {
            "identifier": "identifier 123"
        },
        "granularity": "GDC.time.date",
        "from": -6,
        "to": 0
    }
}

Example: All time date filter

{
    "relativeDateFilter": {
        "dataSet": {
            "identifier": "identifier123"
        },
        "granularity": "ALL_TIME_GRANULARITY",
        "from": 0,
        "to": 0
    }
}

Example: Ranking filter

Although the ranking filter is supported by the interface of setFilterContext , dashboards do not support this filter and it results in error.

removeFilterContext

Removes filters from the embedded dashboards (in edit mode only).

{
    "gdc": {
        "product": "dashboard",
        "event": {
            "name": "removeFilterContext",
            "data": {
                "filters": [
                    {
                        "displayForm": {
                            "identifier": "identifier123"
                        }
                    }
                ]
            },
            "contextId": "<context_id>"
        }
    }
}

where displayForm refers to the attribute filter.