ThoughtSpot and Salesforce Integration

ThoughtSpot and Salesforce Integration

Integrating ThoughtSpot with Salesforce enables users to access analytics directly within Salesforce. By embedding ThoughtSpot content, organizations can deliver data-driven insights where their end users work, enhancing decision-making and efficiency.

This guide explores the various embedding options, including the ThoughtSpot Lightning Web Component (LWC) plugin for Salesforce, Visual Embed SDK, and non-SDK approaches, and provides key recommendations for authentication, customization/branding, and embedding in mobile apps.

Embeddable objects🔗

ThoughtSpot allows users to create several types of objects. You can easily embed any of the following objects into Salesforce:

  • Search - A self-service interface that allows users to perform searches on data and build visualizations.

  • Answers - Individual visualizations generated and saved from user search queries.

  • Liveboards - Interactive dashboards that contain one or more visualizations (Answers).

  • Spotter - An AI-powered assistant that helps users analyze data using natural language.

  • Full Application - Allows embedding the full ThoughtSpot application or the individual application pages.

Embedding methods🔗

You can embed ThoughtSpot in Salesforce using the following methods:

Embedding methodDescription

ThoughtSpot supported LWC Plugin

ThoughtSpot-managed Lightning Web Component (LWC) plugin for Salesforce enables seamless embedding of Liveboards and Spotter directly within Salesforce.

This is the recommended approach for most Salesforce Lightning environments.

Custom LWC with Visual Embed SDK

For maximum flexibility and customization, use the Visual Embed SDK within your own custom LWC. This method supports embedding all ThoughtSpot components such as Liveboards, Spotter, Search, Answers and full application experience, and allows for deep integration with Salesforce Cloud products.

iFrame embedding (without SDK)

For Salesforce Classic or when SDK/LWC plugin use is not possible, embed ThoughtSpot using a simple iFrame. This legacy approach is quick to implement but has limitations in authentication, event handling, and customization.

Key considerations🔗

CapabilityThoughtSpot LWC Plugin (managed package)Custom LWC with SDKiFrame via Visualforce/Apex

Setup effort

Low

Install, drag and drop in Lightning App Builder, and configure props

Medium/High

Build LWC, handle authentication, events, and testing

Low/Medium

Quick to place, but manual parameter and authentication handling is required

Supported ThoughtSpot experiences

Liveboards and Spotter

All SDK-supported components
(Liveboards, Spotter, Search, Answers, Full application)

Any embeddable ThoughtSpot URL

Record-aware context
(for example, Account/Opportunity filters)

Built-in support

Pass recordId/fields via properties

Yes

Compose runtime filters from record context

Manual

Append query parameters to iFrame URL

Authentication options

SSO and Cookieless Trusted authentication

All authentication methods supported, including SSO, Cookieless Trusted authentication and more)

Works with SSO only.
Limited options

Salesforce Mobile app

Supported when Org authentication is configured

Recommended with Cookieless Trusted authentication

Inframe authentication limitations

CSP and security

Documented CSP entries; package streamlines most settings

You must manage Trusted Sites and CSP allowlists

Must allow ThoughtSpot as trusted host

Branding, styles, themes

Configurable via component properties

Limited deep styling

Full control via SDK and custom CSS

Minimal

Basic styling options for ThoughtSpot application only

Events and callbacks
(For filters, drilldown, and more)

Common events exposed via component API

Full event surface; wire to Apex/Flow

None

Custom Actions

None

Supported

None

Access to ThoughtSpot REST APIs
(Object export, metadata, Answer Service, and so on)

Limited

Available

SDK and REST APIs supported

None

Time-to-production

Fastest

Moderate

Fast

Maintainability and upgrades

Vendor-maintained; update by package version

You own app lifecycle and SDK versioning

You own app lifecycle

Granular UX control

Medium

High

Low

High-level implementation steps🔗

To embed ThoughtSpot content, complete the steps described in the following sections:

Embed using ThoughtSpot LWC plugin🔗

For information about the LWC plug-in installation and setup, see Integration Guide.

Custom LWC with Visual Embed SDK🔗

The Salesforce lightning platform moved developers away from Visualforce to Lightning Web Components (LWC). If you are considering using the SDK, we will assume your Salesforce instance is running on Lightning.

Note
To simplify development, we recommend using the Salesforce extensions pack in Visual Studio Code.

You have a couple of options:

LWC from scratch
Note
This guide does not cover LWC development. We will assume you have experience developing in Salesforce. If not, contact your ThoughtSpot Sales representative for details.

Any LWC you develop in Salesforce will contain an html, js, and meta.xml file. Let’s walk through a simple Liveboard embed component.

