Customize full application embedding

Customize full application embedding

The AppEmbed component embeds the entire ThoughtSpot application within another page.

Choose the page to load🔗

The pageId parameter of the AppEmbed parameters object lets you specify the ThoughtSpot page in the Page enumeration that the AppEmbed component loads to.

Alternatively, you can use the path parameter to directly specify a page path, to load a specific Liveboard or Answer.

const embed = new AppEmbed("#embed", {
    pageId: Page.Liveboards,
    // path: 'pinboard/96a1cf0b-a159-4cc8-8af4-1a297c492ff9',  // Alternative direct path rather than pageId
    showPrimaryNavbar: false,
    frameParams: {
        height: '100%',
        width: '100%'

Customize the ThoughtSpot top menu🔗

You cannot change the ThoughtSpot top menu directly, but you can hide and replace it with your own navigation menu (it can even look exactly the same as ThoughtSpot default).

To hide the top menu bar, set the showPrimaryNavbar parameter of the AppEmbed to false.

You can replicate the behavior of the hidden menu bar in the embedding web application’s UI.

The AppEmbed object has a method called navigateToPage() that will switch the currently loaded page in the ThoughtSpot embedded application. The navigateToPage() method accepts the values that work for pageId or path parameters.

The new navigation menu should call navigateToPage for the various pages you want to provide access to:

// with noReload option
embed.navigateToPage(Page.Answers, true);

Detect changes in the currently loaded page🔗

Various actions the user takes within the embedded ThoughtSpot application may cause navigation within ThoughtSpot.

The embedding web application can listen for the EmbedEvent.RouteChange event by attaching an event listener to the AppEmbed object. The response has a currentPath property which is the path after the ThoughtSpot domain, for example:


To parse the currentPath into varying useful components, this tsAppState object code can be created in the global scope for use by any other web application code:

// Simple global object to handle details about what is visible in the AppEmbed component at a given moment
let tsAppState = {
  currentPath: startPath,
  currentDatasources: [], // Can be set later when detected from TML or other events
  // return back what is being viewed at the moment, in the form that will translate to the pageId property if captialized, or path property if not
  get pageType() {
      if (this.currentPath.includes('/saved-answer/')){
          return 'answer';
      else if (this.currentPath.includes('/pinboard/')){
          return 'liveboard';
      * Others are meant to match the exact pageId from SDK
      else if(this.currentPath.includes('/answer/')){
          return 'Search';
      else if(this.currentPath.includes('/answers')){
          return 'Answers';
      else if (this.currentPath.includes('/pinboards')){
          return 'Liveboards';
      else if(this.currentPath.includes('/insights')){
          return 'SpotIQ';
      else if(this.currentPath.includes('/monitor')){
          return 'Monitor';
      else if(this.currentPath.includes('/data')){
          return 'Data';
      else {
          return 'Home';
  // If viewing an Answer or Liveboard, returns the GUID of that object from the parsed URL
  get objectId() {
      let pathParts = this.currentPath.split('/');
      // '/saved-answer/' is path for Answers (vs. /answer/)
      if (this.currentPath.includes('/saved-answer/')){
          answerGUID = pathParts[2];
          return pathParts[2];
      // '/pinboard/' is path for saved Liveboards
      else if (this.currentPath.includes('/pinboard/')){
          let pathParts = this.currentPath.split('/');
          // May need adjustment for tabbed views to add in current Tab
          liveboardGUID = pathParts[2];
          return pathParts[2];
          return null;


The following example shows the event listener code updating the global tsAppState object above whenever there is a change within the embedded ThoughtSpot app:

embed.on(EmbedEvent.RouteChange, (response) => {
  // console.log("RouteChange fires");
  // console.log(response);
  // tsAppState object has currentPath property, which allows its other methods to parse out pageId, object type, GUIDs etc.
  tsAppState.currentPath =;
  console.log("TS App page is now: ", tsAppState.currentPath);

  // Update elements within your web application based on the new state of ThoughtSpot (adjust menu selections, etc.)


Navigate using a custom action🔗

To add a custom action for in-app navigation, follow these steps:

  1. Add a custom action.

  2. Define the navigation path

In this example, the view-report action on a Liveboard page calls the navigateTo method to open a specific saved Answer page when a user clicks the View report button in the embedded app.

appEmbed.on(EmbedEvent.CustomAction, async (payload: any) => {
    if ( === 'view-report') {

If you want to navigate to a specific application page without initiating a reload, you can set the noReload attribute to true as shown here:

appEmbed.on(EmbedEvent.CustomAction, async (payload: any) => {
    if ( === 'view-report') {
        appEmbed.navigateToPage('saved-answer/3da14030-11e4-42b2-8e56-5ee042a8de9e', true);

CSS customization and hiding page elements🔗

CSS customization allows overriding the default styles from the ThoughtSpot application, including the application pages.

If there is an element of a page that you dislike and cannot hide with any combination of other options in ThoughtSpot, you can often use CSS customization to target the element and apply either display: none;, visibility: hidden; or height: 0px; and make it functionally disappear to the end user.

Specifying a direct element using the direct CSS selectors vs. the ThoughtSpot provided variables. To discover the appropriate selector, use the Inspect functionality of your browser to bring up the Elements portion of the browser’s Developer Tools, then look at the Styles information.

An example of using direct selectors in a file is available in the complete.css.

.bk-data-scope .left-pane .header-lt {
  display: none !important;
  visibility: hidden !important;

Direct selectors can also be declared using rules in the Visual Embed SDK code. This is useful for real-time testing, particularly in the Visual Embed SDK playground. Note the format for encoding CSS rules into the JavaScript object format used by for rules.