Interactive Dashboards as Application Components
Data visualization layers often live in a separate analytics tool, isolated from the application that needs them. Cumul.io takes a different approach: dashboards are embedded directly into applications, and custom events allow those dashboards to trigger actions back in the host app. To demonstrate, we built a Spotify Playlist analytics demo that uses Cumul.io dashboards displaying data from the Kaggle Spotify Dataset 1921–2020 plus live data from the Spotify Web API when a user logs in.
The demo lets visitors interact with charts and, via Cumul.io custom events, add songs to their own Spotify playlists, view additional information about a selected track, and play it—all from within the application. The full code is available in an open repository, and a boiled-down version focused on custom events is in the cumulio-spotify-datatalks repo.


Understanding Custom Events
Cumul.io custom events are a mechanism for triggering events from a dashboard chart to be consumed by the application that hosts the dashboard. The key characteristic is that events are attached to individual charts, not to a dashboard as a whole. The payload is a JSON object that includes the triggering dashboard's ID, the event name, and other fields that depend on the chart type. For example, an event from a scatter plot contains the x and y values of the clicked point, while an event from a table contains column values.
// 'Add to Playlist' custom event from a row in a table
{
"type":"customEvent",
"dashboard":"xxxx",
"name":"xxxx",
"object":"xxxx",
"data":{
"language":"en",
"columns":[
{"id":"Ensueno","value":"Ensueno","label":"Name"},
{"id":"Vibrasphere","value":"Vibrasphere","label":"Artist"},
{"value":0.406,"formattedValue":"0.41","label":"Danceability"},
{"value":0.495,"formattedValue":"0.49","label":"Energy"},
{"value":180.05,"formattedValue":"180.05","label":"Tempo (bpm)"},
{"value":0.568,"formattedValue":"0.5680","label":"Accousticness"},
{"id":"2007-01-01T00:00:00.000Z","value":"2007","label":"Release Date (Yr)"},
],
"event":"add_to_playlist"
}
}
//'Song Info' custom event from a point in a scatter plot
{
"type":"customEvent",
"dashboard":"xxxx",
"name":"xxxx",
"object":"xxxx",
"data":{
"language":"en",
"x-axis":{"id":0.601,"value":"0.601","label":"Danceability"},
"y-axis":{"id":0.532,"value":"0.532","label":"Energy"},
"name":{"id":"xxxx","value":"xxx","label":"Name"},
"event":"song_info"
}
}
This design means the analytics layer remains a completely separate entity—dashboards can be managed independently without touching application code, while events give applications a way to reuse dashboard data for arbitrary actions.
Enabling Events in the Dashboard Editor
Before integrating dashboards into an application, custom events must be configured on the charts in the Cumul.io platform. To do so, select a chart in a dashboard, open its settings, choose Interactivity, and turn Custom Events on. Then click edit to define the event's Event Name (what the application receives) and Label (what appears in the dashboard UI).


In this demo, two events were configured on a scatter plot and table: add_to_playlist and song_info. Finally, note the dashboard ID from the Settings tab; the application will need it for integration.
Embedding the Dashboard
With events enabled, the next step is integrating a dashboard into the application. This walkthrough uses the Cumul.io Spotify Playlist dashboard as the main view and a Song Info dashboard as a drill-through view (a secondary dashboard displayed within the primary one when an event fires). The repository's skeleton commit provides a starting point; at that commit a bare "Cumul.io Favorites" tab appears with a Login button when running npm run start.
All code changes are made in src/app.js. First, store the dashboard IDs and a dashboardOptions object:
// create dashboards object with the dashboard ids and dashboardOptions object
// !!!change these IDs if you want to use your own dashboards!!!
const dashboards = {
playlist: 'f3555bce-a874-4924-8d08-136169855807',
songInfo: 'e92c869c-2a94-406f-b18f-d691fd627d34',
};
const dashboardOptions = {
dashboardId: dashboards.playlist,
container: '#dashboard-container',
loader: {
background: '#111b31',
spinnerColor: '#f44069',
spinnerBackground: '#0d1425',
fontColor: '#ffffff'
}
};
Then create a loadDashboard() function that calls Cumulio.addDashboard(), optionally modifies the dashboardOptions, and loads the playlist dashboard when the Cumul.io Favorites tab is shown:
// create a loadDashboard() function that expects a dashboard ID and container
const loadDashboard = (id, container) => {
dashboardOptions.dashboardId = id;
dashboardOptions.container = container || '#dashboard-container';
Cumulio.addDashboard(dashboardOptions);
};
export const openPageCumulioFavorites = async () => {
ui.openPage('Cumul.io playlist visualized', 'cumulio-playlist-viz');
/**************** INTEGRATE DASHBOARD ****************/
loadDashboard(dashboards.playlist);
};

Listening for Events
After a dashboard is embedded, the host application can listen for incoming custom events via the Cumulio.onCustomEvent() function. These events originate from the two charts that have the add_to_playlist and song_info events enabled:


