Skip to main content

Widget Configuration

Complete reference for all widget configuration options, methods, and custom events.


Quick Reference

PocketPing.init({
// Required (choose one)
projectId: 'proj_xxx', // SaaS
// endpoint: 'https://...', // Self-hosted

// Appearance
operatorName: 'Support',
operatorAvatar: 'https://...',
primaryColor: '#6366f1',
theme: 'auto',
position: 'bottom-right',

// Behavior
welcomeMessage: 'Hi! How can we help?',
placeholder: 'Type a message...',
soundEnabled: true,

// Page visibility
showOnPages: ['*'],
hideOnPages: ['/admin/*'],

// Callbacks
onOpen: () => {},
onClose: () => {},
onMessage: (msg) => {},
onSessionStart: (session) => {},
});

Connection Options

Choose ONE of these options:

OptionTypeDescription
projectIdstringYour project ID from app.pocketping.io dashboard
endpointstringYour self-hosted bridge server URL
// SaaS (recommended for most users)
PocketPing.init({
projectId: 'proj_xxxxxxxxxxxxx',
});

// Self-hosted
PocketPing.init({
endpoint: 'https://yoursite.com/pocketping',
});
Don't mix

Using both projectId and endpoint together will cause unexpected behavior. Choose one.


Appearance Options

Customize how the widget looks.

Visual Reference

┌─────────────────────────────────────────────────────────────────┐
│ WIDGET ANATOMY │
│ │
│ ┌───────────────────────────┐ │
│ │ [Avatar] Operator Name │ ◄── operatorName, operatorAvatar│
│ │ ─────────────────────────│ │
│ │ │ │
│ │ Welcome message appears │ ◄── welcomeMessage │
│ │ here when chat opens │ │
│ │ │ │
│ │ ─────────────────────────│ │
│ │ [Type a message...] │ ◄── placeholder │
│ │ [Send] │ ◄── primaryColor applied here │
│ └───────────────────────────┘ │
│ │
│ Position: bottom-right ──────────────► or ◄── bottom-left │
│ │
└─────────────────────────────────────────────────────────────────┘

Options

OptionTypeDefaultDescription
operatorNamestring"Support"Display name in widget header
operatorAvatarstring-URL to avatar image (square, min 64x64)
primaryColorstring"#6366f1"Brand color (buttons, links, accents)
themestring"auto"Color scheme: "light", "dark", or "auto"
positionstring"bottom-right"Screen position: "bottom-right" or "bottom-left"

Examples

Custom branding:

PocketPing.init({
projectId: 'proj_xxx',
operatorName: 'Sarah from Acme',
operatorAvatar: 'https://yoursite.com/sarah.jpg',
primaryColor: '#10b981', // Emerald green
theme: 'light',
position: 'bottom-left',
});

Match system theme:

PocketPing.init({
projectId: 'proj_xxx',
theme: 'auto', // Follows user's OS dark/light preference
});

Behavior Options

Control how the widget behaves.

OptionTypeDefaultDescription
welcomeMessagestring-Message shown when chat first opens
placeholderstring"Type a message..."Input field placeholder text
soundEnabledbooleantruePlay sound on incoming messages
showOnPagesstring[]["*"]URL patterns where widget appears
hideOnPagesstring[][]URL patterns where widget is hidden

Welcome Messages

// Simple welcome
PocketPing.init({
projectId: 'proj_xxx',
welcomeMessage: 'Hi! How can we help you today?',
});

// No auto-message (visitor speaks first)
PocketPing.init({
projectId: 'proj_xxx',
// welcomeMessage not set = no auto-message
});

Page Visibility

Control where the widget appears:

PocketPing.init({
projectId: 'proj_xxx',

// Show everywhere except admin and checkout
showOnPages: ['*'],
hideOnPages: ['/admin/*', '/checkout', '/checkout/*'],
});
PocketPing.init({
projectId: 'proj_xxx',

// Only show on specific pages
showOnPages: ['/pricing', '/contact', '/support/*'],
hideOnPages: [],
});

Pattern matching:

