LLMs.txt: Complete documentation index for AI agents
Get into the Developer Portal

Get into the Developer Portal

Developer Portal🔗

Start in the Developer Portal, where every ID and configuration option you need lives.

  1. Log in to ThoughtSpot.

  2. Click the Develop tab.

    Note

    The Develop tab is visible only to users with Developer or Admin privilege. If you don’t see it, ask your administrator to add you to a group with the Has Developer privilege permission.

From the Developer Portal you have access to:

Developer Playground

An interactive sandbox where you configure the component you want to embed, see it render live, and copy out the exact SDK code. This is where every step starts.

AI Theme Builder

The same live-render-and-copy pattern, but for styling.

SpotterCode

An AI coding assistant built into the Playground and IDE that can generate and refine embed code from a plain-language prompt, and help theme it too.

Security Settings

Where you allowlist your portal domain for CSP and CORS. Nothing renders without this.

Customizations

Connectors, security settings, and webhooks for the broader ThoughtSpot instance.

Important

Why this step matters: skipping the Playground and hand-writing IDs from old tickets or Slack messages is the single most common source of "why is my embed blank" bugs. Grab every ID from the Playground, not from memory, and keep the terminology aligned with the ThoughtSpot objects you are embedding.

Project setup🔗

Before you write a single line of embed code, four things need to be settled: the portal’s domain needs to be allowlisted, you need the actual cluster hostname, you need to know which auth type you’re building against, and you need the project files scaffolded. Skipping them is the fastest way to spend an afternoon debugging a CORS error and blaming the code.

1. Allowlist the portal domain🔗

In the ThoughtSpot UI, an admin or developer-privileged user goes to Develop > Customizations > Security Settings and adds your portal’s domain (for example, https://spotstay.com) to the CSP and CORS allowlists. Without this, the browser blocks the embed regardless of how correct the code is.

This is a one-time, admin-side setup step: it is not something the SDK or any tooling generates for you. Do this first so you are not debugging a CORS error later and assuming it is your code.

2. Get the cluster hostname🔗

Your ThoughtSpot instance lives at a specific hostname. For a Cloud instance, it looks like spotstay.thoughtspot.cloud. It’s visible in the browser URL bar whenever you’re logged into the ThoughtSpot UI. It is also listed under Develop > REST API Playground, which shows the fully qualified host that any API call must target. This is the value that goes into thoughtSpotHost. If you get it wrong, every embed on the page renders blank.

3. Choose an auth type🔗

The tutorial-friendly option is AuthType.None. It prompts for a ThoughtSpot login at runtime and is fine for local development. It is not what ships to hosts in production.

The production-recommended pattern is Trusted Authentication: your own backend exchanges credentials for a token server-side, and hosts are signed in to the embed silently. No ThoughtSpot login screen, no separate ThoughtSpot license per user. Setting this up means standing up a small token-issuing endpoint on your side. It’s a separate build from the embed code itself, and worth planning for before this goes past a demo.

See Authentication for the full option set, AuthType.None, AuthType.Basic, AuthType.TrustedAuthToken, AuthType.TrustedAuthTokenCookieless, and SSO-based flows, and which fits your setup.

4. Create the project structure🔗

With the domain allowed, the hostname in hand, and an auth type picked, create a small project folder. This matches the structure in the SpotStay example repo on GitHub:

spotstay-embed/
├── index.html   # Page shell + wrapper app navigation
├── app.js       # All embedding code (SpotterEmbed, LiveboardEmbed, custom actions)
└── styles.css   # Host app styling

Install the SDK:

npm install @thoughtspot/visual-embed-sdk

In app.js, import the components you’ll use:

import {
  SpotterEmbed,
  LiveboardEmbed,
  AuthType,
  init,
  EmbedEvent,
  HostEvent,
  CustomActionTarget,
  CustomActionPosition,
} from '@thoughtspot/visual-embed-sdk';
Note

For a throwaway prototype, a CDN import works as well: keep <script type="module" src="app.js"> and import the SDK from the jsDelivr build instead of the npm package. Use npm if this is going into a real app.

index.html owns the page chrome, nav bar, container div, and nothing else. ThoughtSpot doesn’t need to know anything about the rest of the portal:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>SpotStay Portal</title>
  <link rel="stylesheet" href="styles.css" />
</head>
<body>
  <nav class="app-nav">
    <span class="brand">SpotStay</span>
    <button data-view="liveboard" class="nav-btn active">Dashboard</button>
    <button data-view="spotter" class="nav-btn">Ask a question</button>
  </nav>

  <main>
    <div id="ts-embed"></div>
    <div id="detail-panel" class="hidden"></div>
  </main>

  <script type="module" src="app.js"></script>
</body>
</html>

app.js initializes the SDK once, near the top of the file. Always call init() before calling render() on any embed component:

const tsURL = 'https://spotstay.thoughtspot.cloud';

init({
  thoughtSpotHost: tsURL,
  authType: AuthType.None, // (1)
});
  1. AuthType.None is fine while you’re iterating locally: you get a one-time login popup and the session holds until it expires. Before this touches production, swap in a token-based AuthType such as AuthType.TrustedAuthTokenCookieless, so hosts are authenticated silently through your own backend, not a ThoughtSpot login popup.

Then add tab-switching logic so the nav bar swaps embeds:

const container = document.getElementById('ts-embed');

document.querySelectorAll('.nav-btn').forEach((btn) => {
  btn.addEventListener('click', () => {
    document.querySelectorAll('.nav-btn').forEach((b) => b.classList.remove('active'));
    btn.classList.add('active');
    container.innerHTML = '';
    btn.dataset.view === 'spotter' ? renderSpotter() : renderLiveboard();
  });
});

renderLiveboard(); // default view on load
© 2026 ThoughtSpot Inc. All Rights Reserved.