For this demo the listener function calls listenToEvents() when the Cumul.io Favorites tab loads, then dispatches based on the event received:
const listenToEvents = () => {
Cumulio.onCustomEvent((event) => {
if (event.data.event === 'add_to_playlist'){
//DO SOMETHING
}
else if (event.data.event === 'song_info'){
//DO SOMETHING
}
});
};
Adding a Song to a Playlist
When a user clicks the Add to Playlist event on a point in the Energy/Danceability scatter plot, the application receives the song's name and ID (derived and included as a field in the chart data). These sample events show the payloads:
"name":{"id":"So Far To Go&id=3R8CATui5dGU42Ddbc2ixE","value":"So Far To Go&id=3R8CATui5dGU42Ddbc2ixE","label":"Name & ID"}
"columns":[
{"id":"Weapon Of Choice (feat. Bootsy Collins) - Remastered Version","value":"Weapon Of Choice (feat. Bootsy Collins) - Remastered Version","label":"Name"},
{"id":"Fatboy Slim","value":"Fatboy Slim","label":"Artist"},
// ...
{"id":"3qs3aHNUcqFGv7jMYJJCYa","value":"3qs3aHNUcqFGv7jMYJJCYa","label":"ID"}
]
The application extracts the song name and ID via a getSong() helper, then calls the addToPlaylistSelector() function from src/ui.js. That function opens a window listing the logged-in user's available Spotify playlists and sends the Spotify Web API request to add the selected track.
/*********** LISTEN TO CUSTOM EVENTS AND ADD EXTRAS ************/
const getSong = (event) => {
let songName;
let songArtist;
let songId;
if (event.data.columns === undefined) {
songName = event.data.name.id.split('&id=')[0];
songId = event.data.name.id.split('&id=')[1];
}
else {
songName = event.data.columns[0].value;
songArtist = event.data.columns[1].value;
songId = event.data.columns[event.data.columns.length - 1].value;
}
return {id: songId, name: songName, artist: songArtist};
};
const listenToEvents = () => {
Cumulio.onCustomEvent(async (event) => {
const song = getSong(event);
console.log(JSON.stringify(event));
if (event.data.event === 'add_to_playlist'){
await ui.addToPlaylistSelector(song.name, song.id);
}
else if (event.data.event === 'song_info'){
//DO SOMETHING
}
});
};

Displaying Extended Song Information
The Song Info event demonstrates a more advanced pattern: embedding a Parameterizable Filter. The Song Info dashboard has a songId parameter used in a filter; the application provides a value for that parameter when it creates an authorization token. A dedicated getDashboardAuthorizationToken() function accepts metadata and posts it to the /authorization endpoint of the server running in server/server.js:
const getDashboardAuthorizationToken = async (metadata) => {
try {
const body = {};
if (metadata && typeof metadata === 'object') {
Object.keys(metadata).forEach(key => {
body[key] = metadata[key];
});
}
/*
Make the call to the backend API, using the platform user access credentials in the header
to retrieve a dashboard authorization token for this user
*/
const response = await fetch('/authorization', {
method: 'post',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' }
});
// Fetch the JSON result with the Cumul.io Authorization key & token
const responseData = await response.json();
return responseData;
}
catch (e) {
return { error: 'Could not retrieve dashboard authorization token.' };
}
};
The application then loads the Song Info dashboard with a new token containing the selected song's ID as metadata, and calls ui.displaySongInfo():
const loadDashboard = (id, container, key, token) => {
dashboardOptions.dashboardId = id;
dashboardOptions.container = container || '#dashboard-container';
if (key && token) {
dashboardOptions.key = key;
dashboardOptions.token = token;
}
Cumulio.addDashboard(dashboardOptions);
};
const loadDashboard = (id, container, key, token) =u003e {n dashboardOptions.dashboardId = id;n dashboardOptions.container = container || '#dashboard-container'; nn if (key u0026u0026 token) {n dashboardOptions.key = key;n dashboardOptions.token = token;n }nn Cumulio.addDashboard(dashboardOptions);n};
const listenToEvents = () => {
Cumulio.onCustomEvent(async (event) => {
const song = getSong(event);
if (event.data.event === 'add_to_playlist'){
await ui.addToPlaylistSelector(song.name, song.id);
}
else if (event.data.event === 'song_info'){
const token = await getDashboardAuthorizationToken({ songId: [song.id] });
loadDashboard(dashboards.songInfo, '#song-info-dashboard', token.id, token.token);
await ui.displaySongInfo(song);
}
});
};
This lets the drill-through dashboard render with context—showing detailed characteristics of the selected track, including a play option.
Key Takeaways
- Custom events in Cumul.io work at the chart level; the payload includes fields relevant to that chart's structure.
- Events are configured in the chart settings by enabling the Custom Events toggle and defining an event name and label.
- The application listens with
Cumulio.onCustomEvent()and can then perform any desired action—opening a dialog, another dashboard, an external API call, and so on. - Parameterizable filters allow values to be passed to a drill-through dashboard via authorization token metadata.
Running the Demo
The demo requires a Cumul.io account and a registered application on the Spotify Developer dashboard. To run it locally:
- Clone the cumulio-spotify-datatalks repository and run
npm install. - Create a
.envfile in the root with the following credentials from your Cumul.io and Spotify Developer accounts:- Cumul.io:
CUMULIO_API_KEY=xxxCUMULIO_API_TOKEN=xxx - Spotify:
SPOTIFY_CLIENT_ID=xxxSPOTIFY_CLIENT_SECRET=xxxACCESS_TOKEN=xxxREFRESH_TOKEN=xxx
- Cumul.io:
- Run
npm run start, openhttp://localhost:3000/, and log into your Spotify account.
The decoupled nature of Cumul.io dashboards means application developers can avoid constant dashboard edits, while custom events provide a clean interface to turn dashboard data into application behavior—whether that means playing a track, sending an email, or any other action the payload can support.