PatternMatches
*All pages
/pricingExactly /pricing
/docs/*/docs/, /docs/intro, /docs/guides/setup
/blog/*/blog/, /blog/post-1, /blog/2024/article

Callback Options

React to widget events in your code.

OptionTypeDescription
onOpen() => voidCalled when widget opens
onClose() => voidCalled when widget closes
onMessage(msg: Message) => voidCalled on any message (sent or received)
onSessionStart(session: Session) => voidCalled when a new session is created

Example: Analytics Integration

PocketPing.init({
projectId: 'proj_xxx',

onOpen: () => {
// Track in Google Analytics
gtag('event', 'chat_opened', { event_category: 'engagement' });

// Track in Mixpanel
mixpanel.track('Chat Opened');
},

onClose: () => {
gtag('event', 'chat_closed', { event_category: 'engagement' });
},

onMessage: (message) => {
// Log all messages for debugging
console.log('Message:', message.content, 'Direction:', message.direction);

// Track message count
gtag('event', 'chat_message', {
event_category: 'engagement',
direction: message.direction, // 'inbound' or 'outbound'
});
},

onSessionStart: (session) => {
// Store session ID for support reference
console.log('Session started:', session.id);

// Identify session in your analytics
mixpanel.identify(session.visitorId);
},
});

Message Object

interface Message {
id: string;
content: string;
direction: 'inbound' | 'outbound'; // inbound = from visitor, outbound = from you
timestamp: string;
sender: {
name: string;
type: 'visitor' | 'operator' | 'ai';
};
}

Methods

After initialization, control the widget programmatically.

Basic Controls

// Open the chat widget
PocketPing.open();

// Close the chat widget
PocketPing.close();

// Toggle open/closed
PocketPing.toggle();

Dynamic Configuration

// Update settings at runtime
PocketPing.setConfig({
primaryColor: '#ef4444', // Change to red
operatorName: 'Emergency Support',
});

Visitor Identification

Associate visitor with your user data so operators can see who they're talking to:

// After user logs in
PocketPing.identify({
id: 'user_12345', // Required - unique user identifier
email: '[email protected]',
name: 'John Doe',
// Any custom properties
plan: 'pro',
company: 'Acme Inc',
signupDate: '2024-01-15',
});