meta.xml
Defines the metadata values for the component. Specifically, where you want to embed in Salesforce (Record Pages, Experience Cloud, Homepage, and more), and any configurable parameters for your ThoughtSpot objects (type of object to embed, Cluster URL, Org, and more).

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>63.0</apiVersion>
    <isExposed>true</isExposed>
    <masterLabel>ThoughtSpot Embed Template</masterLabel>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
        <target>lightningCommunity__Page</target>
        <target>lightningCommunity__Default</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__RecordPage,lightning__AppPage,lightning__HomePage,lightningCommunity__Default">
            <property label="What are you embedding?" name="embedType" type="String" datasource="Liveboard, Spotter" default="Liveboard"/>
                <property
                    name="tsURL"
                    type="String"
                    label="ThoughtSpot URL"
                    required="false"
                    description="The full URL to your ThoughtSpot host"
                    default=""
                />
                <property
                    name="tsOrg"
                    type="String"
                    label="TS Org ID - leave empty if not using orgs"
                    required="false"
                    description="ThoughtSpot Organization Identifier"
                    default=""
                />
                <property
                    name="tsObjectId"
                    type="String"
                    label="Liveboard or Datasource GUID"
                    required="false"
                    description="ThoughtSpot Content GUID"
                    default=""
                />
                <property
                    name="hideLiveboardHeader"
                    type="Boolean"
                    default="false"
                    label="Hide Liveboard Header?"
                />
                <property
                    name="showLiveboardTitle"
                    type="Boolean"
                    default="false"
                    label="Show Liveboard Title?"
                />
                <property
                    name="fullHeight"
                    type="Boolean"
                    default="false"
                    label="Full Height Liveboard?"
                />
            </targetConfig>
        </targetConfigs>
    </LightningComponentBundle>

html
This page defines the div where your ThoughtSpot object will be embedded.

<template>
    <div class="container" data-id="myContainer">
        <div class="thoughtspotObject" data-id="thoughtspotObject" id="thoughtspotObject" lwc:dom="manual"></div>
    </div>
</template>

javascript

  • The js file will communicate with your ThoughtSpot cluster and use the Visual Embed SDK to embed your objects.

  • Variables set in the meta.xml will be tracked and applied in the SDK initialization.

  • You must import the Visual Embed SDK as a static resource in Salesforce. Get the latest NPM version here.

  • Add Salesforce URL to CORS allowed-domains in ThoughtSpot.

  • Update CORS and CSP settings in Salesforce with your ThoughtSpot cluster URL.

///////////////////////////////////////
//Prototype for TS Liveboard Embed
//
// High-level steps:
//   : Update CCORS whitelisted domains settings in ThoughtSpot (Developer -> Security). Add your Salesforce url(s)
//   : Update CORS and CSP settings in Salesforce with your thoughtspot cluster url
//   : Upload the ThoughtSpot SDK into SF as Static Resource. Make sure name matches thoughtSpotSDK import below
//   : Set values for your ThoughtSpot username & password below.
//
// Notes:
//   : Basic Auth used in this LWC, no SSO.
//   : Do not use in production
//
///////////////////////////////////////
import { LightningElement, api, track } from 'lwc';
import thoughtSpotSDK from '@salesforce/resourceUrl/thoughtSpotSDK';
import { loadScript } from 'lightning/platformResourceLoader';

export default class TsEmbedTemplate extends LightningElement {

    @api objectApiName; /** Object API name - automatically passed when in a record page */
    @api recordId;      /** Object record ID - automatically passed when in a record page */

    //track variables set in meta.xml
    @api embedType;
    @api tsObjectId;
    @api tsURL;
    @api tsOrg;
    @api hideLiveboardHeader;
    @api showLiveboardTitle;
    @api fullHeight;

    ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Basic Auth testing - use your ThoughtSpot credentials
    ////////////////////////////////////////////////////////////////////////////////////////////////////
    myTestUser   = '';
    myTestPW     = '';
    ////////////////////////////////////////////////////////////////////////////////////////////////////

    async connectedCallback() {
        console.log("### Loading the ThoughtSpotSDK...");
        this.loadTSSDK();
    }

    loadTSSDK() {
        loadScript(this, thoughtSpotSDK)
            .then(() => {
                // ThoughtSpot library loaded successfully
                console.log("### SDK successfully loaded...initializing embed");
                this.initSDKEmbed();
            })
            .catch(error => {
                // Error occurred while loading the ThoughtSpot library
                this.handleError(error);
            });
    }

