Knowi makes it easier to create and embed analytics and visualizations into other business applications including your own and into cloud applications like Shopify or Salesforce.
Multiple options are available for embedding:
Embedding offers the ability to customize the user experience of dashboard interaction and functionality of the embedded applications. We provide multiple embed options:
Dashboards and widgets can be embedded using our Javascript API, or using an iFrame.
Knowi's embedded solution allows you to add the power of interactive visualization to external websites and applications. Knowi offers built-in features to distribute live dashboards with a customizable, tailored experience using a Javascript API and the security of Single Sign-On.
Embedding can be a single dashboard or visualization to the full application with integration to handle authentication, personalization, and content management.
Key concepts
Javascript API: API for embedding and programmatically managing the interaction and experience. Ideal for integrating with the functionality of the embedding application
Secure Hash: For public embedding, URL parameters such as user filters can be encrypted.
Authenticated Access: Method to guarantee security and governance for embedded views through Single Sign-On. If users of your application sign in, they will be allowed a passthrough to access Knowi content using the same credentials. Removes the friction of prompting a Knowi login screen.
User Filtering: Ability to securely filter a dashboard's data based on the Knowi login information. This is ideal in multi-tenant scenarios if you have a single dataset or database for multiple users or groups of users. Applying a user filter provides the functionality of utilizing the same content and style across users whilst ensuring each user can see only the rows governed by their user filter
Use this option to share or embed a dashboard for public access without security.
Note: This makes the dashboard publicly accessible without requiring a login. Do not use this option for sensitive data.
To enable a public share URL, click the menu icon in the top right of the dashboard, select Sharing Options, toggle on Shareable URL, and click Save Changes. The embed code can also be used to embed the dashboard into your own portal or HTML pages. To disable the URL, return to Sharing Options and toggle it off.

URL Parameters
Customize the shared URL by appending the following parameters:
contentFilters -- filter dashboard data by field values. The value must be in encoded JSON form.
Example: contentFilters=[{"fieldName":"opened","values":[1000],"operator":">"}]
For supported operators, combining filters, date ranges and URL encoding, see Content Filters in Share URLs.
themeId -- apply a custom theme to the dashboard.
Example: ?themeId=light
Full URL examples:
# With a content filter
https://www.knowi.com/d/3cKltxiizxNFgxjRvanZwY2WZoiikPo5ip3EqS13cii1KdQie?contentFilters=%5B%7B%22fieldName%22%3A%22opened%22%2C%22values%22%3A%5B1000%5D%2C%22operator%22%3A%22%3E%22%7D%5D
# With a theme
https://www.knowi.com/d/3cKltxiizxNFgxjRvanZwY2WZoiikPo5ip3EqS13cii1KdQie?themeId=light
# Combined
https://www.knowi.com/d/3cKltxiizxNFgxjRvanZwY2WZoiikPo5ip3EqS13cii1KdQie?themeId=light&contentFilters=%5B%7B%22fieldName%22%3A%22opened%22%2C%22values%22%3A%5B1000%5D%2C%22operator%22%3A%22%3E%22%7D%5D
Use this option to securely embed dashboards where you can filter the data based on parameters that are encrypted (using your customer key). This ensures that the request is not tampered with.
Steps:
Contact us to obtain a customer key.
Use this key to AES encrypt your request parameters. Users can generate the key (secure hash) with or without parameters. To include a parameter: include contentFilters as a parameter.
Parameters: contentFilters
Example: contentFilters=[{"fieldName":"opened","values":[1000],"operator":">"}]
Please contact support@knowi.com for assistance with AES encryption and/or sample code.
To generate an embeddable URL, navigate to the Sharing Options settings on the dashboard, toggle on Secure Shareable URL, and click Save Changes.

