In previous blog posts (1, 2, 3), we explored different topics around Qlik's embedding library, qlik-embed, and how to integrate it seamlessly with OAuth for authentication. Today, we'll delve into the latest updates and new features, including embedding Qlik Answers, go over UI capabilities, and advanced configuration options.
Recap: What is qlik-embed?
qlik-embed is a versatile library designed to facilitate the embedding of Qlik Sense analytics into web applications. By using web components, it allows developers to easily integrate Qlik's powerful analytics capabilities without dealing with the complexities of traditional embedding methods. The library supports various authentication methods, including Qlik Cloud API keys, OAuth2 clients, and Qlik Sense Enterprise interactive login.
In our previous discussions, we highlighted the ease of use and the flexibility qlik-embed offers, supporting components such as chart, field, selections, and entire app.
New Feature: Embedding Qlik Answers
One of the most exciting additions to qlik-embed is the ability to embed Qlik Answers. Qlik Answers leverages AI to provide natural language querying capabilities, allowing users to interact with their data using conversational language (If you haven’t already checked that out, visit this Community post or watch this demo video). The new UI component ai/assistant enables this functionality directly right within your web app.
Here's an example of how you can integrate Qlik Answers into your application:
<qlik-embed
ui="ai/assistant"
assistant-id="<assistant-id>"
appearance="qlik-light"> // or "qlik-dark"
</qlik-embed>
This simple integration can greatly enhance user interaction by allowing them to ask questions and receive insights in real-time, making data exploration more intuitive and user-friendly.
More on UIs and Parameters
As I mentioned before, the qlik-embed framework supports a variety of UIs, each designed for specific purposes. Let’s take a quick overview on each one:
analytics/sheet: For embedding entire Qlik Sense sheets with full selectivity but without additional features like alerts or notes. (Supports sheets that contain only nebula.js visualizations, for a full list: see here: https://qlik.dev/embed/foundational-knowledge/visualizations/)<qlik-embed id="visualization" ui="analytics/sheet" app-id="13b05004-2752-4f39-a077-7a71c5816997" object-id="bdGHw"></qlik-embed>
analytics/chart: For embedding single chart objects or creating charts on the fly with better performance. (Supports nebula.js objects only, see full list above)<qlik-embed id="visualization" ui="analytics/chart" app-id="13b05004-2752-4f39-a077-7a71c5816997" object-id="hshG"></qlik-embed>
analytics/field: A lightweight listbox for a specific field (dimension or measure)(To find the library-id, you can add /options/developer to the URL when editing a sheet, right click on a object containing your master dimension or measure then click on Developer and look for the qLibraryId value)<qlik-embed id="visualization" ui="analytics/field" app-id="13b05004-2752-4f39-a077-7a71c5816997" library-id="BfXheUu" type="dimension"></qlik-embed>
analytics/selections: Displays a selection bar with controls for managing selections.<qlik-embed id="visualization" ui="analytics/selections" app-id="13b05004-2752-4f39-a077-7a71c5816997"></qlik-embed>
classic/app: Provides a full-featured Qlik Sense sheet analysis and authoring experience.<qlik-embed id="visualization" ui="classic/app" app-id="13b05004-2752-4f39-a077-7a71c5816997"></qlik-embed>
classic/chart: Backwards-compatible for single chart objects (legacy), including support for extensions.<qlik-embed id="visualization" ui="classic/chart" app-id="13b05004-2752-4f39-a077-7a71c5816997" object-id="hshG" iframe="true"></qlik-embed>
Each UI type can be configured with various parameters to customize the appearance and functionality. For example, you can set the theme, dimensions, measures, and even complex properties for charts.
Here’s an example of embedding a dynamic chart (See here for more info about Charts on the Fly)
<qlik-embed
ui="analytics/chart"
app-id="YOUR_APP_ID"
type="barchart"
dimensions='["Category"]'
measures='["Sum(Sales)"]'
properties='{"orientation": "horizontal"}'>
</qlik-embed>
This flexibility allows you to create highly dynamic and interactive dashboards that can adapt to users' needs in real-time.
Advanced Configuration: Context Parameters and Themes
A cool feature of qlik-embedis the ability to pass context parameters using the context__json attribute. This allows for more granular control over the embedded visualizations, enabling customization of themes, interactions, and other properties directly within the web component.
Reference my previous post about this here.
Accessing the App Model through qlik-embed
With qlik-embed, you can access the metadata of a Qlik Sense application, including, but not limited to, obtaining a list of sheets and adding them to a dropdown list element for instance.
Keep in mind that this won't work with the classic/app UI
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<style>
body,
html {
margin: 0;
padding: 0;
font-family: sans-serif;
font-size: 14px;
background-color: #f5f5f5;
color: #333;
height: 100%;
width: 100%;
}
.container {
padding: 8px;
gap: 8px;
position: relative;
flex: 1 0 auto;
display: flex;
flex-direction: column;
align-items: stretch;
box-sizing: border-box;
}
.classic-app {
height: 800px;
width: 1200px;
border: 1px solid #bbb;
flex-grow: 1;
border-radius: 3px;
box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.2);
position: relative;
box-sizing: border-box;
overflow: auto;
position: relative;
}
.viz {
width: 1200px;
height: 900px;
padding: 16px;
border: 1px solid #bbb;
border-radius: 3px;
box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.2);
position: relative;
}
</style>
<title>@qlik/embed-web-components example - using OAuth</title>
<script crossorigin="anonymous" type="application/javascript"
src="https://cdn.jsdelivr.net/npm/@qlik/embed-web-components"
data-host="https://YOUR_TENANT.us.qlikcloud.com" data-client-id="CLIENT_ID"
data-redirect-uri="https://localhost:3000/index_oauth_object.html" data-access-token-storage="session"></script>
<script type="module">
const embeddedObject = document.getElementById("visualization");
const refApi = await embeddedObject.getRefApi();
console.log('refApi -> ', refApi);
const doc = await refApi.getDoc();
const appSheetList = await doc.getSheetList();
//add the sheet references to a dropdown list
let dd = document.getElementById('sheetdrop');
dd.length = 0;
let defaultOption = document.createElement('option');
defaultOption.text = "Select a sheet to navigate to";
dd.add(defaultOption);
dd.selectedIndex = 0;
let option;
for (let i = 0; i < appSheetList.length; i++) {
option = document.createElement('option');
option.text = appSheetList[i].qMeta.title;
option.value = appSheetList[i].qMeta.id;
dd.add(option);
}
//add a listener to change the object-id property in the qlik-embed element
dd.addEventListener("change", function () {
if (dd.selectedIndex > 0) {
let selOption = dd.options[dd.selectedIndex];
console.log(selOption.value);
embeddedObject.setAttribute('object-id', selOption.value);
}
});
</script>
</head>
<body>
<div id="main-app">
<div class="container">
<h1>@qlik/embed-web-components Example</h1>
</div>
<div>
<select id="sheetdrop" name="SheetList">
</select>
</div>
<div id="analytics-chart" class="container">
<div class="viz">
<qlik-embed id="visualization" ui="analytics/sheet" app-id="27018b4a-eaa7-4658-a8c2-ecf48d321371"
object-id="d568340d-1264-473e-bbdf-68d2555f007e"></qlik-embed>
</div>
</div>
</body>
</html>
The continuous evolution of qlik-embed brings exciting new features that enhance the integration of Qlik analytics into web applications. Stay tuned for more updates and explore the full potential of qlik-embedon qlik.dev.
...View More
In august 2020 we introduced the App Analyzer for Qlik Cloud tenants, a powerful monitoring tool which tracks metrics such as an app’s memory usage, ensuring you stay within your quotas. It also aids in app optimization by revealing field and table sizes, and highlighting potential data modeling issues like synthetic keys and data islands.
There have been some data load editor improvements that I think are worth mentioning so in this blog post I will cover some of the new features in the data load editor that I have found useful. The first, and my favorite new feature, is the table preview. The second is the ability to do a limited load and load a specified number of rows in each table. The third feature I will cover is the ability to view the script history, as well as the option to save, download and restore previous versions. Let’s look at each of these in more detail.
When building an app, my preference is to use the load data editor to load my data. With table preview, I can view loaded data tables at the bottom of the data load editor after data has been loaded or previewed in an app.
This is my favorite new feature because nine times out of ten, I want to view the data I loaded to ensure it loaded as expected and to check that my logic is correct. Having the preview table right there in the data load editor, saves me from having to go somewhere else, like the data model viewer or a sheet, to view the loaded data. I can use the preview table to check that they have the desired results. The ability to do this quick check saves me time.
As a developer, I can select the table to preview, and the data can be viewed as a table, as seen above, or as a list or grid as seen in the images below. When previewing the data as a table, the preview table can be expanded to show more rows, columns in the table can be widened and there is pagination that allows me to move around in the table. There is also an option to view the output of the load. This will show the same info you see in the load data window when the app is reloading.
List View
Grid View
The second feature in the data load editor I find useful is the preview data option. This provides an easy way for me to load some, but not all, of the data when reloading. In the screenshot below, the default of 100 rows is entered. This will load a max of 100 rows in each table. This value can be edited if desired. By default, the use store command is toggled off. When this is off, store commands in the script are ignored preventing potentially incomplete data from being exported. This feature is helpful when I want to just profile the data and see what the data looks like. It can also be helpful when there is a lot of data to be loaded and I do not need to load it all to check that the script is working as expected. Again, this is another time saver because I can limit the load thus the time it takes for the app to reload in a single step. I find this helpful when I want to quickly test a change in the script but do not want to wait for the entire app to reload.
The last data load feature I am going to cover is history for scripts. This new capability allows me to create versions of the script, name and rename scripts, restore the script from a previous version, download the load script or delete a version of the script.
I have not used the history feature much, but I can see it being helpful when I want to name various versions of the script. Every time the script is edited, it is saved to the current version. At any time, I can save that current version giving it a meaningful name. Maybe I want to make some changes to the script but want to have a backup in case it does not work. This can be done now right in the data load editor. I also have an easy way to restore a previous version, if necessary. Once a version is named, it can be renamed, restored, or deleted. All script versions can be downloaded as a QVS file. One thing to note is that the history only saves scripts created in the data loaded editor.
Hopefully, you find these new data load editor features helpful. They are available now in your tenant. Just check out the data load editor in your app.
Thanks,
Jennell
...View More
Join Principal Technical Marketing Manager Mike Tarallo and Senior Web Developer Ouadie Limouni as the team up once again to show you what is possible and what you may have missed in the Qlik Cloud platform. Witness the art of the possible, sophisticated and simple embedding, and a recent recap of the capabilities that make Qlik a leader for 14 years in the Gartner Magic Quadrant in Analytics and Business Intelligence Platforms.
In the last couple of posts, we explored qlik-embed, Qlik’s new library for embedding Qlik Sense analytics into web applications, and went over how to do silent authentication with OAuth. Since then, the library has seen some updates, and today, we’ll delve into a new feature that allows to embed charts that are created on the fly as well as look into how to handle anonymous access using OAuth impersonation.
What’s New in qlik-embed?
Charts on the Fly
One of the features thatstandout in the newest qlik-embed release is "charts on the fly." This allows you to create charts dynamically from data within a Qlik Sense app without needing the chart to pre-exist in the app itself.
Instead, you pass a chart definition including dimensions, measures, and chart properties, and qlik-embed generates it on the fly in your web app.
Here’s a quick example using qlik-embed web components:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<style>
.container {
padding: 8px;
gap: 8px;
position: relative;
flex: 1 0 auto;
display: flex;
flex-direction: column;
align-items: stretch;
box-sizing: border-box;
}
.viz {
width: 600px;
height: 600px;
padding: 16px;
border: 1px solid #bbb;
border-radius: 3px;
box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.2);
position: relative;
}
</style>
<title>@qlik/embed-web-components example - using OAuth</title>
<script crossorigin="anonymous" type="application/javascript"
src="https://cdn.jsdelivr.net/npm/@qlik/embed-web-components@1/dist/index.min.js"
data-host="<YOUR TENANT>" data-client-id="<CLIENT ID>"
data-redirect-uri="https://localhost:3000/index_oauth_object.html" data-access-token-storage="session"></script>
</head>
<body>
<div id="main-app">
<div class="container">
<h1>@qlik/embed-web-components Example</h1>
</div>
<div id="analytics-chart" class="container">
<h2>"qlik-embed" <em>analytics-chart</em> embedding chart on the fly.</h2>
<div class="viz">
<qlik-embed id="visualization" ui="analytics/chart" app-id="<THE APP ID>"
type="barchart" dimensions='["Type", "Experience"]' measures='["Count([Demo ID])"]'
properties='{ orientation: "horizontal", barGrouping: { grouping: "stacked" } }'
context___json='{ theme: "Breeze", interactions: { select: false } }'></qlik-embed>
</div>
</div>
</body>
</html>
This feature is particularly powerful for creating highly dynamic and responsive dashboards where the visualizations can adapt to the user's needs in real time. However, keep in mind that "charts on the fly" is currently limited to the chart types available in the analytics/chart UI within qlik-embed. You can refer to the chart compatibility table for the most up-to-date information.
Notice that you can now pass context using the context___json (triple underscores (___)) to apply a specific theme etc..
For instance:
<qlik-embed context___json='{ theme: "Breeze" }' ... />
Understanding OAuth Impersonation
OAuth impersonation tokens in Qlik Cloud are a game-changer for web applications needing to access resources on behalf of users, especially when dealing with different identity providers. This method replaces the need for third-party cookies with OAuth tokens to maintain state, significantly improving security and user experience.
Things to keep in mind when using OAuth Impersonation:
Do Not Expose Machine-to-Machine Clients on the Frontend: keep your client secrets in the backend.
Use a Backend Web Application for Token Issuance: Create an endpoint in your backend application to issue tokens.
Explicitly Set Scopes on Impersonation Tokens: Ensure your tokens have the minimal required scopes to enhance security.
Here’s an example snippet for issuing impersonation tokens using the@qlik/apilibrary:
import { auth as qlikAuth, users as qlikUsers } from "@qlik/api";
const qlikConfig = {
authType: "oauth2",
host: "https://tenantName.region.qlikcloud.com",
clientId: "OAuth impersonation client Id",
clientSecret: "OAuth impersonation client secret",
};
//set the host configuration to talk to Qlik tenant
qlikAuth.setDefaultHostConfig(qlikConfig);
//access token method the frontend will call
app.post("/access-token", requiresAuth(), async (req, res) => {
const userId = req.session?.user?.id;
try {
//call to Qlik Cloud tenant to obtain an access token
const accessToken = await qlikAuth.getAccessToken({
hostConfig: {
...qlikConfig,
userId,
noCache: true,
},
});
console.log("I got an access token!");
//access token returned to front end
res.send(accessToken);
} catch (err) {
console.log(err);
res.status(401).send("No access");
}
});
Or using the fetch API:
const hostConfig = {
host: "https://tenantName.region.qlikcloud.com",
};
const payload = {
client_id: "OAuth impersonation client Id",
client_secret: "OAuth impersonation client secret",
grant_type: "urn:qlik:oauth:user-impersonation",
user_lookup: {
field: "subject",
value: "SUBJECT_VALUE",
},
scope: "user_default",
};
async function getAccessToken(hostConfig, payload) {
const getToken = await fetch(`${hostConfig.host}/oauth/token`, {
method: "POST",
mode: "cors",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
const response = await getToken.json();
//console.log(response);
return response;
}
(async () => {
await getAccessToken(hostConfig, payload);
})();
Once you have the backend that generates the access token built, you can access it on the frontend in the qlik-embed library by using the "data-get-access-token" attribute and passing it the name of the function that calls your access token backend API endpoint, like this:
<script crossorigin="anonymous" type="application/javascript"
src="https://cdn.jsdelivr.net/npm/@qlik/embed-web-components@1/dist/index.min.js"
data-host="<YOUR TENANT>" data-client-id="<YOUR CLIENT ID>"
data-get-access-token="getAccessToken" data-auth-type="Oauth2"></script>
<script>
async function getAccessToken() {
const response = await fetch("<BACKEND API URL>/access-token", {
method: "POST",
credentials: "include",
redirect: "follow",
mode: "cors"
});
if (response.status === 200) {
const tokenResp = await response.json();
const accessToken = tokenResp.access_token;
return accessToken;
}
const err = new Error("Unexpected serverside authentication error");
err.status = response.status;
err.detail;
throw err;
}
</script>
You can visit qlik.dev for more information about authentication concepts.
The qlik-embed library continues to evolve, bringing powerful new features and enhanced security capabilities to the table. Whether you're creating dynamic visualizations on the fly or implementing different auth methods, qlik-embed provides the tools needed for bring Qlik analytics into your web applications.
...View More
Our Leigh Kennedy, Distinguished Principal Enterprise Architect, is back with an updated look on applying software development life cycle (SDLC) concepts to your Qlik Cloud Analytics tenants. Take it away Leigh!
This past week, with all the focus in Orlando for Qlik Connect, I decided to spend some time giving a dashboard in one of our existing demos a makeover. Given all the new capabilities that have been introduced recently, I was excited to see what I could create. Let me walk you through how I completed this dashboard makeover.
Today I am going to blog about cyclic dimensions. A cyclic dimension is a group of dimensions that can be cycled through in a visualization. The dimensions do not have to be related or have a hierarchical relationship. The dimensions only have to make sense with the measures used in the visualizations. Cyclic dimensions can be very useful when it is valuable to view a visualization across many dimensions. It becomes even more valuable if there are multiple visualizations on a sheet, or in an app, that use the same cyclic dimension. When a cyclic dimension is switched to the next field, all visualizations that use the cyclic dimension will be changed to the same field. This is a time saver. You may wonder if alternate dimensions can do the same thing. Alternate dimensions allow a user to change the dimension in a chart, but it only changes it for the specified chart whereas a cyclic dimension can change the dimension for multiple charts.Alternate dimensions can also be used in a visualization with a cyclic dimension.
Building a cyclic dimension is very easy and there are few ways to use them. You create a cyclic dimension the same as you do a single or drill-down dimension. From the Master items, create a new dimension. At the top select Cyclic dimension type, then add the fields to include. Give the cyclic dimension a name and save. Labels can be added to give the fields a different name and description. At least two fields need to be added to a cyclic dimension.
A cyclic dimension can be added to a visualization the same way a single dimension is added. Once they are added to a visualization a cycle icon will appear next to the field name as well as an arrow. By default, the first field in the cyclic dimension will be displayed. To change the dimension in the visualization, a user can click on the cycle icon or click on the label or down arrow and select another dimension.
Another way a user can cycle through the dimensions is to use a button. In the What’s New app, buttons have been created to cycle through the cyclic dimensions.
In all three buttons, the action is set to Step cyclic dimension and the Step is set to backward for the left arrow and forward for the right arrow and the cycle button in the middle.
Left arrow buttonRight arrow & cycle buttons
In the What’s New app, you can also see how changing the cyclic dimension in one visualization, updates all the visualizations using the cyclic dimension. In the screenshot below, Category Name is the current cyclic dimension.
If I switch the dimension, using any of the ways I have described above, Country Code is the dimension. Notice that the dimension in all the visualizations have been updated to Country Code in the screenshot below.
Check out Qlik Help to learn more about cyclic dimensions and to be aware of the limitations. Also watch Michael Tarallo’s SaaS in 60 video on Cyclic Group Dimensions. Try them out in your next app.
Thanks,
Jennell
...View More