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

  1. Create a portal for each role — Each portal contains only the dashboards that role needs
  2. Your backend selects the portal — When generating the embed token, set object_name to the appropriate portal based on the user's role
  3. 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.)

seller_portal.embed.aml
EmbedPortal seller_portal {
objects: [
sales_performance, // dashboard
inventory_status, // dashboard
seller_data, // dataset
]
}
buyer_portal.embed.aml
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_portal and buyer_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}`;
}
info

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.

LayerWhat it controlsHow it works
Portal selection (object_name)Which dashboards the user can accessBackend maps role → portal name
Row-level permissions (user_attributes)Which data rows the user can see within those dashboardsUser 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_portal or buyer_portal rather than portal_1 or portal_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.

Let us know what you think about this document :)