Botsplash Dashboard Widget Integration Guide

Overview

The Botsplash Dashboard widget allows customers to embed the full Botsplash dashboard directly into their CRM or agent applications as an iframe widget. This enables agents to engage with customers without leaving their primary work environment.

Important Security Requirements

DOMAIN WHITELISTING IS REQUIRED: Before implementing the widget, your domain must be whitelisted by Botsplash for security reasons. Contact Botsplash support to whitelist your CRM domain.

Pre-whitelisted Domains

The following CRM platforms are already whitelisted and require no action:

  • Salesforce
  • HubSpot
  • Other major CRM platforms (contact support for confirmation)

Production vs Staging Domains

Environment Domain Example URL
Production botsplash.com https://acmemortgage.botsplash.com
Staging botsplash.space https://acmemortgage.botsplash.space

When developing or testing against the Botsplash staging server, use the botsplash.space domain instead of botsplash.com. The script URL, BSPDASHBOARD_APP_URL, and any baseUrl overrides must all point to the .space domain for staging access.

X-Frame-Options Error

If you encounter an error message containing X-Frame-Options directive set to "sameorigin", this indicates your domain is not whitelisted. Please contact Botsplash support with your updated domain to resolve this issue. Also verify you are using the correct domain — botsplash.com for production and botsplash.space for staging.


The recommended approach is to use login() or loginAccount() with a server-generated JWT token. This provides secure, implicit authentication so agents don’t need to log in manually.

Step 1: Add the Widget Script

<script>
  window.BSPDASHBOARD_APP_URL         = 'https://<account-id>.botsplash.com';
  window.BSPDASHBOARD_APP_HIDE_DEFAULT = true; // Prevent auto-load; we will call login() ourselves

  (function () {
    var d = document;
    var s = d.createElement('script');
    s.src   = 'https://app.botsplash.com/y.js';
    s.async = true;
    d.getElementsByTagName('head')[0].appendChild(s);
  })();
</script>

Step 2: Generate a JWT Token on Your Server

Your backend creates a signed JWT using the Botsplash API key. See Server-Side Token Generation for a full example.

Step 3: Log In with the Token

Once the script has loaded and you have a token from your server, call login() or loginAccount():

// Option A — login() with token and options
$bspdashboard.login(token, {
  version     : 2,                                              // Default: 1
  displayType : window.$bspdashboard.DisplayType.Floating,      // Optional
  uiOptions   : window.$bspdashboard.WidgetUiOptions.HideAll,   // Optional
});

// Option B — loginAccount() convenience function
$bspdashboard.loginAccount('<account-id>', token, {
  version     : 2,
  displayType : window.$bspdashboard.DisplayType.Floating,
  uiOptions   : window.$bspdashboard.WidgetUiOptions.HideAll,
});

Replace <account-id> with your actual Botsplash account identifier (e.g. acmemortgage).


Global API Reference (window.$bspdashboard)

The widget script exposes a global $bspdashboard object with the following methods and constants.

Constants

Constant Values Description
DisplayType.Floating 1 Floating overlay (default)
DisplayType.Inline 4 Inline / embedded in a container
WidgetUiOptions.None 0 Show all UI sections (default)
WidgetUiOptions.HideProfile 1 Hide the profile section
WidgetUiOptions.HideSettings 2 Hide the settings section
WidgetUiOptions.HideAll 3 Hide both profile and settings

Methods

login(tokenOrWidgetUrl, options)

Primary authentication method. Accepts either a JWT token or a full widget URL.

Parameters:

Parameter Type Description
tokenOrWidgetUrl string A JWT token or a full https://... widget URL
options object Optional configuration (see below)

Options object:

Property Type Default Description
accountName string Extracted from hostname Account identifier (e.g. 'acmemortgage')
baseUrl string BSPDASHBOARD_APP_URL or https://{accountName}.botsplash.com Override the base URL used to build the widget login URL
version number 1 Widget protocol version. Use 2 for current server compatibility
rootId string 'bspdashboard-root' DOM element ID where the widget mounts
displayType number 1 (Floating) Widget display mode — see DisplayType constants
uiOptions number 0 (None) Bitwise UI visibility flags — see WidgetUiOptions constants

Examples:

// Token-based login with inline display, hiding profile & settings
$bspdashboard.login(token, {
  accountName : 'acmemortgage',
  version     : 2,
  displayType : window.$bspdashboard.DisplayType.Floating,
  uiOptions   : window.$bspdashboard.WidgetUiOptions.HideAll,
});

loginAccount(accountName, token, optionsOrDevUrl, maybeOptions)

Convenience wrapper around login() that takes the account name as a separate argument.

