Embed ThoughtSpot in a Flutter app

Embed ThoughtSpot in a Flutter app

Your application developers can now seamlessly integrate ThoughtSpot’s analytics and insights into their Flutter applications using ThoughtSpot Flutter Embed SDK. The SDK provides the following components to embed a ThoughtSpot Liveboard into a Flutter app.

  • LiveboardEmbedController
    Controls and manages interactions with the embedded content.

  • LiveboardEmbed Widget
    Renders the embedded Liveboard in the Flutter UI.

Before you beginπŸ”—

Before you begin, check if your setup has the following:

  • A Flutter application project setup. For information about creating a Flutter app, see Flutter documentation.

  • Access to a ThoughtSpot instance with administrator and developer privileges.
    Ensure that your host app embedding ThoughtSpot is added to the CSP and CORS allowlists in ThoughtSpot.

  • Access to the Liveboard object that you want to embed.

Get started with embeddingπŸ”—

This section provides a set of steps to quickly embed a ThoughtSpot Liveboard in a Flutter app.

Install the SDKπŸ”—

  1. Download the Flutter embed SDK package to your application setup.

  2. In your Flutter project directory, locate the pubspec.yaml and add the necessary dependencies and import the Flutter SDK.

     dependencies:
     flutter_embed_sdk: ^<latest_version>
  3. Run the following command.

    flutter pub get

Import the SDKπŸ”—

Import the SDK and initialize it in your main.dart file:

import 'package:flutter/material.dart';
import 'package:thoughtspot_flutter_embed/thoughtspot_flutter_embed.dart';

After you import, define the embed configuration and view settings using the LiveboardEmbedController component. The LiveboardEmbedController is the controller object used for configuring the settings required to embed a ThoughtSpot Liveboard in a Flutter app. The LiveboardEmbedController component allows you to do the following:

  • initialize the embed configuration such as ThoughtSpot host URL, authentication method.

  • handle authentication

  • set Liveboard ID, view configuration settings and customization options.

  • configure event listeners and manage app interactions

Your code must include a LiveboardEmbed widget to pass the LiveboardEmbedController component and configuration settings to render embedded Liveboard within your Flutter app.

Specify ThoughtSpot URL and configure authentication settingsπŸ”—

  1. Define the following attributes for EmbedConfig:

    • thoughtSpotHost
      The hostname of your ThoughtSpot application instance. For example, team2.thoughtspot.cloud. See FAQs to know how to find the hostname of your application instance.

    • authType
      Authentication type. In the current version, mobile embedding supports only the Cookieless Trusted authentication method (AuthType.TrustedAuthTokenCookieless).

      // Set up authentication and host URL
          embedConfig = EmbedConfig(
            authType: AuthType.TrustedAuthTokenCookieless,
            thoughtSpotHost: '<YOUR_THOUGHTSPOT_HOST_URL>', // Replace `<YOUR_THOUGHTSPOT_HOST_URL>`. For example, 'https://your-instance.thoughtspot.cloud'
            getAuthToken: GetAuthToken(),
          );
  2. Initialize the LiveboardEmbedController component with the EmbedConfig and LiveboardViewConfig in a stateful widget.

    // Initialize the controller to manage the embedded view
        liveboardEmbedController = LiveboardController(
          embedConfig: embedConfig,
          viewConfig: liveboardViewConfig,
        );

Specify the Liveboard IDπŸ”—

Specify the ID of the Liveboard that you want to embed.

  liveboardViewConfig = LiveboardViewConfig(
      liveboardId: '<YOUR_LIVEBOARD_ID>', // For example, 'aa435ee8-212a-4317-8be8-ee85b4b6cfb9'
    );

Customize your embed viewπŸ”—

If you want to customize your embedded Liveboard view, there are several customization options available:

Customize menu actionsπŸ”—

By default, the SDK includes a set of menu actions in the embedded Liveboard view.

To disable or hide a menu action, you must specify the action ID in the disabledActions, visibleActions, or hiddenActions array.

Note

To show or hide menu actions, use either visibleActions or hiddenActions.

  //To show or hide menu actions, use either `visibleActions` or `hiddenActions` array.
    visibleActions: [Action.AddFilter,Action.Share,Action.DrillDown,Action.AxisMenuFilter,Action.AxisMenuTimeBucket], //empty array removes all actions
  //disable actions
    disabledActions: [Action.DrillDown, Action.Edit],
  //specify the reason for disabling menu actions
    disabledActionReason: "Contact your administrator to enable this feature",

Customize stylesπŸ”—

You can use ThoughtSpot’s CSS customization framework to customize the text strings, icons, styles and the UI layout of the embedded view.

 liveboardViewConfig = LiveboardViewConfig(
      liveboardId: '<YOUR_LIVEBOARD_ID>', // e.g., 'aa435ee8-212a-4317-8be8-ee85b4b6cfb9'
      //Define styles to customize the embedded page
      customizations: CustomisationsInterface(
         style: CustomStyles(
           customCSS: customCssInterface(
             variables: {
               "--ts-var-root-background": "#f6f641",
               "--ts-var-root-color": "#041a45",
               "--ts-var-viz-background": "#38f193",
               "--ts-var-viz-border-radius": "20px",
             },
           ),
        ),
     ),
  );

Handle events and app interactionsπŸ”—

To listen to the events emitted by the embedded ThoughtSpot component, register embed event handlers.

The following code adds event listeners for EmbedEvent.Load, EmbedEvent.Error, and EmbedEvent.Data.

 // Add an event listeners
    liveboardEmbedController.on(EmbedEvent.Data, (payload) {
      print('Data: ${payload['displayMode']}');
    });
    liveboardEmbedController.on(EmbedEvent.Load, (payload) {
      print('Liveboard loaded');
    });
    liveboardEmbedController.on(EmbedEvent.Error, (payload) {
      print('Error: $error');
    });
  }