Build the URL with the generated hash at in step 2 at runtime. Embed into an iFrame inside your portal (or use the JavaScript API) Example: https://www.knowi.com/share/secure/VyqOBEBfyKt7ZUzLyH68Vm3lT34NisUIYM1VOis0IpI38ie/{secureHash}
Example Javascript Usage:
<HEAD>
<script src="https://www.knowi.com/minify/knowi-api.min.js"></script>
<!-- *********** Edit here *********** -->
<script>
function loadChart() {
Knowi.render('#knowi-div', {
type: 'secure',
hash: "rcf9rdm6zTDd6KIz9EblkO0e0BfEFF0SCjH9RABg=",
dashboard: "4kjl45kipgqULyXaT5fAUD3ipIypbipPNq2wm6D197pJKCnQnTx",
themeId: 'dark', // optional - override the dashboard theme
view: {
title: true,
border: true,
header: true,
setting: true
}
}, function () {
});
}
</script>
</HEAD>
<BODY onload="loadChart()">
<div id="knowi-div"></div>
</BODY>
</HTML>
Try the Interactive Embed Demo to test Secure URL embedding with live theme switching and view options.
You can also specify a time to expire for a given request, so that the link with the same parameters cannot be reused. To add an expiry, pass in the following two parameters to the request prior to the encryption routine:
Current Epoch Time: _t
Expiry in seconds: _ttl (default is 60 seconds if _t is present without _ttl).
Example url before passing it through the hashing/encryption routine: contentFilters=[{"fieldName":"opened","values":[1000],"operator":">"}]&_t=1699999999999&_ttl=30
Users can change the default timezone to any of the required timezone. By default, the timezone is set to the dashboard creator's timezone. Here is a list of time zones supported by Knowi. To change the timezone in the secure hash URL, append the _tz parameter at the end of the URL.
_tz=<timezone>
Note:
The _tz parameter can be appended to a post-encrypted URL only.
Make sure to append the _tz parameter after the ? symbol.
Examples:
https://www.knowi.com/share/secure/giiHglNJBQ0TZHzjG9f8XvpEMvruhisQFQk7V9UisMKllwie/LEr___2nqUZtopDswWtnxfRpTLTCaSdnRknTs3E9YTXwSA90P5VNc4dvm3T8FzDvycPBRvZXvg8X9YYGI1b17hzFqtPnbnlFPD___X+M+TGOJqlyXaD___A8+6aJfVwfNxpeVEWF6yGkingMJcug___lhWfhh1jqa12kN5p0xR___7FF191ic=?_tz=UTC
https://www.knowi.com/share/secure/giiHglNJBQ0TZHzjG9f8XvpEMvruhisQFQk7V9UisMKllwie/LEr___2nqUZtopDswWtnxfRpTLTCaSdnRknTs3E9YTXwSA90P5VNc4dvm3T8FzDvycPBRvZXvg8X9YYGI1b17hzFqtPnbnlFPD___X+M+TGOJqlyXaD___A8+6aJfVwfNxpeVEWF6yGkingMJcug___lhWfhh1jqa12kN5p0xR___7FF191ic=?_tz=America/New_York
In some scenarios, you want to guarantee the authentication of users before viewing Knowi content. Single sign-on enables the users signed into your application to view a protected-private Knowi resource without the need of signing in once again on Knowi. Afterward, a new browser session and cookie will be issued to the browser.
User identity, permissions, access level, and attributes are all constructed within the browser session of the single sign-on user, which is created using a unique customer token. Anyone with access to the customer token may create an SSO user to which that Knowi instance is connected to, as any user, with any permission. See our example code to learn how to generate an SSO flow
Generating Knowi Customer Token:
In order to create and manage SSO users, you'll first need a Knowi SSO Customer Token.
Step 1: On the left hand side menu, click User Settings --> Account Settings tab.

Step 2: From the Customer Settings section, select "Generate" in the SSO Token field .
Protect the Knowi SSO Token as you would any credentials to your Knowi instance and keep SSO Token section disabled if you are not using it.
This same token has a second, unrelated job: it is the encryption key for embed tokens under Asymmetric JWT authentication. It is never a signing key.