Parameters:

Parameter Type Description
accountName string Account identifier (e.g. 'acmemortgage')
token string JWT authentication token
optionsOrDevUrl object or string Options object or a dev base URL string
maybeOptions object Options object (only used when the third argument is a URL string)

Examples:

// Standard usage with options
$bspdashboard.loginAccount('acmemortgage', token, {
  version     : 2,
  displayType : window.$bspdashboard.DisplayType.Floating,
  uiOptions   : window.$bspdashboard.WidgetUiOptions.HideAll,
});

// Dev / staging usage with a base URL override
$bspdashboard.loginAccount('acmemortgage', token, 'https://acmemortgage.botsplash.space', {
  version     : 2,
  displayType : window.$bspdashboard.DisplayType.Floating,
  uiOptions   : window.$bspdashboard.WidgetUiOptions.HideAll,
});

openChat()

Opens the dashboard widget window. Useful for programmatically showing the chat frame in response to user actions (e.g. clicking a “Chat” button in your CRM).

$bspdashboard.openChat();

closeChat()

Closes the dashboard widget window without destroying it. The widget stays loaded and can be reopened with openChat().

$bspdashboard.closeChat();

loadVisitor(visitor)

Loads an existing visitor by clientVisitorId, or creates a new visitor when one does not yet exist. This is the primary method for linking CRM customer records to Botsplash conversations.

Parameters:

Parameter Type Description
visitor object Visitor information (see fields below)

Visitor object fields:

Field Type Required Description
clientVisitorId string No Your CRM’s unique customer ID. When provided, Botsplash looks up the existing visitor. When omitted, a new visitor is created
agentClientUserId string No Agent ID to assign the conversation to
participantAgentIds string[] No Additional agent IDs to add as participants
teamCode string No Team code to route the conversation to
firstName string No Visitor’s first name
lastName string No Visitor’s last name
email string No Visitor’s email address
phoneNumber string No Visitor’s phone number
state string No Visitor’s state / region
tzName string No Visitor’s timezone (IANA format, e.g. 'America/New_York')
deliveryStatus number No Delivery status code
extendedAttributes object No Custom key-value pairs for additional visitor data

Examples:

// Load an existing visitor by CRM customer ID
$bspdashboard.loadVisitor({
  clientVisitorId : '12345',
});

// Load a visitor with full profile information
$bspdashboard.loadVisitor({
  clientVisitorId    : '12345',
  agentClientUserId  : '12345',
  participantAgentIds: ['54321'],
  teamCode           : '333',
  firstName          : 'Jane',
  lastName           : 'Doe',
  email              : 'example@example.com',
  phoneNumber        : '3334445555',
  state              : 'NC',
  tzName             : 'America/New_York',
  deliveryStatus     : 202,
  extendedAttributes : {
    color        : 'red',
    leadSourceId : '123456789',
    priority     : 'high',
  },
});

// Create a new visitor (no clientVisitorId)
$bspdashboard.loadVisitor({
  firstName   : 'John',
  lastName    : 'Smith',
  email       : 'john.smith@example.com',
  phoneNumber : '5551234567',
});

logoff()

Triggers a logout event inside the widget iframe.

$bspdashboard.logoff();

Server-Side Token Generation

Your backend must generate a signed JWT that the widget uses for implicit authentication. The token is signed with your Botsplash API key using the HS256 algorithm.

JWT Payload Fields

Field Type Required Description
said string No Sub-account identifier (for multi-location setups)
id string Yes Unique user ID in your system
fn string Yes User’s first name
ln string Yes User’s last name
email string Yes User’s email address
source string No Identifier for the calling application (e.g. 'acme-center')
iat number Yes Issued-at timestamp (seconds since epoch)

Example: Express.js + jsonwebtoken

/* Copyright (c) 2016-present Rohi LLC.  All rights reserved. */

const express = require('express');
const jwt     = require('jsonwebtoken');
const router  = express.Router();

// POST /api/botsplash/token
router.post('/token', async (req, res) => {
  try {
    const userId         = req.user.id;       // From your auth middleware
    const botsplashApiKey = process.env.BOTSPLASH_API_KEY;

    if (!botsplashApiKey) {
      return res.status(500).json({ error: 'Botsplash API key not configured' });
    }

    const profile = await getUserProfile(userId);
    if (!profile) {
      return res.status(404).json({ error: 'Profile not found' });
    }

    const payload = {
      said   : profile.subAccountId,    // Optional: for multi-location setups
      id     : userId,
      fn     : profile.firstName,
      ln     : profile.lastName,
      email  : profile.email,
      source : 'integration-partner-name',
      iat    : Math.floor(Date.now() / 1000),
    };

    const token = jwt.sign(payload, botsplashApiKey, { algorithm: 'HS256' });

    return res.json({
      success     : true,
      token,
      accountName : process.env.BOTSPLASH_ACCOUNT_NAME,  // e.g. 'acmemortgage'
    });
  } catch (err) {
    console.error('botsplash:token:error:', err);
    return res.status(500).json({ error: 'Failed to generate token' });
  }
});

