Web Messenger Javascript Api

This document covers the FlowXO JavaScript API for programmatic control of the chat widget.

Getting Started

Most integrations only need a few lines of code. Here are the most common patterns:

Basic Setup with User Identity

Use window.onFlowXOInit to configure the widget and identify users before it connects:

<script>
  window.onFlowXOInit = async (connectionId) => {
    // Fetch user data from your backend
    const user = await fetchCurrentUser();

    return {
      member: user
        ? {
            id: user.id,
            name: user.displayName,
            email: user.email,
            metadata: {
              plan: user.plan,
              company: user.company,
            },
          }
        : undefined,
      config: {
        primaryColor: '#4F46E5',
        header: {
          title: 'Support',
        },
      },
    };
  };
</script>
<script
  src="https://messenger.flowxo.com/loader.js"
  data-connection="your-connection-id"
></script>

Auto-Open After Delay

Use the flowxo:ready event to interact with the widget after it initializes:

<script>
  document.addEventListener('flowxo:ready', (event) => {
    const { connectionId } = event.detail;

    // Open the widget after 30 seconds
    setTimeout(() => {
      FlowXO.open(connectionId);
    }, 30000);
  });
</script>
<script
  src="https://messenger.flowxo.com/loader.js"
  data-connection="your-connection-id"
></script>

Track Widget Events

Listen for user interactions and messages:

FlowXO.on('open', ({ connectionId }) => {
  analytics.track('widget_opened', { connectionId });
});

FlowXO.on('userMessage', ({ connectionId, message }) => {
  console.log('User sent:', message);
});

FlowXO.on('agentMessage', ({ connectionId, message }) => {
  // Show notification if widget is closed
  if (!FlowXO.isOpen(connectionId)) {
    showNotification('New message from support');
  }
});

Update User Identity on Login/Logout

// When user logs in
document.getElementById('login-btn').addEventListener('click', async () => {
  const user = await loginUser();
  FlowXO.identify({
    id: user.id,
    name: user.name,
    email: user.email,
  });
});

// When user logs out
document.getElementById('logout-btn').addEventListener('click', () => {
  FlowXO.logout();
});

Global API

The FlowXO API is exposed on window.FlowXO after the loader script initializes.

FlowXO.init(options)

Programmatically initialize a new widget instance. Use this for manual control instead of auto-initialization via data-connection attributes.

const widget = await FlowXO.init({
  connectionId: 'your-connection-id',
  config: {
    // Optional: configuration overrides
    primaryColor: '#6F5FE8',
  },
  user: {
    // Optional: user identity
    id: 'user-123',
    name: 'John Doe',
    email: 'john@example.com',
  },
});

Parameters:

Property Type Required Description
connectionId string Yes Connection ID for the widget
config object No Configuration overrides (merged with server config)
user Member No User identity to set (same as calling identify())

Returns: Promise<WidgetInstance | undefined>


FlowXO.identify(member) / FlowXO.identify(connectionId, member)

Identify a user for personalization and conversation continuity.

// Single widget (uses first/default instance)
FlowXO.identify({
  id: 'user-123',
  name: 'John Doe',
  email: 'john@example.com',
  avatar: 'https://example.com/john.jpg',
  metadata: {
    plan: 'premium',
    signupDate: '2024-01-15',
  },
});

// Multiple widgets (specify connection ID)
FlowXO.identify('connection-id-1', {
  id: 'user-123',
  name: 'John Doe',
});

Member Properties:

Property Type Required Description
id string Yes Unique identifier for user
name string No Display name
email string No Email address
avatar string No Avatar image URL
metadata object No Custom metadata key-values

Alias: FlowXO.setUser() - identical functionality


FlowXO.logout(connectionId?)

Clear user identity and optionally start a new conversation.

// Single widget
FlowXO.logout();

// Multiple widgets
FlowXO.logout('connection-id-1');

Alias: FlowXO.clearUser() - identical functionality


FlowXO.open(connectionId?)

Open the widget.

FlowXO.open();
FlowXO.open('connection-id-1'); // For multiple widgets

FlowXO.close(connectionId?)

Close the widget.

FlowXO.close();
FlowXO.close('connection-id-1'); // For multiple widgets