Note: Contact support@knowi.com if the SSO TOKEN option is not available in your Knowi Customer Settings.
Getting Started:
Embedding with SSO requires some code writing to seamlessly integrate into your web application. You can find several example scripts on our SSO examples GitHub repository.
The following simplifies the information needed to embed with SSO.
User Token: Create an SSO user within your account using your Knowi SSO Customer Token
curl -i -X POST -d "user=email@domain.com&ssoCustomerToken=<SSO_TOKEN>" https://www.knowi.com/sso/user/create
Note: Additional parameters can be passed when generating an SSO user token, such as assignment to groups, roles/permissions, and/or user filters. See the API reference for usage.
Session Token: Create a new session token using the returned token from step 1
curl -i -X POST -d "user=email@domain.com&userToken=<USER_TOKEN>" https://www.knowi.com/sso/session/create
Note: An optional parameter for custom session expiry can be passed when creating an SSO session token. See the API reference for details.
Embed: Write a Javascript section with the session token returned from step 2
function loadKnowiUser() {
Knowi.render('#knowi-div', {
type: "single",
token: "BYhXXCeu0Ego8zA1FqtLOOM4BDWot5AYBLI7PWrQTbsie",
url: "https://www.knowi.com/",
themeId: "dark", // optional - override the dashboard theme
view: {
title: true,
header: true
}
}, function () {
});
}
Note: Alternatively, you can log in directly on a browser or iFrame the URL using the session token returned from step 2
https://www.knowi.com/sso/user/login?token=<SESSION_TOKEN>
Try the Interactive Embed Demo to test SSO embedding with live theme switching and view options.
SSO API Resources:
POST https://www.knowi.com/sso/user/create
| Parameter | Type | Description |
|---|---|---|
| ssoCustomerToken | string | Required. Customer-specific SSO Token to authorize SSO user management. |
| user | string | Required. Email/username of the new or existing user. |
| userGroups[] | array of strings | An array of groups the user will be associated with. Note: Group will be created if it does not exist. Send an empty array ([]) to dissociate the user from all groups. |
| role | string | Role and permissions to assign the user. Defaults to system user if blank. |
| refresh | bool | If true, the user's properties (i.e. userGroups[], contentFilter, role) will be updated with new values. |
| refreshToken | bool | If set to false, the user token will not be refreshed. If the flag is false and the user does not exist, a new user will still be created with a new token. Defaults to true. |
| contentFilter | object | A JSON object to apply a row-level filter on data user is allowed to see. Ex: [{"fieldName": "region", "values":["Canada","Mexico"], "operator":"="}] |
Returns:
A user specific token. Store this for your user within your system.
Example
curl -i -X POST -d "userGroups[]=First Group&userGroups[]=Second Group&user=a@a.com&ssoCustomerToken=9ebdlklfWlYuQXPXanqHxq7ZflklfZ1pGC8Ny8l2is9uNhMie" https://www.knowi.com/sso/user/create
POST https://www.knowi.com/sso/session/create
| Parameter | Type | Description |
|---|---|---|
| user | string | Required. Email/username of the existing user. |
| userToken | string | Required. Token returned from user creation (/sso/user/create) |
| expiry | integer | Optional. Number of minutes from the token creation datetime until expiration. By default, session tokens expire after 30 minutes. |
Returns:
A session Id/token with an expiry of 1440 minutes from the creation datetime.
Example
curl -i -X POST -d "user=a@a.com&userToken=NUAslkrtRTTFMvscpiislikfyfhsgu491is7plqRvwvJGEgm7JVU8ie&expiry=1440" https://www.knowi.com/sso/session/create
Note: For added security, Both User creation and session creation also have optional domain matching, where we serve requests from specific hosts.
POST: https://www.knowi.com/sso/user/remove
| Parameter | Type | Description |
|---|---|---|
| user | string | Required. Email/username of the existing user. |
| userToken | string | Required. Token returned from user creation (/sso/user/create) |
| ssoCustomerToken | string | Required. Customer-specific SSO Token to authorize SSO user management. |
To update user level filters, use the following end point:
POST: https://www.knowi.com/sso/user/contentfilters/update
| Parameter | Type | Description |
|---|---|---|
| contentFilter | string | Required. A JSON object to apply a row-level filter on data user is allowed to see. Ex: [{"fieldName": "region", "values":["Italy"], "operator":"="}] |
| user | string | Required. Email/username of the existing user. |
| ssoCustomerToken | string | Required. Customer-specific SSO Token to authorize SSO user management. |
Example
curl -i -X POST -d "user=demoSSO@knowi.com&ssoCustomerToken=9ebdlklfWlYuQXPXanqHxq7ZflklfZ1pGC8Ny8l2is9uNhMie&contentFilter=[{\"fieldName\":\"customer\",\"values\":[\"Costco\"],\"operator\":\"=\"}]" https://www.knowi.com/sso/user/contentfilters/update
Option 1: iFrame the URL, with the session token:
https://www.knowi.com/sso/user/login?token=b7E5pofgis9nBjSyPxUclksflkfltS1ZEPhhHhG2MBZis34QJiiBFn8ie
Option 2: Use the JavaScript API:
Knowi.render('#knowi-div', {
type: 'single',
token: '...',
view: {
title: true,
css: ['https://knowi-web.s3.amazonaws.com/css/custom1.css', 'https://knowi-web.s3.amazonaws.com/css/custom2.css']
},
},
function() { alert("Loaded") }
);
The same single sign-on session token also embeds a published Knowi App in your site, using Knowi.render with type: 'appSso' and the App's own address. Embedding has to be enabled on the App first, with the list of sites allowed to show it. See App embedding setup and code.
Create User with user level filters enabled:
curl -i -X POST -d "userGroups[]=Default&user=a17@a.com&ssoCustomerToken=9ebdlklfWlYuQXPXanqHxq7ZflklfZ1pGC8Ny8l2is9uNhMie&contentFilter=[{\"fieldName\":\"customer\",\"values\":[\"LinkedIn\"],\"operator\":\"=\"}]" https://www.knowi.com/sso/user/create
Then create the session token and iFrame the URL with the session token like in the example above.
More on User level filters here.
The following end points can be used to retrieve groups, dashboards, queries and widgets:
GET /sso/dashboards
Parameters: token. SSO session token. Required.
Returns: Returns a list of dashboards and details for each dashboard in JSON Array form
Example: curl -i -X GET https://www.knowi.com/sso/dashboards?token="9sBRdisBevkFvfIbb3HnipqjutS00JIjWpTcGKUPe2wMAie"
GET /sso/widgets:
Parameters: token. SSO session token. Required.
Returns: Returns a list of widgets and details for each widget in JSON Array form
GET /sso/queries:
Parameters: token. SSO session token. Required.
Returns: Returns a list of queries associated to the user
GET /sso/groups:
Parameters: token. SSO session token. Required.
Returns: Returns a JSON list of user groups associated to the user
Get last timestamp of a users activity
GET /sso/session/lastActive
Parameters: token - SSO session token. Required.
Returns: timestamp in milliseconds for an SSO user's last system activity. Returns "-1" if user is inactive.
Example: curl -i -X GET https://www.knowi.com/sso/session/lastActive?token="9sBRdisBevkFvfIbb3HnipqjutS00JIjWpTcGKUPe2wMAie"
Extends the lifetime of SSO session token by 30 minutes
PUT /sso/session/keepAlive
Parameters: token - SSO session token. Required.
Returns: Returns No content
Example: curl -i -X PUT https://www.knowi.com/sso/session/keepAlive?token="9sBRdisBevkFvfIbb3HnipqjutS00JIjWpTcGKUPe2wMAie"
Logout and terminate an SSO user session
GET /sso/user/logout
Parameters: token - SSO session token. Required.
Returns: Returns No content
Example: curl -i -X GET https://www.knowi.com/sso/user/logout?token="9sBRdisBevkFvfIbb3HnipqjutS00JIjWpTcGKUPe2wMAie"
The Search Based Analytics API lets you
1. Develop applications to list query suggestions and retrieve the associated response from the query.
2. Embed a Google Search like interface to enable plain english requests to search across datasets within a given user's account.
Using Knowi's Search Analytics empowers your end-users the ability to ask questions of their data in English. Think of this as a Google search on your datasets. This functionality can be embedded in your application through Single Sign-On. Try it out.
Similar to embedding with SSO and the Javascript API, the steps to embedding Search Analytics are almost identical and can be achieved in three steps:
1. User Token: Create a Knowi user token for a new or existing user
curl -i -X POST -d "user=email@domain.com&ssoCustomerToken=" https://www.knowi.com/sso/user/create
2. Session Token: Create a Knowi session token with the user token from step 1
curl -i -X POST -d "user=email@domain.com&userToken=" https://www.knowi.com/sso/session/create
3. Embed: Write a Javascript file with the session token returned from step 2
Knowi.render('#knowi-div', {
type: 'nlp',
token: "ii7Cdf7QJy3PaYQLrdZLaGgMnq3Dy2Q1JEhiiuDR9GG64ie",
url: 'http://localhost:9090',
view: {
nlpOptions: {
icon: "off",
css: {
background: 'transparent',
width: '80%'
},
placeholder: "Try: total sales for canada this week",
help: "off",
helpText: "Ability to customize the help text of the question mark",
defaultView: "visual"
}
}
}, function () { });
Note: For embedding Search Analytics, type must be nlp
Note: The defaultView can either be data or visual. By default, it is set to data. If set to visual, then a visualization tab will show up in NLP results of the embedded view.
Following API's may be used to create your own search bar. Here are the relevant API calls:
GET: /sso/nlp/suggestions
| Parameter | Required | Description |
|---|---|---|
| token | yes | SSO session token |
| query | yes | Query to process |
Returns: - A list of suggestions as json array
POST: /sso/nlp/parse
| Parameter | Required | Description |
|---|---|---|
| token | yes | SSO session token |
| query | yes | Query to process |
| datasetId | yes | Dataset ID that your query should point to |
| format | no | Format of the response (json, txt). Defaults to json |
Returns: - Data as json or txt array
Two flows for two different goals:
Both: you sign a short-lived token with your own private key. Knowi holds only the public key.
They differ in one step: the embed flow also encrypts the signed token, because the URL carries row-level filters that should not be readable. Terminology:
aud, exp, etc.)."SSO" means three things on this page. (1) The older Single Sign-On API. (2) The login flow below (`aud: knowi:sso`). (3) Your SSO token in Settings > Account - a shared secret used by the embed flow as the encryption key. The login flow never touches it.
| Embed flow | Login flow | |
|---|---|---|
| You want | A share link filtered to one viewer, no login | To log an SSO user in |
aud |
knowi:embed |
knowi:sso |
| Token you produce | JWE - signed, then encrypted (5 segments) | JWS - signed only (3 segments) |
| Secrets you need | Your private key and your SSO token | Your private key only |
| Carries filters | Yes - contentFilters inside the token |
No - the user's own role decides what they see |
| Where it goes | Last path segment of the secure share URL | token parameter of /sso/user/login |
| Maximum lifetime | No limit (server can impose a cap) | 30 minutes |
Everything through Building a token applies to both flows.
Migrating from an older method? Same endpoints, same JS API parameters. You just mint the value yourself instead of asking Knowi for it, and it now expires.
Note: The JWT public key option is not available by default. Contact your Knowi account manager to have it enabled for your account.
To find the setting:
Then add a key in one of two ways.
Option 1: Generate Key Pair in Knowi
ES256, recommended) or RSA 2048 (signs RS256).The key pair is created in your browser. The private key downloads as knowi-jwt-private-key.pem, and Knowi stores only the public key. The private key is never sent to Knowi and is offered for download only once, so store it securely on the server that will sign your tokens. If you lose it, generate a new pair.
Key generation requires HTTPS. If it is not available in your browser, generate the pair yourself and use Option 2.
Option 2: Upload Public Key
Generate a key pair on your own system, for example with openssl:
openssl ecparam -name prime256v1 -genkey -noout | openssl pkcs8 -topk8 -nocrypt -out private.pem openssl pkey -in private.pem -pubout -out public.pem
Then click Upload Public Key, choose public.pem or paste its contents, and click Upload. The key must start with -----BEGIN PUBLIC KEY-----. Supported: EC P-256/P-384/P-521 and RSA 2048+.
The algorithm follows from the key type: P-256 ES256, P-384 ES384, P-521 ES512, RSA RS256.
Anything else is rejected.
Managing the key
Once a key is saved, the JWT public key row shows the signing algorithm and a shortened key fingerprint.
If the account has no SSO token, the row also shows Embed URLs require both a JWT public key and an SSO token. JWT alone enables SSO login only. To use the embed flow, generate an SSO token as described in Single Sign-On API.
One key per account. Uploading a new key or revoking the current one invalidates every existing
token immediately - saved JWT share groups included. Only you can reissue them. For tokens without
exp, key rotation is the only way to revoke them.
aud decides which flow the token belongs to.
Embed (knowi:embed). Filters ride inside the token:
{
"aud": "knowi:embed",
"customerId": 1234,
"iat": 1791855015,
"exp": 1791941415, // optional - omit for a link that never expires
"contentFilters": [
{"fieldName": "tenant_id", "operator": "Equals", "values": ["acme"]}
]
}
Without exp, the link never expires (revoke by rotating the public key):
{
"aud": "knowi:embed",
"customerId": 1234,
"iat": 1791855015,
"contentFilters": [
{"fieldName": "tenant_id", "operator": "Equals", "values": ["acme"]}
]
}
Login (knowi:sso). No filters; sub names the user to log in as:
{
"aud": "knowi:sso",
"customerId": 1234,
"sub": "$SSO_USERNAME",
"iat": 1791855015,
"exp": 1791856815 // iat + 1800 = 30 minutes (the max)
}
iat is required (Unix seconds). exp is required for login tokens and optional for embed.
claims in the examples below means one of these two objects.
| Claim | Required | Notes |
|---|---|---|
aud |
yes | knowi:embed or knowi:sso. A token minted for one is rejected by the other. |
customerId |
yes | Your Knowi customer id, included in the claims the Create/Test Secure Links dialog builds. |
iat |
yes | Seconds since epoch. When the token was created. |
exp |
login: yes; embed: optional | Seconds since epoch. Omit for an embed link that never expires. Login tokens must expire (max 30 min). On-prem can impose an embed cap too. |
sub |
SSO only | Username of the SSO user to log in as. The user must already exist and must have been created with /sso/user/create. Regular Knowi users, such as users invited from User Settings, cannot log in with a JWT. |
contentFilters |
embed only | Row filters. Only take effect if signed into the token - see below. |
ctx |
optional | Opaque string passed through to the dashboard as share context. |
Filters must be signed into the token. The rows in the Create/Test Secure Links dialog only build the claim for you to copy - they are not sent to Knowi. If you change the rows after signing, sign the token again. A token with no
contentFiltersshows unfiltered data.
One step for login, two for embed:
| Step | Key used | What it achieves | Embed flow | Login flow |
|---|---|---|---|---|
| 1. Sign (JWS) | your private key | Proves the claims are yours and unaltered. | yes | yes |
| 2. Encrypt (JWE) | your SSO token, as SHA-256(ssoToken) |
Hides the claims and ties the link to a second server-side secret. | yes | no |
Why embed gets step 2: the URL is the credential and lives in browser history for up to 24h, with claims that name which rows to show. Encryption keeps them unreadable. A login token goes straight back to Knowi and carries nothing confidential, so signing alone is enough.
Your SSO token is in Settings > Account. Keep it server-side - it decrypts the embed token.
# pip install pyjwt cryptography jwcrypto
import jwt, base64, hashlib, json, time
from jwcrypto import jwe as jwe_mod, jwk
now = int(time.time())
claims = {
"aud": "knowi:embed",
"customerId": 1234,
"iat": now,
"exp": now + 86400, # optional - omit for a link that never expires
"contentFilters": [
{"fieldName": "tenant_id", "operator": "Equals", "values": ["acme"]}
],
}
signed = jwt.encode(claims, private_key_pem, algorithm="ES256")
# For an SSO login token you are done here: `signed` is the token you send.
# Step 2 below is for embed tokens only. It wraps `signed` in an encrypted envelope.
cek = hashlib.sha256(sso_token.encode("utf-8")).digest()
key = jwk.JWK(kty="oct", k=base64.urlsafe_b64encode(cek).rstrip(b"=").decode())
token = jwe_mod.JWE(signed.encode(), json.dumps({"alg": "dir", "enc": "A256GCM"}))
token.add_recipient(key)
blob = token.serialize(compact=True)
print(blob) # 5 dot-separated segments
// npm i jose
import { SignJWT, CompactEncrypt } from 'jose';
import { createPrivateKey, createHash } from 'crypto';
const now = Math.floor(Date.now() / 1000);
const claims = {
aud: 'knowi:embed',
customerId: 1234,
iat: now,
exp: now + 86400, // optional - omit for a link that never expires
contentFilters: [
{fieldName: 'tenant_id', operator: 'Equals', values: ['acme']}
]
};
const key = createPrivateKey(privateKeyPem);
const jwt = await new SignJWT(claims)
.setProtectedHeader({ alg: 'ES256' }) // must match your key type
.sign(key);
// For an SSO login token you are done here: `jwt` is the token you send.
// Step 2 below is for embed tokens only. It wraps `jwt` in an encrypted envelope.
const cek = createHash('sha256').update(ssoToken, 'utf8').digest();
const blob = await new CompactEncrypt(new TextEncoder().encode(jwt))
.setProtectedHeader({ alg: 'dir', enc: 'A256GCM' })
.encrypt(cek);
console.log(blob); // 5 dot-separated segments
Note `.digest()` with no argument - raw bytes. `.digest('hex')` yields a 64-character string and
the token will be rejected.
// nimbus-jose-jwt
SignedJWT jwt = new SignedJWT(new JWSHeader(JWSAlgorithm.ES256), claims);
jwt.sign(new ECDSASigner(privateKey)); // RSASSASigner for an RSA key
// For an SSO login token you are done here: jwt.serialize() is the token you send.
// Step 2 below is for embed tokens only. It wraps the signed JWT in an encrypted envelope.
byte[] cek = MessageDigest.getInstance("SHA-256")
.digest(ssoToken.getBytes(StandardCharsets.UTF_8));
JWEObject jwe = new JWEObject(
new JWEHeader(JWEAlgorithm.DIR, EncryptionMethod.A256GCM),
new Payload(jwt.serialize()));
jwe.encrypt(new DirectEncrypter(cek));
String blob = jwe.serialize();
These samples mint an embed token (both steps). For a login token: set aud to knowi:sso,
add sub, drop contentFilters, and stop after the signing call.
JWE details: alg=dir, enc=A256GCM, compact serialization (RFC 7516). The key derivation
(SHA-256(ssoToken)) is the only Knowi-specific part.
Embed links are created from the sharing settings of a dashboard or widget. JWT mode is available only once a JWT public key is set up (see Setting up the key).
The dialog is for building claims and testing. In production, have your service sign a fresh token each time it renders the page, rather than storing one link in static HTML, because the link expires when the token does.
The resulting link:
https://www.knowi.com/share/secure/{secureShareUrl}/{token}
Same hash parameter as Secure URL Embed (Knowi-encrypted in the UI):
Knowi.render('#container', {
type: 'secure',
url: 'https://www.knowi.com/',
dashboard: '{secureShareUrl}',
hash: blob // your JWE goes where the Knowi-encrypted hash would
});
Only SSO users can log in with a JWT. A regular Knowi user is rejected with BAD_CREDENTIALS, even if the username matches.
Create the SSO user once (this is the only place in the login flow where the SSO token appears):
POST https://www.knowi.com/sso/user/create user=<sub>&ssoCustomerToken=<your SSO token>&role=user
Then on every login, redirect the browser (no server call needed):
https://www.knowi.com/sso/user/login?token={jwt}
Append &dashboardId=123 to land on a specific dashboard. With the JS Embed API:
Knowi.render('#container', {
type: 'single', // GET: builds sso/user/login?token=...
url: 'https://www.knowi.com/',
token: signedJwt, // a fresh knowi:sso JWT, injected server-side
dashboardId: 123
});
type: 'single' sends a GET (token in the URL); type: 'sso' sends a POST (token in the body).
Same endpoint. Prefer sso.
Paste a token into the Create/Test Secure Links dialog in JWT mode (see Using an embed token). Knowi checks it immediately: bad signature, failed decrypt, expired, time remaining, or missing filters. What's in this token? shows the filters it really carries.
Save is optional. The link works as soon as it appears. Save stores the group so reopening the dialog restores it. Each method (Knowi-encrypted / JWT) keeps its own groups; one Save stores both.
What gets stored. Embed tokens only (login tokens are never stored). The token is kept encrypted with your SSO token, re-checked on open. Your private key is never sent to Knowi. If you prefer Knowi holds nothing, skip Save.
| Message | Cause | Fix |
|---|---|---|
JWT has expired. |
exp is in the past. |
Mint a fresh token. |
JWT signature verification failed. |
Private key does not match the uploaded public key. | Sign with the matching private key. |
JWT algorithm mismatch |
The alg header does not match the key type. |
Use the algorithm the key implies - P-256 is ES256. |
JWE decryption failed |
SSO token mismatch or token altered in transit. | Re-encrypt with the current SSO token. Check for stray spaces or truncation if copied by hand. |
JWT audience does not include |
The token was minted for the other flow, for example an embed token sent to /sso/user/login. |
Use knowi:sso for login tokens and knowi:embed for embed links. |
exceeds the maximum |
Lifetime is over the cap for that audience. | Keep exp - iat within 30 min for login. Embed has no default cap but the server can impose one. |
BAD_CREDENTIALS at /sso/user/login |
The token is valid, but the user named in sub was not found: it does not exist, is not an SSO user, belongs to a different customer, or is deactivated. Signature, expiry, lifetime, and aud problems return their own messages instead. |
Create the user with /sso/user/create and check that sub and customerId match it. |
| Link loads but shows all rows | The token carried no contentFilters. |
Add filters to the claims and re-sign. |
DECODER routines::unsupported (Node) |
PEM is empty or not a private key. | Check the path and that the file starts with -----BEGIN PRIVATE KEY-----. |
| Login cookie dropped when testing locally | file:// framing http://localhost; cookie blocked as cross-site. |
Serve the test page from the Knowi origin so the two share a site. HTTPS hosts are unaffected. |
The easiest method for embedding a Knowi display (dashboard or visualization) is with the copy-paste embed code. Navigate to a dashboard or visualization on Knowi and copy the Embed Code from the Share option.