Required field: id must be a non-empty string (typically your user's database ID).

Identity is persisted in localStorage and automatically sent on reconnection, so users stay identified across page refreshes.

This data appears in your messaging platform (Telegram/Discord/Slack):

┌──────────────────────────────────────────────────────┐
│ 🆕 New conversation │
│ │
│ 👤 John Doe │
│ 📧 [email protected]
│ 📋 plan: pro • company: Acme Inc │
├──────────────────────────────────────────────────────┤
│ "I need help with the API integration" │
└──────────────────────────────────────────────────────┘

Reset Identity

Clear identity on logout and optionally start a fresh session:

// Clear identity only (keep session)
await PocketPing.reset();

// Clear identity AND start new session (recommended on logout)
await PocketPing.reset({ newSession: true });

Get Current Identity

const identity = PocketPing.getIdentity();
// Returns: { id: 'user_12345', email: '...', name: '...' } or null

Cleanup

// Completely remove the widget from the page
PocketPing.destroy();

// Widget can be re-initialized after destroy
PocketPing.init({ projectId: 'proj_xxx' });

Custom Events

This is PocketPing's most powerful feature. Custom events enable bidirectional communication between your widget and backend.

Overview

┌─────────────────────────────────────────────────────────────────┐
│ CUSTOM EVENTS │
│ │
│ Widget Backend │
│ ┌───────────────┐ ┌───────────────┐ │
│ │ │ │ │ │
│ │ trigger() │ ─────────────────────► │ onEvent() │ │
│ │ │ "clicked_pricing" │ │ │
│ │ │ { plan: 'pro' } │ │ │
│ │ │ │ │ │
│ │ onEvent() │ ◄───────────────────── │ emitEvent() │ │
│ │ │ "show_discount" │ │ │
│ │ │ { percent: 20 } │ │ │
│ └───────────────┘ └───────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘

Sending Events (Widget → Backend)

Use trigger() to send events to your backend:

// Track pricing page interactions
document.querySelector('#pricing-button').addEventListener('click', () => {
PocketPing.trigger('clicked_pricing', {
plan: 'pro',
price: 49,
source: 'homepage',
});
});

// Track form submissions
document.querySelector('#signup-form').addEventListener('submit', () => {
PocketPing.trigger('form_submitted', {
formType: 'signup',
fields: ['email', 'name'],
});
});

// Track page views
PocketPing.trigger('page_viewed', {
page: window.location.pathname,
referrer: document.referrer,
});

Your backend receives these events via the SDK's onEvent handler.

Listening to Events (Backend → Widget)

Use onEvent() to react to events from your backend:

// Show a discount popup
PocketPing.onEvent('show_discount', (data) => {
showPopup({
title: 'Special Offer!',
message: `Get ${data.percent}% off with code: ${data.code}`,
});
});

// Highlight a feature
PocketPing.onEvent('highlight_feature', (data) => {
document.querySelector(`#${data.featureId}`).classList.add('highlight');
});

// Open chat with a message
PocketPing.onEvent('open_chat', (data) => {
PocketPing.open();
if (data.message) {
showSystemMessage(data.message);
}
});

Unsubscribing

// Store the unsubscribe function
const unsubscribe = PocketPing.onEvent('some_event', (data) => {
// Handle event
});

// Later, stop listening
unsubscribe();

Use Cases

ScenarioDirectionEventData
Track pricing clicksWidget → Backendclicked_pricing{ plan, price }
Track form submissionsWidget → Backendform_submitted{ formType, fields }
Track feature usageWidget → Backendused_feature{ featureId }
Show discount offerBackend → Widgetshow_discount{ percent, code }
Highlight UI elementBackend → Widgethighlight{ selector }
Open chat with contextBackend → Widgetopen_chat{ message }
Request form fillBackend → Widgetrequest_info{ fields }

Full Example: Lead Scoring

Widget (track behavior):

// Track high-intent actions
PocketPing.trigger('viewed_pricing');
PocketPing.trigger('started_trial');
PocketPing.trigger('invited_team_member');

// Track engagement
PocketPing.trigger('time_on_page', { seconds: 120 });

Backend (respond based on score):

// In your backend SDK
const pp = new PocketPing({
onEvent: async (event, session) => {
// Calculate lead score
const score = await calculateLeadScore(session.visitorId, event);

// High-intent visitor? Show offer
if (score > 80) {
await pp.emitEvent(session.id, 'show_discount', {
percent: 20,
code: 'HIGHINTENT20',
expires: '24h',
});
}
},
});

Complete Example

PocketPing.init({
// Connection
projectId: 'proj_xxxxxxxxxxxxx',

// Appearance
operatorName: 'Acme Support',
operatorAvatar: 'https://acme.com/support-avatar.png',
primaryColor: '#0ea5e9',
theme: 'auto',
position: 'bottom-right',

// Behavior
welcomeMessage: 'Hi! How can we help you today?',
placeholder: 'Ask us anything...',
soundEnabled: true,
showOnPages: ['*'],
hideOnPages: ['/admin/*', '/checkout'],

// Analytics integration
onOpen: () => {
gtag('event', 'chat_opened');
},

onMessage: (message) => {
if (message.direction === 'inbound') {
gtag('event', 'message_sent');
}
},

onSessionStart: (session) => {
// Identify in Mixpanel
mixpanel.identify(session.visitorId);
mixpanel.people.set({ has_chatted: true });
},
});

// Identify logged-in users
if (window.currentUser) {
PocketPing.identify({
email: window.currentUser.email,
name: window.currentUser.name,
plan: window.currentUser.plan,
});
}

// Track pricing interest
document.querySelector('#pricing-cta')?.addEventListener('click', () => {
PocketPing.trigger('clicked_pricing', { source: 'homepage' });
});

// Listen for backend events
PocketPing.onEvent('show_offer', (data) => {
showOfferBanner(data);
});

Next Steps