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

You control capabilities through two mechanisms:

  1. Portal contents — Including datasets enables exploration; omitting them creates a view-only experience
  2. Embed payload settings — The settings.ai.enabled flag controls Ask AI access
Basic:      Portal (dashboards only)           → View only
Pro: Portal (dashboards + datasets) → View + Explore
Enterprise: Portal (dashboards + datasets) + AI enabled → View + Explore + Ask AI

Step-by-step implementation

Step 1: Create a portal for each tier

Each tier gets its own portal. The key difference is whether you include datasets.

basic_portal.embed.aml
EmbedPortal basic_portal {
objects: [
overview_dashboard,
// No datasets = view-only experience
]
}
pro_portal.embed.aml
EmbedPortal pro_portal {
objects: [
overview_dashboard,
sales_analytics,
customer_insights,
sales_data, // Dataset enables exploration
]
}
enterprise_portal.embed.aml
EmbedPortal enterprise_portal {
objects: [
overview_dashboard,
sales_analytics,
customer_insights,
executive_summary,
sales_data, // Dataset enables exploration
operations_data, // Dataset enables exploration
]
}

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: Select portal and features in your backend

Map each subscription plan to its portal, and enable AI for Enterprise users.

const PLAN_PORTAL_MAP = {
basic: 'basic_portal',
pro: 'pro_portal',
enterprise: 'enterprise_portal',
};

function generateEmbedUrl(user) {
const embed_payload = {
object_name: PLAN_PORTAL_MAP[user.plan],
object_type: 'EmbedPortal',
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(embed_payload, EMBED_SECRET, { algorithm: 'HS256' });
return `https://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 portal selection with row-level permissions using user_attributes.

function generateEmbedUrl(user) {
const embed_payload = {
object_name: PLAN_PORTAL_MAP[user.plan],
object_type: 'EmbedPortal',
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(embed_payload, EMBED_SECRET, { algorithm: 'HS256' });
return `https://holistics.io/embed/${EMBED_KEY_ID}?_token=${token}`;
}

This ensures:

  • Portal selection controls which dashboards and features they get (based on subscription)
  • Row-level permissions controls which data they see (based on their client/tenant ID)

For setup details, see the Row-level Permission 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+
Data exportpermissions.allow_dashboard_export: truePro+
function generateEmbedUrl(user) {
const embed_payload = {
object_name: PLAN_PORTAL_MAP[user.plan],
object_type: 'EmbedPortal',
embed_user_id: user.id,
embed_org_id: user.orgId,
permissions: {
enable_personal_workspace: user.plan !== 'basic',
org_workspace_role: user.plan === 'enterprise' ? 'editor' : null,
allow_dashboard_export: user.plan !== 'basic',
},
settings: {
ai: { enabled: user.plan === 'enterprise' },
allow_data_subscribe: user.plan !== 'basic',
},
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}`;
}

Let us know what you think about this document :)