Chat Widget SDK

Complete reference for the Transactional Support Chat Widget SDK

Chat Widget SDK

The Transactional Support Chat Widget provides a complete live chat experience for your website. This document covers all SDK methods, configuration options, and best practices.

Installation

Get the embed code from your inbox settings:

  1. Go to Support > Inboxes > Your Inbox > Settings
  2. Enable the Chat Widget toggle
  3. Copy the embed code from the Embed Code section

Add the copied script before the closing </body> tag:

<!-- Transactional Support Widget -->
<script>
  (function(w,d,s,o,n,f,js,fjs){
    w[o]=w[o]||{};w[o][n]=w[o][n]||function(){(w[o][n].q=w[o][n].q||[]).push(arguments)};
    w[o][n].l=1*new Date();js=d.createElement(s);fjs=d.getElementsByTagName(s)[0];
    js.id=o+'_'+n;js.src=f;js.async=1;fjs.parentNode.insertBefore(js,fjs);
  }(window,document,'script','Transactional','support','https://cdn.usetransactional.com/sdk/support.min.js'));
 
  Transactional.support('init', { inboxId: 'YOUR_INBOX_ID' });
</script>

Replace YOUR_INBOX_ID with your inbox ID from the settings page.

SDK Methods Reference

init(options)

Initialize the chat widget with your inbox configuration.

Transactional.support('init', {
  inboxId: 'YOUR_INBOX_ID',        // Required - from inbox settings
 
  // Optional: Behavior
  defaultState: 'closed',           // 'open' | 'closed' | 'hidden'
  soundEnabled: true
});

Init Options Reference:

OptionTypeDefaultDescription
inboxIdstringRequiredYour inbox ID from settings
defaultStatestringclosedInitial widget state (see below)
soundEnabledbooleantrueEnable notification sounds

Default State Options:

ValueDescription
closedShows launcher button only (default)
openWidget opens automatically on page load
hiddenWidget is completely hidden until triggered via show()

The defaultState option can also be configured in the dashboard under Inbox Settings > Chat Widget > Default State. Client-side options override server configuration.


identify(userId, userData)

Identify a visitor as a known user. Call this when a user logs in.

Transactional.support('identify', 'user-123', {
  // Required
  email: 'john@example.com',
 
  // Recommended
  name: 'John Doe',
 
  // Optional standard fields
  phone: '+1234567890',
  avatarUrl: 'https://example.com/avatar.jpg',
 
  // Custom attributes (any key-value pairs)
  plan: 'premium',
  role: 'admin',
  lifetime_value: 5000,
  signup_date: '2024-01-01'
});

Parameters:

ParameterTypeRequiredDescription
userIdstringYesUnique user ID from your system
userDataobjectNoUser data and custom attributes

Standard User Fields:

FieldTypeDescription
emailstringUser's email address
namestringDisplay name
phonestringPhone number
avatarUrlstringProfile image URL

Any additional fields are stored as custom attributes and displayed in the dashboard.


company(companyId, companyData)

Associate the current user with a company. Useful for B2B support.

Transactional.support('company', 'company-456', {
  // Required
  name: 'Acme Inc',
 
  // Optional standard fields
  website: 'https://acme.com',
  industry: 'Technology',
  size: '100-500',
  plan: 'enterprise',
 
  // Custom attributes
  mrr: 5000,
  contract_end: '2025-01-01',
  account_manager: 'Jane Smith',
  features: ['analytics', 'api', 'sso']
});

Parameters:

ParameterTypeRequiredDescription
companyIdstringYesUnique company ID from your system
companyDataobjectNoCompany data and custom attributes

Standard Company Fields:

FieldTypeDescription
namestringCompany name
websitestringCompany website
industrystringIndustry category
sizestringCompany size range
planstringSubscription plan

trackEvent(eventName, properties)

Track a custom event for the current user. Events appear in the visitor's activity timeline.

// Simple event
Transactional.support('trackEvent', 'page_viewed');
 
// Event with properties
Transactional.support('trackEvent', 'purchase_completed', {
  orderId: 'order-123',
  amount: 99.99,
  currency: 'USD',
  products: ['Product A', 'Product B']
});
 
// Feature usage tracking
Transactional.support('trackEvent', 'feature_used', {
  feature: 'data_export',
  format: 'csv',
  rows_exported: 1500
});

Parameters:

ParameterTypeRequiredDescription
eventNamestringYesEvent name (snake_case recommended)
propertiesobjectNoAdditional event data

trackPageView()

Track a page view for the current user. Page views are automatically tracked on initial load and browser navigation, but you can manually trigger them for SPAs.

// Manual page view (for SPAs)
Transactional.support('trackPageView');