FlowXO.toggle(connectionId?)

Toggle the widget open/closed.

FlowXO.toggle();
FlowXO.toggle('connection-id-1'); // For multiple widgets

FlowXO.isOpen(connectionId?)

Check if the widget is currently open.

if (FlowXO.isOpen()) {
  console.log('Widget is open');
}

Returns: boolean


FlowXO.setConfig(config, connectionId?)

Update widget configuration at runtime. Changes are merged with existing config and persisted to local storage.

FlowXO.setConfig({
  primaryColor: '#FF5733',
  header: {
    title: 'Updated Title',
  },
});

Launcher Customization

Customize the launcher button appearance at runtime:

// Use a custom image as the launcher (full mode)
FlowXO.setConfig({
  launcher: {
    mode: 'full',
    shape: 'rounded',
    iconUrl: 'https://example.com/mascot.png',
    closeIconUrl: 'https://example.com/close.png',
  },
});

// Custom icon with circle shape (default mode)
FlowXO.setConfig({
  launcher: {
    mode: 'icon',
    shape: 'circle',
    iconUrl: 'https://example.com/chat-icon.svg',
    color: '#6F5FE8',
  },
});

// Square launcher with no shadow
FlowXO.setConfig({
  launcher: {
    mode: 'full',
    shape: 'none',
    iconUrl: 'https://example.com/square-mascot.png',
  },
});

Launcher Properties:

Property Type Default Description
mode "icon" | "full" "icon" Display mode. "full" uses the image as the entire launcher
shape "circle" | "rounded" | "none" "circle" Shape of the launcher. "none" = square with no shadow
iconUrl string - Custom icon/image URL
closeIconUrl string - Custom close icon URL (when widget is open)
color string - Background color (only applies in "icon" mode)

Note: Configuration changes are persisted to local storage and will be applied on subsequent page loads.


FlowXO.setLocale(locale, connectionId?)

Set the widget's language/locale for UI strings and localized content.

// Set to Spanish
FlowXO.setLocale('es');

// Set to French for a specific widget
FlowXO.setLocale('fr', 'support-widget');

Parameters:

Parameter Type Required Description
locale string Yes Language code (e.g., "en", "es", "fr")
connectionId string No Target widget (defaults to first instance)

This is a convenience method equivalent to FlowXO.setConfig({ language: locale }).


FlowXO.sendMessage(text, connectionId?)

Send a message programmatically as the user.

FlowXO.sendMessage('Hello, I need help with my order');

If the widget is closed, the message is queued and sent when opened.


FlowXO.getHistory(connectionId?)

Get the conversation history.

const messages = await FlowXO.getHistory();
console.log(messages);
// [
//   { id: "1", role: "user", text: "Hello", timestamp: "2024-01-15T10:00:00Z" },
//   { id: "2", role: "assistant", text: "Hi! How can I help?", timestamp: "2024-01-15T10:00:01Z" }
// ]

Returns: Promise<HistoryMessage[]>

HistoryMessage Properties:

Property Type Description
id string Message ID
role "user" | "assistant" Message sender
text string Message text content
timestamp string ISO timestamp

FlowXO.clearConversation(connectionId?)

Clear the conversation and start fresh.

FlowXO.clearConversation();

FlowXO.destroy(connectionId?)

Destroy a widget instance, removing it from the DOM.

FlowXO.destroy();
FlowXO.destroy('connection-id-1'); // For multiple widgets

Events

Subscribe to widget events to react to user interactions and widget state changes.

FlowXO.on(event, callback)

Subscribe to a widget event.

FlowXO.on('message', (data) => {
  console.log('New message:', data);
});

FlowXO.off(event, callback)

Unsubscribe from a widget event.

const handler = (data) => console.log(data);
FlowXO.on('message', handler);

// Later...
FlowXO.off('message', handler);

Event Types

Event Description Data
open Widget was opened { connectionId }
close Widget was closed { connectionId }
message Any message (user or agent) { connectionId, message }
userMessage User sent a message { connectionId, message }
agentMessage Agent sent a message { connectionId, message }
error An error occurred { connectionId, error }
connectionChange WebSocket connection state changed { connectionId, connected }
conversationCleared Conversation was cleared { connectionId }