module.exports = router;

Client-Side Integration Examples

Simple Example: Static HTML Page

A minimal integration that loads the widget script, fetches a token from your server, and calls loginAccount().

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Agent Dashboard</title>
  <style>
    #bsp-main {
      width: 100%;
      height: 100vh;
    }
  </style>
</head>
<body>

<div id="bsp-main"></div>

<script>
  var BSP_APP_URL    = 'https://acmemortgage.botsplash.com';
  var BSP_ACCOUNT_ID = 'acmemortgage';

  window.BSPDASHBOARD_APP_URL          = BSP_APP_URL;
  window.BSPDASHBOARD_APP_HIDE_DEFAULT = true;

  (function () {
    var d = document;
    var s = d.createElement('script');
    s.src   = BSP_APP_URL + '/y.js';
    s.async = true;
    s.onload = function () {
      // Fetch token from your server, then log in
      fetch('/api/botsplash/token', { method: 'POST' })
        .then(function (r) { return r.json(); })
        .then(function (data) {
          if (data.token && window.$bspdashboard) {
            window.$bspdashboard.loginAccount(BSP_ACCOUNT_ID, data.token, {
              rootId      : 'bsp-main',
              version     : 2,
              displayType : window.$bspdashboard.DisplayType.Floating,
              uiOptions   : window.$bspdashboard.WidgetUiOptions.HideAll,
            });
          }
        });
    };
    d.getElementsByTagName('head')[0].appendChild(s);
  })();
</script>

</body>
</html>

Robust Example: React SPA with BotsplashProvider

For single-page applications the widget script only needs to be loaded once. A React context provider handles authentication state changes, loading the script on login and cleaning up on logout.

TypeScript Declarations

Add these type declarations to your project (e.g. in src/types/botsplash.d.ts or inline):

declare global {
  interface Window {
    BSPDASHBOARD_APP_URL?: string;
    BSPDASHBOARD_APP_HIDE_DEFAULT?: boolean;
    $bspdashboard?: {
      login: (tokenOrUrl: string, options?: any) => void;
      loginAccount: (accountName: string, token: string, options?: any) => void;
      logoff: () => void;
      load: (forceReload?: boolean, clientVisitorId?: string, widgetUrl?: string) => void;
      remove: (shouldLogout?: boolean) => void;
      setUser: (id: string, widgetUrl?: string, options?: any) => void;
      loadVisitor: (visitorData: {
        firstName?: string;
        lastName?: string;
        email?: string;
        phoneNumber?: string;
        clientVisitorId?: string;
        agentClientUserId?: string;
        state?: string;
        extendedAttributes?: Record<string, any>;
      }) => void;
      DisplayType: Record<string, number>;
      WidgetUiOptions: Record<string, number>;
    };
  }
}

BotsplashWidget Component

A self-contained component you can drop into any page. The parent passes isLoggedIn and a fetchToken callback, so the component has no dependency on any specific auth library or API client.

import { useEffect, useState, useRef } from 'react';

const BSP_APP_URL = import.meta.env.VITE_BSP_APP_URL || 'https://acmemortgage.botsplash.com';

interface BotsplashWidgetProps {
  isLoggedIn : boolean;
  fetchToken : () => Promise<{ accountName: string; token: string } | null>;
}

