Skip to main content

Why the Cevro Widget?

Cevro integrates with the helpdesks you already use—Intercom, Zendesk, LiveChat, Zoho—and that works great. But there’s a ceiling. Third-party platforms weren’t built for AI-first support, and some features just aren’t possible when you’re working within someone else’s system. The Cevro Widget removes that ceiling. It’s a native chat experience built from the ground up for AI-powered support. Faster responses, richer interactions, and new capabilities that ship here first.

Built for AI

Designed from the ground up for AI-powered support. Features like rich player context, real-time tool calls, and intelligent escalation work seamlessly—no third-party constraints.

Your Workspace, Your Widget

Connects directly to your AI Procedures, knowledge base, and back-office integrations. Everything you’ve configured in Cevro works out of the box.

New Features First

Advanced capabilities—like proactive messaging, smart nudges, and deeper personalization—will launch here first. Some features won’t be possible on third-party widgets at all.

Simple & Reliable

One integration, one source of truth. No complex API choreography between systems. Faster responses, fewer failure points.

How It Works

1. EMBED SDK → Add the Cevro SDK to your website

2. PLAYER CHATS → AI handles the conversation
   Using your knowledge base and AI Procedures

3. ESCALATION (if needed) → Transfer to human agent
   Via LiveChat or Intercom integration
All conversations are processed by Cevro’s AI engine. When escalation is needed, the conversation is transferred to your human agents through your configured helpdesk (LiveChat or Intercom).

Installation

Copy and paste this snippet before the closing </body> tag. The loader fetches the latest SDK version automatically.
<script>
  (function(){
    window.cevroSettings = {
      workspaceId: 'YOUR_WORKSPACE_ID',
      brandId: 'YOUR_BRAND_ID'
    };
    var c = function(){c.q.push([].slice.call(arguments))};
    c.q = [];
    window.Cevro = c;
    var s = document.createElement('script');
    s.src = 'https://cdn.jsdelivr.net/npm/cevro-messenger-sdk/dist/loader/loader.js';
    s.async = true;
    document.head.appendChild(s);
  })();
</script>
You can queue commands before the SDK loads:
// These work immediately, even before the SDK finishes loading
Cevro('identify', { playerId: 'player-123', email: '[email protected]' });
Cevro('show');

Configuration

Required Settings

