How to Inject CRM Customer IDs into Genesys Cloud Web Messaging via startChat()

How to Inject CRM Customer IDs into Genesys Cloud Web Messaging via startChat()

What You Will Build

  • This tutorial demonstrates how to programmatically inject a known Customer ID from your CRM into a Genesys Cloud Web Messaging session using the startChat() method.
  • The implementation uses the Genesys Cloud Web Messaging SDK (@genesys-cloud/messaging-widget) and the underlying PureCloudPlatformClientV2 logic to ensure the ID persists through the conversation lifecycle.
  • The code is written in TypeScript/JavaScript, targeting a modern web application environment.

Prerequisites

  • OAuth Client Type: A Genesys Cloud OAuth client with the webchat capability enabled.
  • Required Scopes: webchat:start, webchat:send, webchat:receive.
  • SDK Version: @genesys-cloud/messaging-widget v4.0.0 or later.
  • Runtime Requirements: A modern browser supporting ES6+ modules or a bundler setup (Webpack/Vite) for TypeScript.
  • External Dependencies:
    • @genesys-cloud/messaging-widget
    • @genesys-cloud/communication-ui (optional, if using the full UI kit)

Authentication Setup

Web Messaging does not use standard OAuth2 token flows for the end-user session. Instead, it relies on a Session Token obtained via the Genesys Cloud Web Chat API. The SDK handles the exchange of your OAuth client credentials for this session token internally, but you must configure the client correctly.

You must initialize the widget with your organizationId, region, and oauthClientId.

import { MessagingWidget } from '@genesys-cloud/messaging-widget';

const GENESYS_CONFIG = {
  organizationId: 'your-org-id-here',
  region: 'us-east-1', // e.g., us-east-1, eu-west-1
  oauthClientId: 'your-oauth-client-id-here',
  language: 'en-US',
};

// Initialize the widget instance
const widget = new MessagingWidget(GENESYS_CONFIG);

// Wait for the widget to be ready before invoking methods
widget.on('ready', () => {
  console.log('Messaging Widget is ready.');
});

Implementation

Step 1: Understanding the startChat Payload Structure

The startChat() method accepts a configuration object. To pass custom data that survives the initial connection and is available to routing rules or post-engagement analytics, you must use the customAttributes field. However, to ensure the CRM ID is treated as a primary identifier for the user, you should also leverage the user object within the payload.

Genesys Cloud distinguishes between:

  1. customAttributes: Key-value pairs available for routing and scripting.
  2. user: Identity information. While Web Chat is anonymous by default, you can map a CRM ID here to link the session to a known identity in the Genesys Cloud dashboard and APIs.

Critical Constraint: You cannot pass PII (Personally Identifiable Information) like names or emails in the user object unless you have explicitly configured your organization to allow PII in web chat and have the necessary consent flows. Passing a non-PII UUID (Customer ID) is generally safe and recommended.

Step 2: Constructing the Start Chat Request

Below is the TypeScript interface for the payload we will construct. Note the use of customAttributes for routing logic and the user object for identity linkage.

interface StartChatPayload {
  customAttributes?: Record<string, string>;
  user?: {
    id?: string;
    name?: string; // Only if PII is allowed and consented
  };
  // Other optional fields like 'language', 'topic' etc.
}

To pass the CRM ID, we will use a specific key in customAttributes (e.g., crmCustomerId) so that Genesys Cloud routing rules can inspect it. We will also set the user.id if your organization policy allows mapping external IDs to the web chat user object.

async function initiateChatWithCrmId(crmCustomerId: string): Promise<void> {
  if (!widget.isReady()) {
    throw new Error('Messaging Widget is not yet ready.');
  }

  const payload: StartChatPayload = {
    customAttributes: {
      // Use a clear key name. This will be available in routing rules and the conversation object.
      'crmCustomerId': crmCustomerId,
      'source': 'web-portal',
    },
    // Optional: Link the external ID to the Genesys Cloud user identity
    // Note: This requires 'webchat:manage' scope on the server side if you are doing this via API,
    // but via SDK, it depends on org settings.
    user: {
      id: crmCustomerId, 
    }
  };

  try {
    // Invoke the startChat method
    await widget.startChat(payload);
    console.log('Chat started with CRM ID:', crmCustomerId);
  } catch (error) {
    console.error('Failed to start chat:', error);
    throw error;
  }
}

Step 3: Verifying Data Persistence via the Conversations API

To confirm that the CRM ID was successfully passed and is attached to the conversation, you must query the Genesys Cloud Conversations API. This step is crucial for debugging routing issues where the ID might not be reaching the agent.

You need an OAuth token generated from a Genesys Cloud Application User (with conversation:view scope) to make this API call. This is typically done in a backend service, not in the browser, to protect the OAuth secret.

Endpoint: POST /api/v2/conversations/details/query

Request Body:

{
  "size": 5,
  "query": "type:webchat status:active",
  "orderBy": "startTime",
  "orderDir": "desc"
}

Response Analysis:
Look at the conversations array in the response. Inside the participants array, find the participant with type: "customer". The customAttributes object should contain your crmCustomerId.

Step 4: Handling Routing Rules Based on CRM ID