Event Example

// Track when users open/close the widget
FlowXO.on('open', ({ connectionId }) => {
  analytics.track('widget_opened', { connectionId });
});

FlowXO.on('close', ({ connectionId }) => {
  analytics.track('widget_closed', { connectionId });
});

// React to new messages
FlowXO.on('agentMessage', ({ connectionId, message }) => {
  // Show browser notification if widget is closed
  if (!FlowXO.isOpen(connectionId)) {
    showNotification('New message from support');
  }
});

Initialization Hook

Use window.onFlowXOInit to customize widget initialization. This callback is called for each widget instance before it connects, allowing you to set user identity and configuration dynamically.

<script>
  window.onFlowXOInit = async (connectionId) => {
    // Fetch user data from your backend
    const user = await fetchCurrentUser();

    return {
      // Set user identity (optional)
      member: user
        ? {
            id: user.id,
            name: user.displayName,
            email: user.email,
          }
        : undefined,

      // Override configuration (optional)
      config: {
        primaryColor: '#6F5FE8',
        header: {
          title: 'Help Center',
        },
      },
    };
  };
</script>
<script
  src="https://messenger.flowxo.com/loader.js"
  data-connection="your-connection-id"
></script>

Return Properties:

Property Type Description
member Member User identity to set (optional)
config object Configuration overrides (optional)

The callback receives connectionId as a parameter, which is useful when you have multiple widgets on the same page with different configurations.


Loaded Event

The flowxo:loaded event fires when the FlowXO API is ready but before any widgets are auto-initialized. Use this for programmatic initialization when you want full control over when widgets are created.

document.addEventListener('flowxo:loaded', (event) => {
  const { FlowXO } = event.detail;

  // API is ready - initialize widgets programmatically
  FlowXO.init({
    connectionId: 'support-bot',
    user: { id: currentUser.id, name: currentUser.name },
  });
});

Event Detail:

Property Type Description
FlowXO FlowXOAPI The FlowXO API object

Use case: Load the script without data-connection to prevent auto-init, then use flowxo:loaded to initialize widgets conditionally (e.g., only for logged-in users, or after certain page conditions are met).


Ready Event

The flowxo:ready event fires when a widget instance has been initialized and is ready to use. Use this to interact with a specific widget after it's created.

document.addEventListener('flowxo:ready', (event) => {
  const { connectionId, instance } = event.detail;
  console.log('Widget ready:', connectionId);

  // Now safe to call API methods
  FlowXO.open(connectionId);
});

Event Detail:

Property Type Description
connectionId string The widget's connection ID
instance WidgetInstance The widget instance (internal)

For multiple widgets, the event fires once for each widget as it becomes ready.


Multiple Widget Instances

When embedding multiple widgets on a page, pass the connectionId parameter to target specific instances:

// Initialize two widgets
await FlowXO.init({ connectionId: 'sales-bot' });
await FlowXO.init({ connectionId: 'support-bot' });

// Control specific widgets
FlowXO.open('sales-bot');
FlowXO.close('support-bot');

// Identify user on specific widget
FlowXO.identify('sales-bot', {
  id: 'user-123',
  name: 'John',
});

When connectionId is omitted, the API operates on the first/default widget instance.


Debug Mode

Enable debug mode for development by adding ?fxo_debug=true to the page URL:

https://yoursite.com/page?fxo_debug=true

Debug mode provides:

  • Detailed console logging
  • Access to FlowXO._debug utilities
// When debug mode is enabled
FlowXO._debug.log('custom', 'Debug message');
FlowXO._debug.getInstances(); // Get all widget instances

Complete Example

