How to initiate Tableau data source refreshes from backend with WebSockets
When Tableau is Embedded in a web app or a client portal, imagine a scenario where a user submits new data or parameters through a backend process. Once the underlying database completes saving this data, the corresponding changes need to be reflected in the frontend. How can we achieve this seamlessly, ensuring that the data on the dashboard is always up-to-date?
This article explores a solution to this challenge by demonstrating how to initiate a Tableau data source refresh from the backend via WebSockets. We’ll walk you through the steps to set up a system that allows for real-time updates in a frontend application with the Tableau Embedded Dashboard. The beauty of this approach is that it enables specific targeting for refreshes if needed, giving you full control over your data.
NOTE: DO NOT use this solution to create auto-refreshing dashboards, such as those used in call centers, as this is not permitted by Tableau Cloud, and your site could be blocked. Use this only for the specified cases where an occasional backend-initiated refresh is needed, for instance, when critical user-defined parameters alter the underlying database data.
Full Codebase can be found here:
https://github.com/Tab-SE/tab_backend_ds_refresh_websocket
Prerequisites
Before we dive into the implementation, here are the prerequisites you’ll need:
- Node.js installed.
- A running Tableau Server or Tableau Cloud visualization that you’d like to embed and refresh.
Implementation
Let’s break down the implementation into two main parts: the frontend and the backend.
Frontend
In the frontend, we’ll establish a WebSocket connection with the backend and listen for refresh commands. Here’s the detailed explanation:
1. Import Libraries and Initialize WebSocket
We begin by importing the necessary libraries, including the Tableau Embedding API, and initializing the WebSocket connection.
- We import the Tableau Embedding API to work with Tableau visualizations.
- We set up an event listener for when the DOM is loaded, ensuring our JavaScript code runs after the page is ready.
- We initialize a WebSocket connection and define a function (
triggerBackend
) to handle backend-initiated refreshes.
2. Establish WebSocket Connection
Now, let’s establish the WebSocket connection and handle messages from the backend:
- We create a function
initializeWebSocket
to set up the WebSocket connection. - We specify the WebSocket server URL (
ws://localhost:3000
) to connect to the backend. - We define event listeners for the WebSocket connection’s open state and incoming messages.
3. Simulate Backend Refresh
To simulate a backend-initiated refresh from the frontend, we define the triggerBackend
function:
- We check if the
clientUUID
is defined, which indicates that the WebSocket connection is established. - If
clientUUID
exists, we use thefetch
API to add the client UUID to the refresh list on the backend (/add-to-refresh-list/:uuid
) and trigger the backend refresh (/trigger-refresh
).
4. Refresh Tableau Data
Finally, when the backend-initiated refresh is received or when the user interacts with the Tableau visualization, we call the refreshTableauData
function:
- This function uses the Tableau Embedding API to refresh the data source asynchronously.
- After a successful refresh, a message is displayed in the UI with the current time.
Backend
In the backend, we set up an Express.js server that handles WebSocket connections and refresh commands. Here’s how it works:
1. WebSocket Server and Client Registration
We create a WebSocket server using the ws
library, and clients receive a unique UUID upon connection.
- We initialize a WebSocket server and listen for client connections.
- Each connected client receives a unique UUID generated using the
uuidv4
library. - We maintain a map of client UUIDs to WebSocket connections.
2. Triggering Refresh
We provide two options for triggering refreshes: broadcasting to all clients or targeting specific clients.
- We check the value of
BROADCAST_TO_ALL
to determine whether to broadcast the refresh to all clients or specific ones. - If
BROADCAST_TO_ALL
istrue
, we loop through all connected clients and send a refresh command to those with an open WebSocket connection. - If
BROADCAST_TO_ALL
isfalse
, we loop through theclientsToRefresh
set, which contains UUIDs of specific clients to target for refresh. - We use the WebSocket connections stored in
clientMap
to send refresh commands to the selected clients. - A response is sent to the requester to confirm the refresh.
3. Adding Clients to the Refresh List
We provide an endpoint to add a client to the list of clients to be refreshed.
Clients can access this endpoint with their UUID as a parameter to add themselves to the clientsToRefresh
set.
- The UUID is added to the set, indicating that this client should receive refresh commands.
4. Configuration
You can easily configure the behavior of the backend by changing the value of BROADCAST_TO_ALL
:
- Set
BROADCAST_TO_ALL
totrue
if you want to broadcast refresh commands to all connected clients. - Set it to
false
if you prefer to target specific clients based on the UUIDs stored in theclientsToRefresh
set.
By following this method, you empower your Tableau Embedded clients to maintain synchronization with the most up-to-date data.