Skip to main content

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.

PlanCapabilities
BasicView dashboards
ProView + Explore data
EnterpriseView + 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:

  1. Which dashboards: objects.dashboards lists the dashboards for the plan
  2. Whether they can explore: including datasets in objects.datasets enables exploration; omitting them creates a view-only experience
  3. Whether they get Ask AI: settings.ai.enabled controls 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:

FeatureHow to enableTypical tier
Personal workspacepermissions.enable_personal_workspace: truePro+
Shared workspacepermissions.org_workspace_role: 'editor'Enterprise
Email subscriptionssettings.allow_data_subscribe: truePro+
Dashboard exportsettings.allow_dashboard_export: truePro+
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.


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