Automatic Tracking:

  • Page views are automatically tracked when the widget loads
  • Navigation via pushState and popstate is automatically detected
  • Duplicate page views to the same URL are deduplicated

show()

Show the chat widget (messenger window).

Transactional.support('show');

Opens the messenger window. If the widget was initialized with defaultState: 'hidden', this will make both the launcher and messenger visible.


hide()

Hide the chat widget (messenger window).

Transactional.support('hide');

Closes the messenger window. The launcher button remains visible (unless widget is in hidden mode).


toggle()

Toggle the messenger visibility.

Transactional.support('toggle');

If open, closes it. If closed, opens it.


shutdown()

Completely remove the widget from the page.

Transactional.support('shutdown');

Use this when:

  • User logs out
  • Navigating to a page where widget shouldn't appear
  • Single-page app cleanup

Important: After shutdown, you must call init() again to re-initialize.


on(event, callback)

Register an event listener.

// Listen for widget open
Transactional.support('on', 'show', () => {
  console.log('Widget opened');
});
 
// Listen for widget close
Transactional.support('on', 'hide', () => {
  console.log('Widget closed');
});
 
// Listen for unread count changes
Transactional.support('on', 'unreadCountChange', (count) => {
  console.log('Unread messages:', count);
  // Update your app's notification badge
  updateBadge(count);
});

Available Events:

EventCallback ArgsDescription
shownoneWidget messenger opened
hidenoneWidget messenger closed
unreadCountChangecount: numberUnread message count changed

off(event, callback)

Remove an event listener.

const myCallback = () => console.log('Widget opened');
 
// Add listener
Transactional.support('on', 'show', myCallback);
 
// Remove listener
Transactional.support('off', 'show', myCallback);

Complete Examples

Basic Integration

Copy the embed code from your inbox settings and add it before </body>:

<!DOCTYPE html>
<html>
<head>
  <title>My App</title>
</head>
<body>
  <!-- Your app content -->
 
  <!-- Transactional Support Widget -->
  <script>
    (function(w,d,s,o,n,f,js,fjs){
      w[o]=w[o]||{};w[o][n]=w[o][n]||function(){(w[o][n].q=w[o][n].q||[]).push(arguments)};
      w[o][n].l=1*new Date();js=d.createElement(s);fjs=d.getElementsByTagName(s)[0];
      js.id=o+'_'+n;js.src=f;js.async=1;fjs.parentNode.insertBefore(js,fjs);
    }(window,document,'script','Transactional','support','https://cdn.usetransactional.com/sdk/support.min.js'));
 
    Transactional.support('init', { inboxId: 'YOUR_INBOX_ID' });
  </script>
</body>
</html>

With User Authentication

// When user logs in
function onUserLogin(user) {
  Transactional.support('identify', user.id, {
    email: user.email,
    name: user.name,
    plan: user.subscription.plan
  });
 
  if (user.company) {
    Transactional.support('company', user.company.id, {
      name: user.company.name,
      plan: user.company.plan
    });
  }
}
 
// When user logs out
function onUserLogout() {
  Transactional.support('shutdown');
 
  // Re-initialize for anonymous visitors
  Transactional.support('init', { inboxId: 'YOUR_INBOX_ID' });
}

React / Next.js Integration

'use client';
 
import { useEffect } from 'react';
import { useUser } from './hooks/useUser';
 
declare global {
  interface Window {
    Transactional: {
      support: (command: string, ...args: unknown[]) => void;
    };
  }
}
 
export function SupportWidget() {
  const { user, isAuthenticated } = useUser();
 
  // Initialize widget
  useEffect(() => {
    // Load SDK
    (function(w,d,s,o,n,f,js,fjs){
      w[o]=w[o]||{};w[o][n]=w[o][n]||function(){(w[o][n].q=w[o][n].q||[]).push(arguments)};
      w[o][n].l=1*new Date();js=d.createElement(s);fjs=d.getElementsByTagName(s)[0];
      js.id=o+'_'+n;js.src=f;js.async=1;fjs.parentNode.insertBefore(js,fjs);
    }(window,document,'script','Transactional','support','https://cdn.usetransactional.com/sdk/support.min.js'));
 
    window.Transactional.support('init', {
      inboxId: process.env.NEXT_PUBLIC_SUPPORT_INBOX_ID
    });
 
    return () => {
      window.Transactional?.support?.('shutdown');
    };
  }, []);
 
  // Identify user when authenticated
  useEffect(() => {
    if (isAuthenticated && user) {
      window.Transactional.support('identify', user.id, {
        email: user.email,
        name: user.name,
        plan: user.plan
      });
    }
  }, [isAuthenticated, user]);
 
  return null;
}