SettingTypeDescription
apiBasestringBackend API URL (e.g., https://chat.cevro.ai)
workspaceIdstringYour workspace identifier
brandIdstringThe brand to use for this widget instance

Optional Settings

SettingTypeDefaultDescription
playerPlayerDataAuthenticated player information
alignment'left' | 'right''right'Widget horizontal position
verticalPaddingnumber20Distance from bottom (px)
horizontalPaddingnumber20Distance from edge (px)
primaryColorstringPrimary brand color (hex, e.g. '#6366f1')
themeThemeConfigCustom theme colors and styling
localePartial<LocaleStrings>UI text overrides for localization
hideDefaultLauncherbooleanfalseHide the default launcher button
customLauncherSelectorstringCSS selector for your own launcher element
zIndexnumber2147483647Stacking order

Theming & Appearance

The widget appearance can be customized at two levels:
  1. Admin dashboard — Configure colors, logo and icons in Settings → Cevro (applies to all visitors)
  2. SDK config — Override specific properties per-instance during initialization

Primary Color

The simplest way to brand the widget. Set a single primaryColor and all accent elements (launcher button, user message bubbles, send button, links) will derive from it automatically:
const chat = new CevroMessenger({
  // ... required config
  primaryColor: '#E91E63'
});
This is also available in the admin dashboard under Settings → Cevro → Primary Color. You can set just the primary color and leave everything else on defaults — the widget will look great out of the box.

Custom Theme

For granular control, pass a theme object to override specific colors and styles:
const chat = new CevroMessenger({
  // ... required config
  primaryColor: '#E91E63',
  theme: {
    backgroundColor: '#1e293b',
    backgroundSecondaryColor: '#0f172a',
    textColor: '#f1f5f9',
    textSecondaryColor: '#94a3b8',
    borderColor: '#334155',
    userMessageBackgroundColor: '#334155',
    userMessageTextColor: '#f1f5f9',
    agentMessageBackgroundColor: '#1e293b',
    agentMessageTextColor: '#f1f5f9',
    headerBackgroundColor: '#0f172a',
    headerTextColor: '#f1f5f9',
    inputBackgroundColor: '#0f172a',
    launcherBackgroundColor: '#E91E63',
    launcherIconColor: '#ffffff',
    launcherHoverShadowColor: 'rgba(233, 30, 99, 0.4)',
    sendButtonBackgroundColor: '#E91E63',
    sendButtonIconColor: '#ffffff',
    fileButtonBackgroundColor: '#334155',
    fileButtonIconColor: '#94a3b8',
    borderRadius: 16,
    shadowColor: 'rgba(0, 0, 0, 0.4)',
  }
});
All properties are optional — only specify the ones you want to override. Everything else falls back to defaults.

Theme Properties Reference

General

PropertyTypeDescription
backgroundColorstringMain background color of the chat window
backgroundSecondaryColorstringSecondary/alternate background
textColorstringPrimary text color
textSecondaryColorstringSecondary/muted text color
borderColorstringBorder color for dividers and outlines

Messages

PropertyTypeDescription
userMessageBackgroundColorstringUser message bubble background
userMessageTextColorstringUser message text color
agentMessageBackgroundColorstringAgent/AI message bubble background
agentMessageTextColorstringAgent/AI message text color
PropertyTypeDescription
headerBackgroundColorstringChat header background
headerTextColorstringChat header text color

Input

PropertyTypeDescription
inputBackgroundColorstringMessage input field background

Launcher Button

PropertyTypeDescription
launcherBackgroundColorstringLauncher button background (defaults to primaryColor)
launcherIconColorstringLauncher button icon color
launcherHoverShadowColorstringShadow color on hover (e.g. rgba(0, 0, 0, 0.3))

Action Buttons

PropertyTypeDescription
sendButtonBackgroundColorstringSend button background (defaults to primaryColor)
sendButtonIconColorstringSend button icon color
fileButtonBackgroundColorstringFile/attachment button background
fileButtonIconColorstringFile/attachment button icon color

Style

PropertyTypeDescription
borderRadiusnumberBorder radius in pixels for rounded corners
shadowColorstringBox shadow color with opacity (e.g. rgba(0, 0, 0, 0.2))

Admin Dashboard Appearance

All theme properties can be managed from the admin dashboard under Settings → Cevro → Appearance:
  • Primary Color — Set the main brand color. All accent elements derive from it automatically.
  • Full Theme — Override any individual color (backgrounds, text, messages, buttons, launcher, etc.).
  • Reset to Primary — Clear all custom theme overrides and go back to deriving everything from the primary color.
  • Bubble Icon — Custom icon for the launcher button.
  • Custom Logo — Brand logo displayed in the chat header.
Theme settings are merged with the following priority (highest first):
  1. SDK config — Values passed in theme during initialization
  2. Admin dashboard — Appearance configured in Settings → Cevro
  3. Defaults — Built-in default values
This lets you configure a base theme in the dashboard while overriding specific properties per-instance in the SDK.

Player Authentication

For authenticated players, pass their information during initialization:
const chat = new CevroMessenger({
  // ... required config
  player: {
    playerId: 'player-123',
    firstName: 'John',
    lastName: 'Doe',
    email: '[email protected]',
    phone: '+1234567890',
    avatar: 'https://example.com/avatar.jpg',
    customAttributes: {
      vipLevel: 'gold',
      totalDeposits: 5000
    },
    playerHash: 'hmac-signature'
  }
});

Supported Player Fields

FieldTypeDescription
playerIdstringRequired. Unique player identifier
playerHashstringHMAC signature for identity verification
firstNamestringPlayer’s first name
lastNamestringPlayer’s last name
emailstringPlayer’s email address
phonestringPlayer’s phone number
avatarstringURL to player’s avatar image
createdAtnumberUnix timestamp of player account creation
customAttributesobjectCustom key-value pairs (string, number, or boolean values)
Security: Always use playerHash (HMAC signature) in production to prevent player impersonation. Generate the hash server-side using your HMAC secret.

Identifying Players After Login

Use identify() to associate an anonymous visitor with an authenticated player after they log in:
// After the player logs in
chat.identify({
  playerId: 'player-123',
  email: '[email protected]',
  firstName: 'John',
  playerHash: 'hmac-signature'
});
If the widget is already booted, identify() performs a soft re-initialization — it reconnects with the new player identity and creates a new session without destroying the UI. If called before boot(), the data is stored and used when boot() is called later. Returns a Promise if you need to wait for completion.

Connecting Player Data to Integrations

Player data you pass through the widget becomes available to your AI Procedures and back-office integrations. Here’s how.

Standard Fields

Fields like playerId, email, firstName, lastName, and phone are stored directly on the player’s contact record. Integrations can reference them automatically — for example, a tool parameter set to {{contact.email}} will resolve to the player’s email.

Custom Attributes

For additional data (session tokens, account types, VIP levels), use customAttributes:
const chat = new CevroMessenger({
  // ... required config
  player: {
    playerId: 'player-123',
    playerHash: 'hmac-signature',
    customAttributes: {
      sessionToken: 'tok_abc123',
      accountType: 'premium',
    },
  },
});
Integrations reference these as {{contact.sessionToken}}, {{contact.accountType}}, etc.
Protected fields: Standard player fields (email, firstName, lastName, phone, address) cannot be passed inside customAttributes — they are automatically stripped. Pass these as top-level fields in the player object instead. Only use customAttributes for additional data that doesn’t have a dedicated field.
Define your fields first. Before passing custom attributes, create the corresponding fields in Settings → Player Attributes. This ensures proper type handling and makes the fields visible across your workspace.

Example: Passing a Session Token to a Tool

1

Define the field

Go to Settings → Player Fields and create a field called sessionToken (type: string).
2

Pass it in the widget

Include sessionToken in customAttributes when initializing the widget (see example above).
3

Use it in a tool

In your tool configuration, set a parameter value to {{contact.sessionToken}}. When the AI invokes the tool, the player’s session token is sent to your back-office API.

Public API

Lifecycle

MethodDescription
boot()Initialize widget, render UI, fetch appearance config from dashboard
shutdown(options?)Remove widget. Pass { clearVisitorData: true } to clear local storage.
show()Open chat window (also initializes session and WebSocket connection)
hide()Close chat window
toggle()Toggle visibility
showLauncher()Show the launcher button (creates it if hideDefaultLauncher was set)
hideLauncher()Hide the launcher button

Player & Config

MethodDescription
identify(playerData)Identify a player after login. Performs soft re-init (async).
update(config)Update SDK configuration (theme, locale, etc). Does not re-init session. For player identity changes, use identify().
getVisitorId()Get the current visitor ID
getUnreadCount()Get the current unread message count

Appearance

MethodDescription
updateAppearance(config)Dynamically update colors, theme, icons, and logo
getAppearance()Get the current appearance configuration
// Dynamically update appearance at runtime
chat.updateAppearance({
  primaryColor: '#10b981',
  theme: {
    headerBackgroundColor: '#064e3b',
    headerTextColor: '#ffffff',
  },
});

Custom Launcher

By default the SDK renders a floating launcher button. You can hide it and use your own button instead.

Hide the Default Launcher

const chat = new CevroMessenger({
  // ... required config
  hideDefaultLauncher: true,
});
chat.boot();

// Open chat programmatically
chat.show();

Use Your Own Launcher Element

Point customLauncherSelector at any element on your page. Clicks on that element will toggle the chat window:
<button id="my-chat-btn">Chat with us</button>

<script>
  const chat = new CevroMessenger({
    // ... required config
    hideDefaultLauncher: true,
    customLauncherSelector: '#my-chat-btn',
  });
  chat.boot();
</script>

Show / Hide Launcher at Runtime

You can show or hide the default launcher dynamically — even if it was hidden at boot:
chat.hideLauncher(); // hide the launcher button
chat.showLauncher(); // show it again (creates it if hideDefaultLauncher was set)

Events

Subscribe to events using on(). It returns an unsubscribe function:
const unsubscribe = chat.on('message:received', (data) => {
  console.log('New message:', data.message.body);
});

// Unsubscribe later
unsubscribe();
You can also unsubscribe with off():
const handler = (data) => console.log(data);
chat.on('message:received', handler);
chat.off('message:received', handler);

Available Events

EventPayloadDescription
bootWidget initialized
readyWebSocket connected and ready
showChat window opened
hideChat window closed
shutdownWidget removed
session:initialized{ sessionId, contactId, ticketId, isNewSession, isNewTicket }Session created or restored
message:received{ ticketId, message }New message from agent/AI
message:sent{ message }Message successfully sent
unread_count_change{ count }Unread count changed
conversation:started{ ticketId }New conversation started
conversation:updated{ ticketId, status, message?, closedAt? }Conversation status changed (e.g. closed)
chat:new_startedNew chat started after previous was closed
typing:start{ ticketId, actor }Agent/AI started typing
typing:stopAgent/AI stopped typing
error{ type, error, message? }An error occurred
connection:openWebSocket connected
connection:closeWebSocket disconnected
connection:error{ error }WebSocket error
appearance:updatedWidgetAppearanceConfigAppearance changed

Example: Notifications & Analytics

chat.on('message:received', (data) => {
  if (Notification.permission === 'granted') {
    new Notification('New message', { body: data.message.body });
  }
});

chat.on('show', () => {
  analytics.track('chat_opened');
});

chat.on('unread_count_change', (data) => {
  document.querySelector('.badge').textContent = data.count;
});

chat.on('error', (data) => {
  console.error(`[${data.type}]`, data.error);
});

Localization

Override default UI strings by passing a locale object. All fields are optional — only the ones you provide will be overridden:
const chat = new CevroMessenger({
  // ... config
  locale: {
    headerTitle: 'Support Chat',
    headerSubtitle: 'We usually reply within minutes',
    inputPlaceholder: 'Type your message...',
    closedMessage: 'This conversation has ended',
    newConversation: 'Start New Chat',
    csatTitle: 'How was your experience?',
    poweredBy: 'Powered by Cevro AI',
  }
});

Available Locale Keys

KeyDefault
headerTitle'Cevro'
headerSubtitle'We typically reply within a few minutes'
inputPlaceholder'How can we help?'
preChatTitle'Start a conversation'
preChatSubtitle'Please provide your contact information to get started.'
preChatFirstNameLabel'First name'
preChatFirstNamePlaceholder'Your first name'
preChatEmailLabel'Email'
preChatEmailPlaceholder'[email protected]'
preChatSubmit'Start Chat'
preChatFirstNameRequired'First name is required'
preChatEmailRequired'Email is required'
preChatEmailInvalid'Please enter a valid email'
closedMessage'The agent closed the chat.'
newConversation'Start New Conversation'
csatTitle'How was your conversation?'
csatSubtitle'Your feedback helps us get better.'
csatPlaceholder'Thank you! What stood out?'
csatSubmit'Submit Feedback'
csatThankYou'Thank you for your feedback!'
poweredBy'Powered by Cevro AI'
Localization strings configured in the admin dashboard take priority over SDK settings.

File Uploads

Players can upload files directly in the chat:
  • Max file size: 25MB
  • Allowed: Images, documents, audio, video, archives
  • Blocked: Executables (.exe, .dll, .js, .php, etc.)
  • Rate limit: 5 uploads per minute

Escalation to Human Agents

When the AI cannot resolve an issue or the player requests human help, the conversation is escalated to your configured helpdesk system.

Supported Escalation Targets

LiveChat

Conversations transfer to your LiveChat operators. Players continue chatting in the widget while agents respond from LiveChat dashboard.

Intercom

Conversations transfer to your Intercom team. Players continue chatting in the widget while agents respond from Intercom inbox.

Zendesk

Conversations transfer to your Zendesk Agent Workspace via Sunshine Conversations. Players continue chatting in the widget while agents respond from Zendesk.

Built-in Help Desk

No external helpdesk? No problem. Escalated conversations appear in the Cevro inbox. Your team replies directly from the dashboard.

How Escalation Works

With LiveChat, Intercom, or Zendesk configured:
  1. AI determines escalation is needed (or player requests it)
  2. Conversation is created in your helpdesk
  3. Human agent receives the full conversation context
  4. Messages sync bidirectionally:
    • Player messages from widget → Helpdesk
    • Agent responses from helpdesk → Widget
Zendesk requirement: If you use Zendesk as your escalation target, you must enable Multi-Conversation in your Zendesk account. Without this, escalations will fail after the first conversation per player.To enable: go to Admin Center → Channels → Messaging → Manage settings → Multi-conversations → Turn on.
Without an external helpdesk:
  1. AI determines escalation is needed (or player requests it)
  2. Conversation appears in the Cevro inbox with escalation status
  3. Your team member opens the ticket and replies directly
  4. Reply is delivered to the player’s widget in real-time
The player never leaves your website. Whether your team responds from an external helpdesk or directly from the Cevro inbox, the player continues chatting in the widget seamlessly.

Admin Settings

Configure widget appearance and security in Settings → Cevro.

Appearance

Manage the complete visual appearance of your widget from the dashboard — no code changes needed.
SettingPurpose
Primary ColorSet the main brand color. All accent elements (launcher, send button, user messages, links) derive from it.
Full ThemeOverride any individual color for every widget element: backgrounds, text, messages, header, input, launcher, buttons.
Reset to PrimaryClear all custom theme overrides and go back to a clean look derived from just the primary color.
Bubble IconCustom icon for the launcher button
Custom LogoBrand logo displayed in the chat header
Auto-openAutomatically open the chat window on page load
CSAT SurveyEnable/disable the satisfaction survey after conversations end
Start by setting just the Primary Color — the widget will look polished out of the box. Fine-tune individual colors later if needed, or reset everything back to the primary color at any time.

Security

SettingPurpose
HMAC VerificationRequire player identity verification
HMAC SecretKey for generating playerHash (server-side)
Allowed DomainsWhitelist domains that can embed the widget

HMAC Setup

1

Generate HMAC Secret

In Settings → Cevro, click Generate to create an HMAC secret key. Copy it immediately — it’s only shown once.
2

Store Securely

Save the secret on your backend server. Never expose it to frontend code or commit it to version control.
3

Generate Hash Server-Side

Create the player hash on your server:
// Node.js example
const crypto = require('crypto');

function generatePlayerHash(playerId, hmacSecret) {
  return crypto
    .createHmac('sha256', hmacSecret)
    .update(playerId)
    .digest('hex');
}
4

Pass to Widget

Include the hash in player.playerHash when initializing the widget.
Regenerating the HMAC key invalidates all existing playerHash values.
Automatic authentication: When HMAC verification is enabled and you toggle on Require Identity Verification in Settings → Cevro, players are automatically authenticated — no security questions needed.How it works:
  • Player identified before first message — Authentication happens instantly at session start. The AI skips verification and goes straight to handling the request.
  • Player identifies mid-conversation (e.g., logs in after starting chat) — The AI detects the identity automatically and authenticates without asking manual questions.
Make sure to pass all the data your tools need in customAttributes (e.g., playerId, username) so the AI can query your back-office immediately after authentication.

Allowed Domains

Restrict which websites can embed your widget:
  • example.com — Specific domain
  • *.example.com — All subdomains
  • * — Any domain (not recommended for production)

Full Example

<script>
  (function(){
    window.cevroSettings = {
      workspaceId: 'ws_abc123',
      brandId: 'br_xyz789',

      alignment: 'right',
      verticalPadding: 20,
      horizontalPadding: 20,
      primaryColor: '#E91E63',

      theme: {
        headerBackgroundColor: '#1e1e2e',
        headerTextColor: '#ffffff',
        agentMessageBackgroundColor: '#f3f4f6',
        agentMessageTextColor: '#111827',
      },

      player: {
        playerId: 'player-123',
        firstName: 'John',
        email: '[email protected]',
        playerHash: 'hmac-signature'
      },

      locale: {
        headerTitle: 'Support',
        inputPlaceholder: 'How can we help?',
      },
    };

    var c = function(){c.q.push([].slice.call(arguments))};
    c.q = [];
    window.Cevro = c;
    var s = document.createElement('script');
    s.src = 'https://cdn.jsdelivr.net/npm/cevro-messenger-sdk/dist/loader/loader.js';
    s.async = true;
    document.head.appendChild(s);
  })();
</script>

<script>
  // Listen for events after SDK loads
  Cevro('on', 'message:received', function(data) {
    console.log('New message:', data.message.body);
  });

  Cevro('on', 'unread_count_change', function(data) {
    console.log('Unread:', data.count);
  });
</script>

Troubleshooting

  • Is boot() being called? Check browser console for errors.
  • Verify your domain is in the Allowed Domains list in Settings → Cevro.
  • Check that workspaceId and brandId are correct.
Add your domain to allowed origins in Settings → Cevro → Allowed Domains. The domain must match exactly (including subdomains).
  • Verify HMAC secret matches between dashboard and your server.
  • Ensure you’re generating the hash server-side, not client-side.
  • Check that the playerId matches exactly between hash generation and widget init.
  • If you regenerated the HMAC key, all old hashes are invalidated.
  • Verify workspaceId and brandId are correct.
  • Ensure the brand has automation enabled.
  • Check browser console for network errors.
  • Check file size (max 25MB).
  • Verify file type is allowed (no executables like .exe, .js, .php).
  • Rate limit: maximum 5 uploads per minute.
  • Verify LiveChat or Intercom integration is configured in Settings.
  • Check that human agents are available in the helpdesk.
  • Ensure the helpdesk integration is enabled for this brand.