Once acquired, this code can be pasted into HTML. This method is useful for simple embeddings, such as embedding into websites, blogs, or internal knowledge bases, but only very simple embedding scenarios should use the embed code.
Note: The JavaScript API is recommended for more control of the look and feel. It is not significantly more work to embed with the JavaScript API and doing so will gain you flexibility and power in your embedded deployment.
Embedding with an iFrame
The basic embed code using the iFrame looks something like this:
HTML:

The secure embed code using the iFrame looks something like this:

iFrame Resources
The JavaScript API is an alternative approach to the iFrame embed method. Use the Knowi JavaScript API to integrate Knowi visualizations into your own web applications. The Javascript API provides better functionality to match the intended look and feel for your end-users.
Some of the things that you can do with the JavaScript API:
Try the Interactive Embed Demo to experiment with SSO, Secure URL, and Public URL embed modes with live theme switching.
<script src="https://www.knowi.com/minify/knowi-api.min.js"></script>
div element in the page body where you want to insert the Knowi visualization:
<div id="knowi-div"></div>
function loadChart() {
Knowi.render('#knowi-div', {
type: 'share',
dashboard: 'BYhXXCeu0Ego8zA1FqtLOOM4BDWot5AYBLI7PWrQTbsie',
url: "https://www.knowi.com/",
view: {
title: true,
header: true
}
}, function () {
});
}
Note: The complete Javascript API Reference to customize your embed is here.
loadChart();
The full code sample from the above example can be found here.
To use the JavaScript API object specified below, be sure to specify the URL to the JavaScript API file in your web page. For more information, see Embedding with Javascript API or code samples. The JavaScript API file is a library that contains functions for interacting with the JavaScript API. It's a minified file and production-ready to be downloaded by the browser.
This section defines the available options for configuring the Knowi Javascript Class.
| Name | Type | Descriptions |
|---|---|---|
| type | string | type of asset/view to embed Supported values: share for dashboard, secure for secure hash dashboard, shareWidget for widget, shareWidgetSecure for secure hash widget, single for single sign-on, nlp for natural language query |
| dashboard | string | share URL of dashboard/widget |
| dashboardId | integer | ID of dashboard/widget |
| hash | string | Encrypted hash from secure share dashboard/widget. Must be used with type: secure, shareWidgetSecure |
| token | string | session token from Single Sign-On. Needed with type: single |
| renderType | string | specifies how embed will be rendered. Options are object, iframe. Defaults to iframe |
| url | string | url for on-premise deployments. Defaults to www.knowi.com |
| themeId | string | ID of a custom theme to apply to the embedded content. Overrides the dashboard-level theme. Widget-level themes, custom widget properties, and custom CSS take precedence over themeId. |
| view | Object | customizable options for the embedded display. |
This section defines the available options for configuring the view object from the Knowi class.
| Name | Type | Descriptions |
|---|---|---|
| title | bool | enable widget title and action menus |
| filter | true | false | "dashboard" | control filter icon visibility (widget filter icons and dashboard filter icon). true = show, false = hide, "dashboard" = respect dashboard setting. Dashboard filters themselves remain visible. |
| autoHeight | bool | automatically adjust dashboard height to div |
| border | bool | enable borders around the widget |
| widgetSpacing | bool | spacing between widgets (px). Possible values between 0-200 |
| setting | bool | enable widget settings |
| resize | bool | enable widget on a dashboard to be resized |
| drag | bool | enable widget on a dashboard to be rearranged |
| scroll | bool | enable scroll on a dashboard |
| header | bool | enable dashboard header including dashboard name and settings |
| dashListIcon | bool | enable/disable the dashboard listing dropdown (defaults to true) Note: Only applicable for 'single' type of embed. (since the others have it off by default). |
| backgroundColor | string | background-color of dashboard Supported formats: rebeccapurple, HEX value: #92a8d1, RGB: rgb(201, 76, 76), RGBA: rgba(201, 76, 76, 0.6) |
| analytics | bool | enable Ad-hoc Analytics mode for widgets. Applicable with types: shareWidget, shareWidgetSecure |
| aiAgent | bool | enable Agentic AI capabilities (defaults to false) |
| chat | bool | enable customer support chat |
| menu | bool | enable side menu bar with system actions as needed |
| menuOptions | Object | disable side navigation menu. Defaults to showing all menu options. Applicable with type: single Available options: Read more about menu options below.
|
| css | array | inject custom CSS files to override the default styling. Example: ['https://knowi-web.s3.amazonaws.com/css/custom1.css', '...'] |
| contentFilters | array | JSON array of user content filters. Applicable with types: share, shareWidget Example: [{"fieldName": "department", "values": ["sales", 19], "operator": "="}, {...}] |
| nlpOptions | Object | customizable settings for NLP search bar. Applicable with type: nlp
|
| dashFilterBar | bool | enable dashboard filters top bar |
| dashFiltersIconToSidePanel | bool | enable filter icon in top filters bar clickable, which open up the right side dashboard filters panel |
The menu options available are:
Your own custom CSS can be injected into the API. Simply specify a comma separated list of CSS files and their full path during the initialization.
Knowi.render('#cloud9charts', {
type: 'touchdown',
username: 'name',
password: 'pass',
view: {
title: true,
css: ['https://knowi-web.s3.amazonaws.com/css/custom1.css', 'https://knowi-web.s3.amazonaws.com/css/custom2.css']
},
}, function() {
alert("Loaded")
});
Try the Interactive Embed Demo to test view options, themes, and embed modes.
To pass in filters:
Knowi.render('#cloud9charts', {
type: 'share',
dashboard: 'CnzzWr6ZGrii4BYsa295HoVWzNB7VaZey6StgO1uFw2kie'
view: {
title: true,
contentFilters: [
{
"fieldName":
"opened",
"values":[1000],
"operator":">"
},
{
"fieldName":"message_type",
"values":["marketing"],
"operator":"="
}
]
},
}, function() {
alert("Loaded")
});
Note: Secure URL modes requires contentFilters to be encrypted.
To apply a custom theme to an embedded dashboard, pass the theme ID as themeId in the top-level configuration object:
Knowi.render('#knowi-div', {
type: 'single',
token: 'YOUR_SESSION_TOKEN',
themeId: 'YOUR_THEME_ID',
view: {
title: true,
// ...
}
}, function() {});
Theme styling is applied in the following order of precedence (highest to lowest):
themeIdthemeId overrides any dashboard-level theme configured in Knowi. However, widgets with explicit theme assignments (e.g., "light" or "dark") are unaffected -- only widgets inheriting their theme from the dashboard will reflect the themeId value.
Try the Interactive Embed Demo to see theme switching in action across all embed modes.
In addition to dashboard level embed options outlined above, you can also share a widget by itself. To generate a shareable URL for a widget, click on 'Generate Shareable URL' from the 'Share' tab of the widget options dropdown.
Note: This makes the widget publicly accessible, without requiring a login. Do not use this option for sensitive data.
To turn off a unique public URL, click on 'Disable Share URL'.
Include the Javascript API:
<script src="//www.knowi.com/minify/knowi-api.min.js"></script>
To render Knowi widget on a page, add the following javascript:
Knowi.render('#myDiv', {
type: 'shareWidget',
widget: 'nZcdj3DThlSDuZhrh6E8KVP9TLZFStoWWAOCGh8zP0cie'
}, function () {
alert("Loaded");
});
The content filters also can be passed to widget same as for dashboards.
If the widget is a Data Grid with Navigation Mode set to Paged, the embed loads page 1 and renders the same Prev/Next, numbered page buttons, and (if enabled) total count as in the dashboard. Paging through the embedded grid re-requests each page from the datasource, the same as in a normal dashboard view.
Knowi allows you to embed the Presentation mode for a specific dashboard. This includes embedding with SSO, share URL, iframe, Knowi JS library, i.e. all kinds of embedding. To embed the presenter, you need to enable the "presenterOptions" field in the View Object Reference.
Here is an example:
function loadChart() {
Knowi.render('#knowi-div', {
type: 'secure',
hash: "rcf9rdm6zTDd6KIz9EblkO0e0BfEFF0SCjH9RABg=",
dashboard: "4kjl45kipgqULyXaT5fAUD3ipIypbipPNq2wm6D197pJKCnQnTx",
view: {
title: true,
border: true,
header: true,
backgroundColor: "lightblue",
setting: true,
presenterOptions: {
instantSights: true,
hideCloseIcon: true,
loop: true,
excludeGrids: true,
autoAdvance: 10
}
}
}, function () {
});
}
This Presenter object includes more options such as:
| Name | Descriptions | :
|---|---|
| instantSights | includes plain English insights from the widget |
| hideCloseIcon | hides the X button in the Presenter, so user will not be able to return to dashboard |
| loop | loops through the slides from the beginning once finished |
| excludeGrids | excludes grid widgets |
| autoAdvance | auto rotate slides, in seconds. If not set, then it will be user-driven |
Scaling an embedded analytics deployment of Knowi often means providing content to different groups of users. There is a security implication of making sure the different groups do not see each others' data (and metadata). There is also a deployment and maintenance consideration: Common dashboards should have to be built only once, even if the different groups of users access different data with those common dashboards.
With Knowi Embedded, there are three main fundamental approaches to maintaining separation between tenants.
A single tenant architecture provides a dedicated Knowi server for each tenant. This deployment architecture is suitable when there may be restrictions that mandate that data of different tenants can't be located on the same physical machine.
Row-level security is both a security and content management concern. The simplest way to make sure users only see their data is to manually build a dashboard for each of them. This is not scalable, so Knowi provides a variety of ways to build a single dashboard that is filtered to the correct data. The correct method to use depends on your data environment.
Here is some guidance (details for each of the methods are below):
Knowi dashboards and widgets can now be embedded without requiring browser cookies to be enabled on the viewer side. This enhancement addresses common viewing issues that previously occurred in private browsing mode or when using cookie-blocking technologies.
Key Improvements
Embedding without cookies is supported for the following methods: - URL Embedding - Secure URL Embedding - JavaScript API - iFrame Embedding
Embedding without cookies is enabled by default. No additional configuration is required; the transition is seamless for both new and existing embedded deployments. To verify, view your embedded dashboard using a private browser window.
Embedding without cookies is not supported for: - SSO Embedding
SSO embedding depends on maintaining an authenticated session between the viewer's browser and the identity provider (such as SAML or OAuth). This session information is managed through browser cookies. Without cookies, authentication sessions cannot persist, causing SSO-based embedding to fail.
As a result, when using SSO embedding, users must allow cookies in their browsers to ensure proper authentication and access to embedded content.
Why This Matters: The Challenge of Third-Party Cookies
When embedding Knowi dashboards into external websites (e.g., embedding a Knowi dashboard on yoursite.com), browser cookies are traditionally used to manage user sessions. However, because these cookies originate from knowi.com, they are considered third-party cookies.
Modern browsers often block third-party cookies by default, particularly in private browsing modes or when privacy-enhancing tools are enabled. This can prevent embedded dashboards from loading correctly or require users to manually enable cookies.
Embedding without cookies removes this dependency, ensuring seamless dashboard access across all browsing environments for supported embedding methods.
In addition to embedding dashboards and widgets, you can embed Knowi's Agentic BI chat interface -- giving your users a conversational AI experience directly inside your application.
There are two approaches:
SSO Chat Embed -- Drop the full Knowi chat UI into your app via iframe using Knowi.render() with type: 'aiConverse'. Your users get the same chat experience with built-in features like data source selection, suggestions, chat history, and themes.
Headless Chat API -- Build your own custom chat UI using the REST endpoints at /api/v1/agent/chat (synchronous) and /api/v1/agent/chat/stream (streaming via Server-Sent Events).
For full documentation including SSO setup, API reference, request/response schemas, code examples, and an interactive demo, see Embedding Agent Chat.