To trigger actions on the embedded ThoughtSpot interface, use Host events as shown in this example:

 // Switch to a specific tab on the Liveboard
    liveboardEmbedController.trigger(HostEvent.SetActiveTab, {
        'tabId': '<YOUR_TAB_ID>', // Replace with your Liveboard tab ID
    }),

 //Reload the Liveboard content
    liveboardEmbedController.trigger(HostEvent.Reload),

Run the app and verify your embedπŸ”—

  1. Review your code
    Check if your final code is similar to the code shown in the following example:

    import 'package:flutter/material.dart';
    import 'package:thoughtspot_flutter_embed/thoughtspot_flutter_embed.dart';
    
    // Custom class to handle authentication token retrieval.
    class GetAuthToken extends EmbedConfigGetAuthToken {
      @override
      Future<String> operate() async {
        return '<YOUR_AUTH_TOKEN>'; // Replace `<YOUR_AUTH_TOKEN>` with your actual trusted auth token.
      }
    }
    
    // Main widget that displays the home page with ThoughtSpot embed.
    class MyHomePage extends StatefulWidget {
      const MyHomePage({super.key, required this.title});
    
      final String title;
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      // Controller to manage the embedded Liveboard
      late LiveboardController liveboardEmbedController;
    
      // Configuration object for embed
      late EmbedConfig embedConfig;
    
      // Configuration for the specific Liveboard view
      late LiveboardViewConfig liveboardViewConfig;
    
      @override
      void initState() {
        super.initState();
    
        // Set up authentication and host URL configuration
        embedConfig = EmbedConfig(
          authType: AuthType.TrustedAuthTokenCookieless, // Cookieless authentication type using token
          thoughtSpotHost: '<YOUR_THOUGHTSPOT_HOST_URL>', // Replace with your ThoughtSpot URL. For example, 'https://your-instance.thoughtspot.cloud'
          getAuthToken: GetAuthToken(), // Use the custom token getter defined above
        );
    
        // Define how the Liveboard should look and behave
        liveboardViewConfig = LiveboardViewConfig(
          liveboardId: '<YOUR_LIVEBOARD_ID>', // Replace with your Liveboard ID
          customizations: CustomisationsInterface(
            style: CustomStyles(
              customCSS: customCssInterface(
                variables: {
                  "--ts-var-root-background":
                      "#f6f641", // Background color of the root container
                  "--ts-var-root-color": "#041a45", // Text color
                  "--ts-var-viz-background": "#38f193", // Visualization background
                  "--ts-var-viz-border-radius":
                      "20px", // Rounded corners for visualizations
                },
              ),
            ),
          ),
        );
    
        // Create the controller to manage and handle embedded content
        liveboardEmbedController = LiveboardController(
          embedConfig: embedConfig,
          viewConfig: liveboardViewConfig,
        );
    
        // Add event listener to handle data-related events from the embedded view
        liveboardEmbedController.on(EmbedEvent.Data, (payload) {
          print('Data: ${payload['displayMode']}');
        });
        // Add event listener to handle the object load
        liveboardEmbedController.on(EmbedEvent.Load, (payload) {
          print('Liveboard loaded');
        });
        // Add event listener to handle errors
        liveboardEmbedController.on(EmbedEvent.Error, (payload) {
          print('Error: $error');
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            backgroundColor: Theme.of(context).colorScheme.inversePrimary,
            title: Text(widget.title), // Show the title passed to the widget
          ),
          body: Column(
            children: [
              Expanded(
                // Display the embedded Liveboard view
                child: LiveboardEmbed(
                  controller: liveboardEmbedController,
                ),
              ),
              // Buttons to interact with the Liveboard
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  // Reload button to reload the Liveboard content
                  ElevatedButton(
                    onPressed: () => liveboardEmbedController.trigger(HostEvent.Reload),
                    child: const Text('Reload'),
                  ),
                  const SizedBox(width: 16),
                  // Button to switch to a specific tab on the Liveboard
                  ElevatedButton(
                    onPressed: () => liveboardEmbedController.trigger(HostEvent.SetActiveTab, {
                      'tabId': '<YOUR_TAB_ID>', // Replace with your Liveboard tab ID
                    }),
                    child: const Text('Set Active Tab'),
                  ),
                ],
              ),
            ],
          ),
        );
      }
    }
  2. Build your Flutter app and verify if the embedded component renders as expected.

flutter run

Test your embedπŸ”—

  • Before testing your embed, check if the platform-specific permissions for Android and iOS are configured. If platform-specific permissions are not configured, follow these steps and then build your app:

    For Android
    1. Open the Android module in your project.

    2. Modify the AndroidManifest.xml file in the android/app/src/main/ directory to enable Internet access:

      <manifest>
      <uses-permission android:name="android.permission.INTERNET"/>
      </manifest>
    For iOS
    1. Open the iOS module in your project.

    2. Modify the Info.plist file in the ios/Runner/ directory to allow WebView content loading:

    <key>NSAppTransportSecurity</key>
    <dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
    </dict>
  • Check your app and verify if the embedded object loads. If you see a blank screen:

    • Ensure that your ThoughtSpot host URL is correct and accessible

    • Check if the authentication credentials in your code are valid

    • Verify if your app has the required network permissions

  • Check if your Liveboard renders with all its charts and tables. If the content is not loading, check if your code has the correct Liveboard ID.
    Additionally, you can add a listener for EmbedEvent.Error and verify the logs.

  • In case of rendering issues, try adjusting the frame size constraints.

  • Verify if your custom styles are applied.

Known limitationsπŸ”—

For information about supported features and known limitations, see Mobile embed limitations.