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
- Create a portal for each role — Each portal contains only the dashboards that role needs
- Your backend selects the portal — When generating the embed token, set
object_nameto the appropriate portal based on the user's role - Users see their dashboards — The embedded portal shows only the dashboards you've assigned
User logs in → Backend checks role → Selects portal → User sees their dashboards
Step-by-step implementation
Step 1: Define a portal for each role
Create a separate .embed.aml file for each role. Each portal includes only the dashboards and datasets that role needs. (See Define your portal for the basics.)
EmbedPortal seller_portal {
objects: [
sales_performance, // dashboard
inventory_status, // dashboard
seller_data, // dataset
]
}
EmbedPortal buyer_portal {
objects: [
order_history, // dashboard
spending_analytics, // dashboard
buyer_data, // dataset
]
}
A few things to note:
- Dashboards can appear in multiple portals. For example, a "Reviews" dashboard could be included in both
seller_portalandbuyer_portal. - You need to publish all portals to production for them to be available for embedding. See Publishing to production.
Step 2: Select the portal in your backend
In your backend, map each user role to the corresponding portal name, and use that when generating the embed token.
// Map roles to portal names
const ROLE_PORTAL_MAP = {
seller: 'seller_portal',
buyer: 'buyer_portal',
admin: 'admin_portal',
};
function generateEmbedUrl(user) {
const portalName = ROLE_PORTAL_MAP[user.role];
const embed_payload = {
object_name: portalName, // This selects which portal the user sees
object_type: 'EmbedPortal',
embed_user_id: user.id,
embed_org_id: user.orgId,
exp: Math.floor(Date.now() / 1000) + 3600,
};
const token = jwt.sign(embed_payload, EMBED_SECRET, { algorithm: 'HS256' });
return `https://holistics.io/embed/${EMBED_KEY_ID}?_token=${token}`;
}
Portal selection happens inside the embed payload, which is encrypted. Users can't switch to a different portal by modifying the URL, they only see what your backend assigns to them.
Step 3: Embed in your frontend
The frontend code is exactly the same as a single-portal setup. No changes needed — the portal 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 portal access and row-level permissions serve different purposes, and you can use them together for fine-grained control.
| Layer | What it controls | How it works |
|---|---|---|
Portal selection (object_name) | Which dashboards the user can access | Backend maps role → portal name |
Row-level permissions (user_attributes) | Which data rows the user can see within those dashboards | User attributes filter query results |
For example, sellers should see the seller portal, but each seller should only see their own sales data. Here's how you'd combine both:
function generateEmbedUrl(user) {
const portalName = ROLE_PORTAL_MAP[user.role];
const embed_payload = {
object_name: portalName, // Controls which dashboards they see
object_type: 'EmbedPortal',
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(embed_payload, EMBED_SECRET, { algorithm: 'HS256' });
return `https://holistics.io/embed/${EMBED_KEY_ID}?_token=${token}`;
}
For more on setting up row-level permissions, see the Row-level Permission guide.
Example: SaaS with tiered plans
The same technique works for subscription-based access. Create a portal for each tier (Basic, Pro, Enterprise) and select 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 — Portal selection controls which dashboards a user sees, while row-level permissions control which data they see. Use both together for the most secure setup.
- Name portals descriptively — Use names like
seller_portalorbuyer_portalrather thanportal_1orportal_a. It makes your code and AML definitions easier to maintain. - Test each portal — Preview each portal in the Holistics development environment before publishing. Make sure every role sees the right set of dashboards.
- Reuse dashboards across portals — A dashboard can belong to multiple portals. You don't need to duplicate dashboards just because two roles need to see the same one.