Monetize Analytics with Subscription Tiers
Introduction
Turn your embedded analytics into a revenue driver by offering different capabilities at each subscription tier. Basic users get view-only dashboards, Pro users can explore and customize, and Enterprise users get AI-powered insights.
| Plan | Capabilities |
|---|---|
| Basic | View dashboards |
| Pro | View + Explore data |
| Enterprise | View + Explore + Ask AI |
This approach lets you:
- Create upsell opportunities: users see the value of higher tiers through feature limits
- Match pricing to value: charge more for self-service exploration and AI
- Reduce support load: higher-tier users answer their own questions
How it works
Everything a tier can do is decided by the embed payload your backend signs, so gating features is a matter of building a different payload per plan:
- Which dashboards:
objects.dashboardslists the dashboards for the plan - Whether they can explore: including datasets in
objects.datasetsenables exploration; omitting them creates a view-only experience - Whether they get Ask AI:
settings.ai.enabledcontrols Ask AI access
Basic: dashboards only → View only
Pro: dashboards + datasets → View + Explore
Enterprise: dashboards + datasets + AI enabled → View + Explore + Ask AI
Step-by-step implementation
Step 1: Define the objects for each tier
Map each plan to its dashboards and datasets. The key difference between Basic and Pro is whether you include datasets.
const PLAN_OBJECTS = {
basic: {
dashboards: ['overview_dashboard'],
// No datasets = view-only experience
},
pro: {
dashboards: ['overview_dashboard', 'sales_analytics', 'customer_insights'],
datasets: ['sales_data'], // Dataset enables exploration
},
enterprise: {
dashboards: ['overview_dashboard', 'sales_analytics', 'customer_insights', 'executive_summary'],
datasets: ['sales_data', 'operations_data'], // Datasets enable exploration and Ask AI
},
};
Why datasets matter:
- Without datasets, users can only view pre-built dashboards
- With datasets, users can click into charts, change groupings, add filters, and save custom views
- Ask AI also requires datasets to answer questions
Step 2: Build the payload from the plan
Look up the user's plan, put the matching objects in the payload, and enable AI for Enterprise users.
function generateEmbedUrl(user) {
const regionDomain = 'secure'; // Use 'us' or 'eu' for US/EU accounts. For custom domains, replace the full host.
const payload = {
objects: PLAN_OBJECTS[user.plan],
embed_user_id: user.id,
embed_org_id: user.orgId,
settings: {
ai: {
enabled: user.plan === 'enterprise', // Only Enterprise gets Ask AI
}
},
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}`;
}
Step 3: Embed in your frontend
The frontend code is the same regardless of tier. All the logic is in your backend.
<iframe
src="<%= generateEmbedUrl(currentUser) %>"
width="100%"
height="600"
frameborder="0"
></iframe>
Multi-tenant data isolation
In a SaaS application, you'll also want each customer to see only their own data. Combine plan-based objects with row-level permissions using user_attributes.
function generateEmbedUrl(user) {
const regionDomain = 'secure'; // Use 'us' or 'eu' for US/EU accounts. For custom domains, replace the full host.
const payload = {
objects: PLAN_OBJECTS[user.plan],
embed_user_id: user.id,
embed_org_id: user.orgId,
user_attributes: {
client_id: [user.clientId], // Each client sees only their data
},
settings: {
ai: {
enabled: user.plan === 'enterprise',
}
},
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}`;
}
This ensures:
- Plan-based objects control which dashboards and features they get (based on subscription)
- Row-level permissions control which data they see (based on their client or tenant ID)
For setup details, see the Row-level permissions guide.
Additional features by tier
Beyond the core view/explore/AI progression, you can gate other features:
| Feature | How to enable | Typical tier |
|---|---|---|
| Personal workspace | permissions.enable_personal_workspace: true | Pro+ |
| Shared workspace | permissions.org_workspace_role: 'editor' | Enterprise |
| Email subscriptions | settings.allow_data_subscribe: true | Pro+ |
| Dashboard export | settings.allow_dashboard_export: true | Pro+ |
function generateEmbedUrl(user) {
const regionDomain = 'secure'; // Use 'us' or 'eu' for US/EU accounts. For custom domains, replace the full host.
const payload = {
objects: PLAN_OBJECTS[user.plan],
embed_user_id: user.id,
embed_org_id: user.orgId,
permissions: {
enable_personal_workspace: user.plan !== 'basic',
org_workspace_role: user.plan === 'enterprise' ? 'editor' : 'no_access',
},
settings: {
ai: { enabled: user.plan === 'enterprise' },
allow_dashboard_export: user.plan !== 'basic',
allow_data_subscribe: user.plan !== 'basic',
},
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}`;
}
Optional: Persist each tier as an Embed Portal
If you'd rather your data team manage what each tier includes from inside Holistics, define one Embed Portal per tier (such as basic_portal and pro_portal) and set embed_portal: PLAN_PORTAL_MAP[user.plan] in the payload instead of listing objects.
Feature flags such as AI, exports, and workspaces stay in the payload either way, since they describe the viewer rather than the content.
Related guides
- Dashboards by user role: show different dashboards to different user roles
- Self-serve exploration: enable data exploration features
- Ask AI: set up AI-powered analytics
- Embed payload reference: full list of embed payload options