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.
| Role | What they see |
|---|---|
| Sellers | Sales Performance, Inventory, Reviews |
| Buyers | Order History, Spending Analytics |
| Admins | Platform 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:
- Map each role to a set of dashboards in your backend
- Put that set in
objects.dashboardswhen generating the embed token - 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}`;
}
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.
| Layer | What it controls | How it works |
|---|---|---|
Dashboard selection (objects.dashboards) | Which dashboards the user can access | Backend maps role to a dashboard list |
Row-level permissions (user_attributes or permissions.row_based) | Which data rows the user sees within those dashboards | Rules 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.