Skip to main content

Show different dashboards to different users

Introduction​

Control which dashboards each user sees based on their role. On a marketplace platform, sellers see sales and inventory dashboards, buyers see order history and spending analytics, and admins get a platform-wide overview. Each sees only what's relevant to them.

RoleWhat they see
SellersSales Performance, Inventory, Reviews
BuyersOrder History, Spending Analytics
AdminsPlatform Overview, Seller Metrics

This is different from row-level permissions, which control what data a user sees within a dashboard. Role-based access controls which dashboards they see in the first place.

How it works​

Because the embed payload lists the dashboards to show, your backend simply picks a different list for each role:

  1. Map each role to a set of dashboards in your backend
  2. Put that set in objects.dashboards when generating the embed token
  3. Users see their dashboards: the embed shows only what the payload lists, with built-in navigation between them
User logs in → Backend checks role → Picks dashboards → Signs payload → User sees their dashboards

Step-by-step implementation​

Step 1: Map roles to dashboards​

In your backend, define which dashboards (and optionally datasets) each role gets. Dashboards are referenced by their unique name in AML.

const ROLE_OBJECTS = {
seller: {
dashboards: ['sales_performance', 'inventory_status', 'product_reviews'],
datasets: ['seller_data'], // lets sellers explore their own data
},
buyer: {
dashboards: ['order_history', 'spending_analytics', 'product_reviews'],
datasets: ['buyer_data'],
},
admin: {
dashboards: ['platform_overview', 'seller_metrics'],
datasets: ['platform_data'],
},
};

A dashboard can appear in more than one role. Here, product_reviews is available to both sellers and buyers.

Step 2: Build the payload from the role​

When generating the embed token, look up the user's role and put the matching objects in the payload.

function generateEmbedUrl(user) {
const regionDomain = 'secure'; // Use 'us' or 'eu' for US/EU accounts. For custom domains, replace the full host.

const payload = {
objects: ROLE_OBJECTS[user.role], // This selects which dashboards the user sees
embed_user_id: user.id,
embed_org_id: user.orgId,
exp: Math.floor(Date.now() / 1000) + 3600,
};

const token = jwt.sign(payload, EMBED_SECRET, { algorithm: 'HS256' });
return `https://${regionDomain}.holistics.io/embed/${EMBED_KEY_ID}?_token=${token}`;
}
info

Dashboard selection happens inside the embed payload, which is signed. Users can't reach a dashboard that isn't in their payload by modifying the URL. They only see what your backend assigns to them.

Step 3: Embed in your frontend​

The frontend code is the same for every role. No changes needed. The dashboard selection is entirely handled by the backend.

<iframe
src="<%= generateEmbedUrl(currentUser) %>"
width="100%"
height="600"
frameborder="0"
></iframe>

Combining with row-level permissions​

Role-based dashboard selection and row-level permissions serve different purposes, and you can use them together for fine-grained control.

LayerWhat it controlsHow it works
Dashboard selection (objects.dashboards)Which dashboards the user can accessBackend maps role to a dashboard list
Row-level permissions (user_attributes or permissions.row_based)Which data rows the user sees within those dashboardsRules filter query results per viewer

For example, sellers should see the seller dashboards, but each seller should only see their own sales data:

function generateEmbedUrl(user) {
const regionDomain = 'secure'; // Use 'us' or 'eu' for US/EU accounts. For custom domains, replace the full host.

const payload = {
objects: ROLE_OBJECTS[user.role], // Controls which dashboards they see
embed_user_id: user.id,
embed_org_id: user.orgId,
user_attributes: {
seller_id: [user.sellerId], // Controls which data they see
},
exp: Math.floor(Date.now() / 1000) + 3600,
};

const token = jwt.sign(payload, EMBED_SECRET, { algorithm: 'HS256' });
return `https://${regionDomain}.holistics.io/embed/${EMBED_KEY_ID}?_token=${token}`;
}

For more on setting up row-level permissions, see the Row-level permissions guide.

Optional: Persist each role as an Embed Portal​

If you'd rather your data team manage each role's dashboard set inside Holistics, define one Embed Portal per role (such as seller_portal and buyer_portal). Your backend then maps the role to a portal name and sets embed_portal: ROLE_PORTAL_MAP[user.role] instead of listing objects. Analysts can add or remove a role's dashboards by editing the portal and publishing, with no backend change or redeploy.

Example: SaaS with tiered plans​

The same technique works for subscription-based access. Pick the dashboards and datasets based on the user's plan instead of their role.

For a complete guide on monetizing analytics with subscription tiers (including how to gate features like data exploration and Ask AI), see SaaS Tiered Plans.

Best practices​

  • Combine with row-level permissions: dashboard selection controls which dashboards a user sees, while row-level permissions control which data they see. Use both together for the most secure setup.
  • Keep the mapping in one place: a single role-to-objects map in your backend (or one portal per role) is easier to audit than conditions scattered across your code.
  • Test each role: use the Embed Builder to preview the payload for each role and confirm every role sees the right set of dashboards.
  • Reuse dashboards across roles: a dashboard can belong to several roles. You don't need to duplicate dashboards just because two roles need to see the same one.

Open Markdown
Let us know what you think about this document :)