    async initSDKEmbed() {
        const containerDiv = this.template.querySelector(
            'div.thoughtspotObject'
        );

        try {
            this.embedInit = tsembed.init({
                thoughtSpotHost: this.tsURL,
                authType: tsembed.AuthType.Basic,
                username: this.myTestUser,
                password: this.myTestPW,
                org_id: this.tsOrg,
                customizations: {
                    style: {
                        customCSSUrl: "https://cdn.jsdelivr.net/gh/thoughtspot/custom-css-demo/css-variables.css", // location of your style sheet

                        // To apply overrides for your style sheet in this init, provide variable values below
                        customCSS: {
                            variables: {
                                "--ts-var-button--secondary-background": "#9da7c2",
                                "--ts-var-button--secondary--hover-background": "#cacad5",
                                "--ts-var-button--primary--hover-background":"#cacad5",
                                "--ts-var-button--primary-background": "#9da7c2",
                                "ts-var-button--primary-color": "#9da7c2",

                                "--ts-var-root-background": "#b0c4df",
                                "--ts-var-viz-border-radius": "22px",
                                "--ts-var-viz-title-font-family": "Helvetica",
                                "--ts-var-viz-background": "#ffffff",

                                "--ts-var-menu--hover-background": "#c9c9c9",
                                "--ts-var-menu-font-family": "Helvetica",

                                "--ts-var-chip-border-radius": "8px",
                                "--ts-var-chip--active-color": "#CF112C",
                                "--ts-var-chip--active-background": "#57a3fd",
                                "--ts-var-chip--hover-color": "white",
                                "--ts-var-chip--hover-background": "#A4A4A3",
                                "--ts-var-chip-color": "#F9F6EE",
                            },
                        },
                    },
                    },
            });

            if( this.embedType === "Liveboard" ) {

                console.log('### Configuring ' + this.embedType + ' embed');
                console.log("### RECORD ID: ", this.recordId);

                this.embedObj = new tsembed.LiveboardEmbed(containerDiv, {
                    frameParams: {
                    },
                    fullHeight: this.fullHeight,
                    hideLiveboardHeader: this.hideLiveboardHeader,
                    showLiveboardTitle: this.showLiveboardTitle,
                    liveboardId: this.tsObjectId,
                });
            }
            else if(this.embedType === "Spotter") {

                console.log('### Configuring ' + this.embedType + ' embed');

                this.embedObj = new tsembed.SpotterEmbed(containerDiv, {
                    frameParams: {
                        height: 800,
                    },
                    worksheetId: this.tsObjectId,
                });
            } else {
                console.log("###ERROR: No embed type selected in meta xml");
            }

            this.embedObj.render();

            }
            catch (error) {
                console.error('Error:', error);
            }
    }

    handleError(error) {
        console.error('Error loading TS library:', error.message || error);
    }
}
LWC Git repository

We can provide all the code needed to get you started. Contact your ThoughtSpot Sales representative for access to our Git repositories.

iFrame embedding🔗

If you have configured ThoughtSpot to use the same SAML provider as your Salesforce instance, you can create a simple Visualforce page that can seamlessly embed a ThoughtSpot Object.

To create a new Visualforce page in Salesforce, go to Setup > Visualforce Pages > New.

The following code example can be used for the new page. It defines the iFrame, with the ThoughtSpot Liveboard URL using a runtime filter to personalize the results to the Salesforce user:

Note
Use this code only if embedding into Salesforce Classic.
<apex:page standardController="Account" tabStyle="Account">
  <apex:pageBlock title="ThoughtSpot">
    <apex:iframe src="https://{thoughtspot-server}/?embedApp=true&p&col1={field_name}&op1=EQ&val1={!Account.Id}&OrgID={org_id}#/embed/viz/{liveboard_guid}
" scrolling="true" height="800">
    </apex:iframe>
  </apex:pageBlock>
</apex:page>
Note
Variable substitution required
  • {thoughtspot-server}. Your ThoughtSpot host URL.

  • {field_name} represents the column from your ThoughtSpot model to be filtered.

  • {!account.Id} is a Salesforce APEX variable, the value is automatically known based on the record page you are embedding into. The filter values you can pass are based on the standardController=<object> you set when configuring the apex page.

  • {org_id}. If using Orgs in ThoughtSpot, provide your Org identifier. If not using Orgs, set the ID to 0.

  • {liveboard_guid}. Your Liveboard identifier.

SSO Options🔗

Authentication is a critical component of embedding ThoughtSpot in Salesforce. The two primary options for this integration are:

SAML-based SSO
  • Allows users to authenticate via Salesforce’s Identity Provider (IdP).

  • Provides a seamless login experience without requiring additional credentials.

  • Requires ThoughtSpot to be configured as a service provider (SP).

Trusted authentication
  • Uses a secure token-based approach for authentication.

  • Provides more control over user access and permissions.

  • Ideal for embedding within customized Salesforce experiences.

  • Seamless embedding within the Salesforce mobile app.

  • Is supported in ThoughtSpot SDK embed only.

Customization and branding with the SDK🔗

The Visual Embed SDK allows extensive customization, including the following:

  • Styling the embedded Liveboards to match Salesforce’s look and feel.

  • Implementing filters and interactive elements.

  • Controlling user experience via ThoughtSpot’s developer-friendly APIs.

Conclusion🔗

Embedding ThoughtSpot into Salesforce enhances analytics accessibility, enabling users to gain insights without leaving their CRM. Whether using the ThoughtSpot LWC plugin, Visual Embed SDK or iframe-based approaches, choosing the right authentication and embedding method is essential. By leveraging LWC and customizing ThoughtSpot’s appearance, organizations can create a seamless and powerful analytics experience within Salesforce.

© 2025 ThoughtSpot Inc. All Rights Reserved.