Passing the ID is only half the battle. The value of passing a CRM ID is usually to route high-value customers to premium agents. You must ensure your Genesys Cloud Routing Rule inspects the customAttributes.crmCustomerId.

In the Genesys Cloud Admin Console, create a Routing Rule:

  1. Condition: Custom Attribute exists crmCustomerId.
  2. Action: Route to Queue Premium Support.

If you are testing this via API, you can simulate this by checking the customAttributes in the conversation object returned by the API in Step 3.

Complete Working Example

Below is a complete, self-contained TypeScript module that initializes the widget, waits for readiness, and starts a chat with a CRM ID. It includes error handling and type definitions.

import { MessagingWidget, WidgetConfig } from '@genesys-cloud/messaging-widget';

// Configuration Interface
interface AppConfig {
  organizationId: string;
  region: string;
  oauthClientId: string;
}

// CRM Customer Data Interface
interface CrmCustomerData {
  id: string;
  tier?: 'premium' | 'standard';
}

class WebChatManager {
  private widget: MessagingWidget;
  private isReady: boolean = false;
  private resolveReady: () => void;
  private readyPromise: Promise<void>;

  constructor(config: AppConfig) {
    this.widget = new MessagingWidget({
      organizationId: config.organizationId,
      region: config.region,
      oauthClientId: config.oauthClientId,
      language: 'en-US',
      // Optional: Configure UI theme
      theme: {
        primaryColor: '#007bff',
      },
    });

    // Setup readiness promise
    this.readyPromise = new Promise((resolve) => {
      this.resolveReady = resolve;
    });

    // Listen for ready event
    this.widget.on('ready', () => {
      this.isReady = true;
      this.resolveReady();
    });

    // Listen for errors
    this.widget.on('error', (error: any) => {
      console.error('Messaging Widget Error:', error);
    });
  }

  /**
   * Waits for the widget to be fully initialized.
   */
  async waitForReady(): Promise<void> {
    return this.readyPromise;
  }

  /**
   * Starts a chat session and injects CRM customer ID.
   * 
   * @param customer - The CRM customer data object.
   */
  async startChatWithCrmContext(customer: CrmCustomerData): Promise<void> {
    if (!this.isReady) {
      await this.waitForReady();
    }

    if (!this.widget.isReady()) {
      throw new Error('Widget failed to initialize within timeout.');
    }

    const customAttributes: Record<string, string> = {
      'crmCustomerId': customer.id,
    };

    // Add tier if available for routing logic
    if (customer.tier) {
      customAttributes['customerTier'] = customer.tier;
    }

    const chatConfig = {
      customAttributes: customAttributes,
      user: {
        id: customer.id,
      },
    };

    try {
      await this.widget.startChat(chatConfig);
      console.log(`Successfully started chat for customer ${customer.id}`);
    } catch (error) {
      console.error('Failed to start chat:', error);
      throw new Error('Chat initiation failed. Check network or OAuth configuration.');
    }
  }

  /**
   * Destroys the widget instance to clean up resources.
   */
  destroy(): void {
    this.widget.destroy();
  }
}

// Usage Example
async function main() {
  const appConfig: AppConfig = {
    organizationId: 'your-org-id',
    region: 'us-east-1',
    oauthClientId: 'your-client-id',
  };

  const chatManager = new WebChatManager(appConfig);

  try {
    await chatManager.waitForReady();
    
    const mockCustomer: CrmCustomerData = {
      id: 'CRM-12345-XYZ',
      tier: 'premium',
    };

    await chatManager.startChatWithCrmContext(mockCustomer);
  } catch (error) {
    console.error('Initialization or Chat Start Failed:', error);
  }
}

// Run the example if executed directly
if (typeof window !== 'undefined') {
  main();
}

Common Errors & Debugging

Error: 401 Unauthorized

  • Cause: The oauthClientId provided in the widget configuration is invalid, disabled, or lacks the webchat:start scope.
  • Fix: Verify the OAuth Client ID in the Genesys Cloud Admin Console. Ensure the client is active and the redirect URIs are correctly configured if you are using implicit flow (though the SDK handles this internally).
  • Debugging: Check the browser network tab for the initial token request. Look for a 401 response from login.mypurecloud.com.

Error: 403 Forbidden

  • Cause: The organization ID is incorrect, or the organization has disabled Web Messaging for this client.
  • Fix: Confirm the organizationId matches the ID of the Genesys Cloud organization. Ensure Web Messaging is enabled in the Admin Console under Admin > Messaging > Web Messaging.

Error: Custom Attributes Not Visible in Routing

  • Cause: The customAttributes object was not passed correctly, or the routing rule is looking for the wrong key.
  • Fix: Ensure the key in the SDK payload (crmCustomerId) exactly matches the key in the Routing Rule condition. Note that keys are case-sensitive.
  • Debugging: Use the Conversations API (GET /api/v2/conversations/{conversationId}) to inspect the active conversation. Check the participants array for the customer. The customAttributes field should be populated.

Error: Widget Not Ready Timeout

  • Cause: The widget failed to load due to network issues or ad blockers blocking the Genesys Cloud CDN.
  • Fix: Ensure the browser can access *.mypurecloud.com and *.genesys.cloud. Check for console errors related to CORS or blocked resources.
  • Debugging: Add a timeout to the waitForReady promise in production code to fail gracefully.

Official References