<!DOCTYPE html>
<html>
  <head>
    <title>FlowXO Widget Example</title>
  </head>
  <body>
    <!-- Initialize callback (runs before widget connects) -->
    <script>
      window.onFlowXOInit = async (connectionId) => {
        // Optionally fetch user from your backend
        const user = await fetchCurrentUser().catch(() => null);

        return {
          member: user
            ? {
                id: user.id,
                name: user.name,
                email: user.email,
              }
            : undefined,
          config: {
            primaryColor: '#6F5FE8',
            header: {
              title: 'Help Center',
              subtitle: 'We typically reply within minutes',
            },
            launcher: {
              mode: 'full',
              shape: 'rounded',
              iconUrl: 'https://example.com/mascot.png',
              closeIconUrl: 'https://example.com/close.png',
            },
          },
        };
      };

      // React to widget ready event
      document.addEventListener('flowxo:ready', (event) => {
        const { connectionId } = event.detail;
        console.log('Widget ready:', connectionId);

        // Set up event listeners
        FlowXO.on('open', () => console.log('Widget opened'));
        FlowXO.on('close', () => console.log('Widget closed'));
        FlowXO.on('userMessage', ({ message }) =>
          console.log('User said:', message)
        );
      });
    </script>

    <!-- Load the widget -->
    <script
      src="https://messenger.flowxo.com/loader.js"
      data-connection="your-connection-id"
      async
    ></script>

    <!-- Your application code -->
    <script>
      // Identify user when they log in (after initial load)
      document
        .getElementById('login-btn')
        .addEventListener('click', async () => {
          const user = await loginUser();
          FlowXO.identify({
            id: user.id,
            name: user.name,
            email: user.email,
          });
        });

      // Clear identity on logout
      document.getElementById('logout-btn').addEventListener('click', () => {
        FlowXO.logout();
      });

      // Custom button to open widget
      document.getElementById('help-btn').addEventListener('click', () => {
        FlowXO.open();
      });
    </script>

    <button id="login-btn">Log In</button>
    <button id="logout-btn">Log Out</button>
    <button id="help-btn">Get Help</button>
  </body>
</html>

Configuration Options Reference

Property Type Description
connectionId string Unique identifier for this chat connection
name string Display name of the connection
workspaceId string Workspace ID this connection belongs to
organizationId string Organization ID
settings WebChatSettings Widget configuration settings (see below)
token string JWT token for authentication (generated at edge)

WebChatSettings

Property Type Description
Display Mode
mode "popup" | "sidebar" | "fullscreen" Widget display mode
initialState "closed" | "open" Initial widget state on page load
mobileInitialState "closed" | "open" Initial state on mobile devices
mobileMode "fullscreen" | "floating" | "inherit" Display mode on mobile devices
Theme
primaryColor string Primary brand color (hex)
accentColor string Accent color for buttons/links. Defaults to primaryColor
theme "light" | "dark" | "auto" Color theme
backgroundColor string Widget background color (hex)
backgroundOpacity number (0-100) Background opacity percentage
customCss string Inline custom CSS
customCssUrl string URL to external custom CSS file
Localization
language string Default language code (e.g., "en", "es")
languages Record<string, Record<string, string>> Custom translation overrides by language
Feature Flags
autoplayAudio boolean Automatically play audio messages
isTestConsole boolean Enable test/debug mode
Nested Configs
header HeaderConfig Header appearance settings
launcher LauncherConfig Launcher button settings
widget WidgetConfig Widget size and URL filtering
welcome WelcomeConfig Welcome message and suggestions
messages MessagesConfig Message bubble appearance
attentionGetter AttentionGetterConfig Attention-grabbing animation settings
composer ComposerConfig Message input settings
attribution AttributionConfig Powered-by attribution settings
privacy PrivacyConfig Privacy and data collection settings
newMessageSound NewMessageSoundConfig Sound notification settings
security SecurityConfig Domain restrictions and security
settingsPanel SettingsPanelConfig User settings panel options
messagePreview MessagePreviewConfig Message preview bubble settings
hostedPage HostedPageConfig Standalone chat page settings
noMessageBehavior NoMessageBehaviorConfig Display when no messages in conversation
channelId ChannelIdConfig Conversation isolation via storage partitioning

HeaderConfig

Property Type Description
title LocalizedString Header title text
subtitle LocalizedString Header subtitle text
iconUrl string URL to header icon/logo
iconBackground string Background color for icon (hex)
hidden boolean Hide the header entirely
showReset boolean Show clear conversation button

LauncherConfig

