Dynamic data sources for embedded analytics
Introduction
When implementing embedded analytics, you often need to serve customers who each have their own separate databases. Rather than creating duplicate dashboards for every customer, you can configure a single embedded dashboard that dynamically connects to the appropriate database based on which customer is viewing it.
This guide walks you through setting up Dynamic Data Sources for embedded analytics. You'll learn how to pass a data source identifier in your embed payload and have Holistics automatically route queries to the correct database.
How it works
Before diving into implementation, here's how the dynamic data source mechanism works at a high level:

The flow works like this:
- Your backend identifies the customer - When a user accesses your embedded dashboard, your application determines which database they should connect to
- You pass the data source in the embed payload - Your backend includes a
data_sourceuser attribute in the signed embed token - Holistics routes the query - When the dashboard loads, Holistics reads the
data_sourceattribute and directs all queries to the specified database connection
This approach lets you maintain a single dashboard definition while serving data from multiple customer databases.
For a deeper understanding of the underlying mechanism, see Dynamic Data Source in the Development documentation.
Dynamic data source implementation
Follow these five steps to configure dynamic database connections for your embedded dashboards.
Step 1: Connect your client databases
First, connect all of your customers' databases to Holistics.
When naming each data source, use a unique and meaningful identifier (e.g., customer_acme, customer_globex). You'll reference these names in your embed payload to specify which database to use.
Step 2: Create the data_source user attribute
Before you can pass the data_source value in your embed payload, you need to define it as a user attribute in Holistics.
Navigate to Settings > User Attributes and create a new attribute named data_source. See User Attributes Documentation for detailed instructions.

Step 3: Create a dynamic variable in AML
Next, create an AML variable that reads the user attribute and provides a fallback value.
Go to the Development tab, create a new file (e.g., embedded_variables.aml), and add:
const client_data_source = if (H.current_user.data_source) {
H.current_user.data_source
} else {
'default_data_source'
}
The fallback value ('default_data_source') is used when no data_source attribute is provided - useful for testing or default behavior.
You can name the file and variable anything you like, as long as the file ends with .aml and the variable name is valid AML syntax.
Step 4: Update your dataset configuration
Modify the dataset that powers your embedded dashboard to use the dynamic variable:
Dataset dynamic_client_dataset {
label: 'Dynamic Client Dataset'
data_source_name: client_data_source
models: [orders]
relationships: []
}
Now the dataset will connect to whichever data source is specified in the embed payload.
Step 5: Pass data source in your embed payload
Finally, when generating the embed token on your backend, include the appropriate data source name based on the logged-in customer:
// Embedded payload
embedded_payload = {
permissions: {},
user_attributes: {
data_source: ['customer_acme'] // Replace with the customer's data source name
}
}
Your backend logic should determine the correct data source name based on your customer identification system.
Testing in embed sandbox
Before deploying to production, use the Embed Sandbox to verify your dynamic data source configuration works correctly. You can test different data_source values and confirm that queries route to the expected databases.

Alternative: Dynamic schema
If your customers share the same database but use different schemas (common in multi-tenant architectures), you can use schema instead of data_source. The setup follows the same pattern—the key difference is where you apply the variable.
Instead of setting data_source_name at the dataset level, you interpolate the schema into table_name or query at the model level:
// Define the variable (same pattern as data_source)
const client_schema = if (H.current_user.schema) {
H.current_user.schema
} else {
'default_schema'
}
// Use in TableModel
Model dynamic_model {
type: 'table'
data_source_name: 'my_wh'
table_name: '${client_schema}.cities'
}
// Or in QueryModel
Model dynamic_query_model {
type: 'query'
data_source_name: 'my_wh'
query: @sql
select * from ${client_schema}.cities
;;
}
Then pass the schema in your embed payload:
embedded_payload = {
permissions: {},
user_attributes: {
schema: ['tenant_acme']
}
}
Supported variables reference
Holistics provides two built-in user attribute variables for dynamic database connections:
| Variable | Purpose | Use in |
|---|---|---|
H.current_user.data_source | Switch between different database connections | Dataset's data_source_name |
H.current_user.schema | Switch between schemas within the same database | Model's table_name or query |
You can use both variables together if your architecture requires switching both data sources and schemas:
embedded_payload = {
permissions: {},
user_attributes: {
data_source: ['customer_acme'],
schema: ['production']
}
}