Canvas uses scopes to allow you to display different cuts of your data depending on which of your customers is viewing the embed. You can think of scopes as a grant for your users to see a limited portion of your full data set. If you don't use scopes - or setup your scopes improperly - each of your users will see the entire dataset in your embed. This makes scopes the most important concept to understand when setting up your embeds.

You define your scopes in Canvas and generate scoped grants in your application.


The first step is deciding how you want to segment your data in the embed. For example, you might decide that every user should see only data belonging to that user. Or that every user should see data belonging to the team that they're on.

Next, for every table in your canvas that should be filtered you either find or add a column that will match this scope. This might be an email or user_id column to display data per user, or a team_id or user_domain column to slice it by team.

The column you choose here will be the scope for your embed. When generating the client token for your users you will include a value for this scope.

In Canvas

In Canvas you add a scope filter. This let's you:

  1. Name the scope

  2. Select what values are valid for the scope

  3. Select which tables should be filtered by this scope and how

Last, we click "Embed settings" to deploy the embed. Here we can name the scope (if we want it to be different from the display name in the canvas)

We've now made this canvas embeddable, but required that anyone attempting to view the embed has a token with a grant for the domain scope. If this scope is missing the embed will fail.

In your application

You generate this token in your application backend. This must be done on the backend because it requires using the private encryption key generated by Canvas.

Canvas as multiple client libraries for generating this token. Here's what generating this token looks like in Node:

import { generateToken } from "canvas-embed-node";

const scopes = { user_domain: "" };
const expiration = 60 * 60 * 24 * 7; // expiration time in seconds
const key =
  "emk_XYZabcDe.123456789ae9a932b1e12345a89abc54deed6549f51034b59478388c45c9e123"; // encryption key
const token = await generateToken(scopes, expiration, key);

This token is then shared with the frontend. A user viewing the embed with this token will see only data from rows with their user_domain column matching the value

Because this is an encrypted token the user will be unable to tamper with it and ask for a different domain.

Last updated