Property Type Description
disabled boolean Disable the launcher button entirely
position "bottom-right" | "bottom-left" Screen position
offset { x?: number, y?: number } Custom offset from default position (px)
color string Background color (hex) - only in "icon" mode
iconUrl string Custom icon URL (SVG, PNG, animated GIF)
closeIconUrl string Custom icon when widget is open
mode "icon" | "full" "icon": inset in styled button. "full": image IS the launcher
shape "circle" | "rounded" | "none" Launcher shape (only in "full" mode)
disableUnreadNotifications boolean Disable unread badge & observer

WidgetConfig

Property Type Description
size "sm" | "md" | "lg" | "xl" | "full" Widget size preset
urlFilter UrlFilterConfig URL-based widget visibility rules

UrlFilterConfig

Property Type Description
include string[] URL prefixes where widget appears (allowlist)
exclude string[] URL prefixes where widget is hidden (blocklist)

WelcomeConfig

Property Type Description
message LocalizedString Welcome message text
choices LocalizedMessageChoice[] Quick reply buttons
suggestions LocalizedString[] Suggested prompts

LocalizedMessageChoice

Property Type Description
value string Value sent when clicked (optional, defaults to label)
label LocalizedString Button display text
type "quickreply" | "url" Action type
urlTarget "new_tab" | "current_tab" Where to open URL (for type "url")

MessagesConfig

Property Type Description
user MessageRoleConfig User message appearance
assistant MessageRoleConfig AI assistant message appearance
liveagent MessageRoleConfig Human agent message appearance

MessageRoleConfig

Property Type Description
avatar { enabled?: boolean, iconUrl?: string } Avatar settings
bubbleColor string Message bubble background color (hex)
bubbleArrow boolean Show speech bubble arrow

ComposerConfig

Property Type Description
prompt LocalizedString Placeholder text in input field
disabled boolean Disable the message input
audio AudioConfig Voice message settings
attachments AttachmentsConfig File attachment settings

AudioConfig

Property Type Description
disabled boolean Disable voice messages
maxLengthInSeconds number Maximum recording length
autosend boolean Auto-send when recording stops

AttachmentsConfig

Property Type Description
disabled boolean Disable file attachments
maxFileSizeInBytes number Maximum file size
maxAttachments number Maximum number of attachments per message
types string[] Allowed MIME types
autosend boolean Auto-send after attaching
imageOnly boolean Only allow image attachments

AttentionGetterConfig

Property Type Description
text LocalizedString Attention-getter message text
delayInSeconds number Delay before showing
durationInSeconds number How long to display
expirationInDays number Days before showing again
intensity "subtle" | "moderate" | "attention-grabbing" Animation intensity
playSound boolean Play sound with animation
soundUrl string Custom sound URL

PrivacyConfig

Property Type Description
forgetChat boolean Clear conversation when widget closes
zeroFootprint boolean Prevent any localStorage usage
collectIp boolean Collect IP address and precise location (default: true)

SecurityConfig

Property Type Description
allowedDomains string[] Domains where widget can be embedded
allowEvaluation boolean Allow JavaScript expression evaluation

Other Configs

Config Properties
NewMessageSoundConfig enabled?: boolean, soundUrl?: string
MessagePreviewConfig enabled?: boolean
HostedPageConfig enabled?: boolean
AttributionConfig disabled?: boolean, text?: LocalizedString, url?: string
SettingsPanelConfig enabled?: boolean, features?: { soundToggle?: boolean, clearConversation?: boolean }

NoMessageBehaviorConfig

Property Type Description
type "typing_indicator" | "loading_message" | "none" Display type when no messages
loadingMessageText LocalizedString | LocalizedString[] Loading message text(s)
cycleIntervalMs number Interval for cycling messages (default: 3000)
timeoutSeconds number Hide after timeout

ChannelIdConfig

Property Type Description
prefix string Prefix for generated channel IDs
separator string Separator between prefix and ID (default: "_")

LocalizedString Type

Format Example
Simple string "Hello!"
Object with translations { "default": "Hello!", "translations": { "es": "¡Hola!" } }

Sample JSON