Vue Integration

<script setup lang="ts">
import { onMounted, onUnmounted, watch } from 'vue';
import { useUserStore } from './stores/user';
 
declare global {
  interface Window {
    Transactional: {
      support: (command: string, ...args: unknown[]) => void;
    };
  }
}
 
const userStore = useUserStore();
 
onMounted(() => {
  // Load SDK
  (function(w,d,s,o,n,f,js,fjs){
    w[o]=w[o]||{};w[o][n]=w[o][n]||function(){(w[o][n].q=w[o][n].q||[]).push(arguments)};
    w[o][n].l=1*new Date();js=d.createElement(s);fjs=d.getElementsByTagName(s)[0];
    js.id=o+'_'+n;js.src=f;js.async=1;fjs.parentNode.insertBefore(js,fjs);
  }(window,document,'script','Transactional','support','https://cdn.usetransactional.com/sdk/support.min.js'));
 
  window.Transactional.support('init', {
    inboxId: import.meta.env.VITE_SUPPORT_INBOX_ID
  });
});
 
// Watch for auth changes
watch(() => userStore.user, (user) => {
  if (user) {
    window.Transactional.support('identify', user.id, {
      email: user.email,
      name: user.name
    });
  }
}, { immediate: true });
 
onUnmounted(() => {
  window.Transactional?.support?.('shutdown');
});
</script>

Contextual Help

// Open widget with context when user clicks help button
function openContextualHelp(topic) {
  Transactional.support('show');
  Transactional.support('trackEvent', 'help_requested', { topic });
}

Hidden Widget with Custom Trigger

Use defaultState: 'hidden' when you want full control over when the widget appears:

// Initialize widget in hidden mode
Transactional.support('init', {
  inboxId: 'YOUR_INBOX_ID',
  defaultState: 'hidden'
});
 
// Custom "Help" button in your app
document.getElementById('help-button').addEventListener('click', () => {
  Transactional.support('show');
});
 
// Or trigger based on user frustration signals
let errorCount = 0;
window.addEventListener('error', () => {
  errorCount++;
  if (errorCount >= 3) {
    Transactional.support('show');
    Transactional.support('trackEvent', 'help_offered_after_errors', {
      errorCount
    });
  }
});

Using Multiple Transactional SDKs

If you're using multiple Transactional products (Support, Forms, Auth), each SDK uses its own namespace:

<!-- Support Widget -->
<script>
  (function(w,d,s,o,n,f,js,fjs){
    w[o]=w[o]||{};w[o][n]=w[o][n]||function(){(w[o][n].q=w[o][n].q||[]).push(arguments)};
    w[o][n].l=1*new Date();js=d.createElement(s);fjs=d.getElementsByTagName(s)[0];
    js.id=o+'_'+n;js.src=f;js.async=1;fjs.parentNode.insertBefore(js,fjs);
  }(window,document,'script','Transactional','support','https://cdn.usetransactional.com/sdk/support.min.js'));
 
  Transactional.support('init', { inboxId: 'YOUR_INBOX_ID' });
</script>
 
<!-- Forms SDK (when available) -->
<script>
  (function(w,d,s,o,n,f,js,fjs){
    w[o]=w[o]||{};w[o][n]=w[o][n]||function(){(w[o][n].q=w[o][n].q||[]).push(arguments)};
    w[o][n].l=1*new Date();js=d.createElement(s);fjs=d.getElementsByTagName(s)[0];
    js.id=o+'_'+n;js.src=f;js.async=1;fjs.parentNode.insertBefore(js,fjs);
  }(window,document,'script','Transactional','forms','https://cdn.usetransactional.com/sdk/forms.min.js'));
 
  Transactional.forms('embed', { formId: 'YOUR_FORM_ID', container: '#form' });
</script>

All SDKs share the same Transactional global object but use separate namespaces. Identity set via Transactional.support('identify', ...) is automatically shared with other SDKs.


Environment Variables

Add these to your environment file:

# Get your inbox ID from the inbox settings page
NEXT_PUBLIC_SUPPORT_INBOX_ID=your-inbox-id

Troubleshooting

Widget Not Appearing

  1. Check inbox ID is correct
  2. Verify script is loaded (Network tab)
  3. Check console for errors
  4. Ensure CSP allows the script domain

User Not Being Identified

  1. Verify identify is called after init
  2. Check user ID is a string
  3. Confirm user data format

Events Not Tracking

  1. Ensure widget is initialized
  2. Check event name is a string
  3. Verify network requests succeed

Messages Not Sending

  1. Check WebSocket connection
  2. Verify inbox is active
  3. Check for rate limiting

Next Steps