const BotsplashWidget = ({ isLoggedIn, fetchToken }: BotsplashWidgetProps) => {
  const [isWidgetLoaded, setIsWidgetLoaded] = useState(false);
  const prevLoggedIn                        = useRef<boolean | null>(null);

  useEffect(() => {
    // Only act on actual auth state changes
    if (prevLoggedIn.current === isLoggedIn) { return; }
    prevLoggedIn.current = isLoggedIn;

    const loadWidget = async () => {
      if (isLoggedIn && !isWidgetLoaded) {
        // Fetch a signed token from the parent's callback
        let tokenInfo;
        try {
          tokenInfo = await fetchToken();
        } catch (err) {
          console.error('Failed to generate Botsplash token:', err);
          return;
        }
        if (!tokenInfo?.token) { return; }

        window.BSPDASHBOARD_APP_URL          = BSP_APP_URL;
        window.BSPDASHBOARD_APP_HIDE_DEFAULT = true;

        const loginOptions = {
          rootId      : 'bsp-main',
          version     : 2,
          displayType : window.$bspdashboard.DisplayType.Floating,
          uiOptions   : window.$bspdashboard.WidgetUiOptions.HideAll,
        };

        if (window.$bspdashboard) {
          // SPA navigation: script already loaded from a previous mount
          window.$bspdashboard.loginAccount(
            tokenInfo.accountName, tokenInfo.token, loginOptions
          );
        } else {
          // First load: inject the script tag once
          const script   = document.createElement('script');
          script.src     = `${BSP_APP_URL}/y.js`;
          script.async   = true;
          script.onload  = () => {
            if (window.$bspdashboard) {
              window.$bspdashboard.loginAccount(
                tokenInfo.accountName, tokenInfo.token, loginOptions
              );
            }
          };
          document.head.appendChild(script);
        }

        setIsWidgetLoaded(true);
      } else if (!isLoggedIn && isWidgetLoaded) {
        // User logged out — tear down the widget
        if (window.$bspdashboard) {
          window.$bspdashboard.remove(true);
        }
        setIsWidgetLoaded(false);
      }
    };

    loadWidget();
  }, [isLoggedIn, isWidgetLoaded, fetchToken]);

  // Cleanup on unmount
  useEffect(() => {
    return () => {
      if (window.$bspdashboard) {
        window.$bspdashboard.remove(true);
      }
    };
  }, []);

  return <div id="bsp-main" style= />;
};

export default BotsplashWidget;

Using the Component

The parent owns the auth state and token-fetching logic, then passes them as props:

import { useCallback } from 'react';
import { useAuth } from './hooks/useAuth';
import { api } from './lib/api-client';
import BotsplashWidget from './components/BotsplashWidget';

function Dashboard() {
  const { user } = useAuth();

  const fetchToken = useCallback(async () => {
    return api.botsplash.generateToken();
  }, []);

  return (
    <div style=>
      <h1>Agent Dashboard</h1>
      <BotsplashWidget isLoggedIn={!!user} fetchToken={fetchToken} />
    </div>
  );
}

Or at the top level for a floating widget on every page:

import { useCallback } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { useAuth } from './hooks/useAuth';
import { api } from './lib/api-client';
import Dashboard from './pages/Dashboard';
import BotsplashWidget from './components/BotsplashWidget';

function AppContent() {
  const { user } = useAuth();

  const fetchToken = useCallback(async () => {
    return api.botsplash.generateToken();
  }, []);

  return (
    <>
      <Routes>
        <Route path="/dashboard" element={<Dashboard />} />
      </Routes>
      <BotsplashWidget isLoggedIn={!!user} fetchToken={fetchToken} />
    </>
  );
}

const App = () => (
  <BrowserRouter>
    <AppContent />
  </BrowserRouter>
);

Loading a Specific Visitor

After the widget is loaded, you can load a specific visitor’s conversation:

$bspdashboard.loadVisitor({
  clientVisitorId : 'CRM_CUSTOMER_ID',
});

Configuration Reference

Global Variables

Variable Type Description
window.BSPDASHBOARD_APP_URL string Your Botsplash account URL (e.g. 'https://acmemortgage.botsplash.com')
window.BSPDASHBOARD_APP_HIDE_DEFAULT boolean Set to true to prevent the widget from auto-loading on script init. Required when using login() / loginAccount()
window.BSPDASHBOARD_CLIENT_VISITOR_ID string Pre-set a visitor ID to load automatically (only used when auto-load is enabled)

Troubleshooting

Common Issues

  1. X-Frame-Options Error
    • Cause: Domain not whitelisted
    • Solution: Contact Botsplash support to whitelist your domain
  2. Widget Not Loading
    • Cause: Incorrect account ID or script URL
    • Solution: Verify your account ID and script URL match
  3. bspdashboard:login:invalidargs in Console
    • Cause: Missing account name or token in login() / loginAccount() call
    • Solution: Ensure both the account name and a valid JWT token are provided
  4. Widget Shows Inside an Iframe
    • Cause: The host page itself is loaded inside an iframe
    • Solution: The widget does not support nested iframe embedding. Load the host page directly
  5. Script Loading Issues
    • Cause: Network restrictions or CORS policies
    • Solution: Check the browser console for errors and verify network access

Support and Contact

For technical support, domain whitelisting requests, or feature questions:

  • Contact the Botsplash support team
  • Provide your account ID and domain information
  • Include any error messages or browser console logs

Copyright © 2025, Rohi LLC. All Rights Reserved.