{
  "connectionId": "conn_abc123xyz",
  "name": "Acme Support Bot",
  "workspaceId": "ws_def456uvw",
  "organizationId": "org_ghi789rst",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "settings": {
    "mode": "popup",
    "initialState": "closed",
    "mobileInitialState": "closed",
    "mobileMode": "fullscreen",
    "primaryColor": "#4F46E5",
    "accentColor": "#7C3AED",
    "theme": "light",
    "backgroundColor": "#FFFFFF",
    "backgroundOpacity": 100,
    "customCss": ".fxo-header { font-weight: bold; }",
    "customCssUrl": "https://example.com/custom-widget.css",
    "language": "en",
    "languages": {
      "es": {
        "composer.placeholder": "Escribe un mensaje..."
      }
    },
    "autoplayAudio": false,
    "isTestConsole": false,
    "header": {
      "title": {
        "default": "Acme Support",
        "translations": { "es": "Soporte Acme" }
      },
      "subtitle": "We typically reply within minutes",
      "iconUrl": "https://example.com/logo.png",
      "iconBackground": "#E0E7FF",
      "hidden": false
    },
    "launcher": {
      "disabled": false,
      "position": "bottom-right",
      "offset": { "x": 10, "y": 20 },
      "color": "#4F46E5",
      "iconUrl": "https://example.com/chat-icon.svg",
      "closeIconUrl": "https://example.com/close-icon.svg",
      "mode": "icon",
      "shape": "circle"
    },
    "widget": {
      "size": "md",
      "urlFilter": {
        "include": ["https://example.com/support", "https://example.com/help"],
        "exclude": ["https://example.com/admin"]
      }
    },
    "welcome": {
      "message": "Hi there! How can I help you today?",
      "choices": [
        {
          "label": "Track my order",
          "value": "track_order",
          "type": "quickreply"
        },
        {
          "label": "Visit FAQ",
          "type": "url",
          "value": "https://example.com/faq",
          "urlTarget": "new_tab"
        }
      ],
      "suggestions": ["What are your hours?", "How do I return an item?"]
    },
    "messages": {
      "user": {
        "avatar": { "enabled": false },
        "bubbleColor": "#E0E7FF",
        "bubbleArrow": true
      },
      "assistant": {
        "avatar": { "enabled": true, "iconUrl": "https://example.com/bot-avatar.png" },
        "bubbleColor": "#F3F4F6",
        "bubbleArrow": true
      },
      "liveagent": {
        "avatar": { "enabled": true, "iconUrl": "https://example.com/agent-avatar.png" },
        "bubbleColor": "#FEF3C7",
        "bubbleArrow": true
      }
    },
    "composer": {
      "prompt": "Type your message...",
      "disabled": false,
      "audio": {
        "disabled": false,
        "maxLengthInSeconds": 120,
        "autosend": false
      },
      "attachments": {
        "disabled": false,
        "maxFileSizeInBytes": 10485760,
        "maxAttachments": 5,
        "types": ["image/*", "application/pdf"],
        "autosend": false,
        "imageOnly": false
      }
    },
    "attentionGetter": {
      "text": "Need help? We're here for you!",
      "delayInSeconds": 30,
      "durationInSeconds": 10,
      "expirationInDays": 7,
      "intensity": "moderate",
      "playSound": true,
      "soundUrl": "https://example.com/notification.mp3"
    },
    "attribution": {
      "disabled": false,
      "text": "Powered by Flow XO",
      "url": "https://flowxo.com"
    },
    "privacy": {
      "forgetChat": false,
      "zeroFootprint": false,
      "collectIp": true
    },
    "newMessageSound": {
      "enabled": true,
      "soundUrl": "https://example.com/message-sound.mp3"
    },
    "security": {
      "allowedDomains": ["example.com", "*.example.com"],
      "allowEvaluation": false
    },
    "settingsPanel": {
      "enabled": true,
      "features": {
        "soundToggle": true,
        "clearConversation": true
      }
    },
    "messagePreview": {
      "enabled": true
    },
    "hostedPage": {
      "enabled": true
    },
    "noMessageBehavior": {
      "type": "typing_indicator",
      "loadingMessageText": "Connecting you with support...",
      "cycleIntervalMs": 3000,
      "timeoutSeconds": 30
    },
    "channelId": {
      "prefix": "acme",
      "separator": "_"
    }
  }
}

Next Steps

Still need help? Contact Us Contact Us