Fixing CORS Errors When Embedding the Genesys Cloud Messenger Widget in Next.js
What You Will Build
- You will implement a server-side rendered Next.js application that successfully loads the Genesys Cloud Messenger widget without triggering browser Cross-Origin Resource Sharing (CORS) or Mixed Content errors.
- This tutorial uses the Genesys Cloud Messenger SDK (
@gencloud/messenger) and the Next.js App Router or Pages Router. - The code examples are written in TypeScript using the Next.js framework.
Prerequisites
- OAuth Client: A Genesys Cloud OAuth client configured with
web_servergrant type. While the widget itself uses a different authentication flow (widget credentials), your backend may need to interact with the API for user context. - Widget Configuration: An active Genesys Cloud Messenger widget ID and Widget Key.
- Next.js Version: Next.js 13+ (App Router) or Next.js 12+ (Pages Router).
- Dependencies:
@gencloud/messenger: The official Genesys Cloud Messenger SDK.react: React 18+.typescript: For type safety.
Authentication Setup
The Genesys Cloud Messenger widget does not use standard OAuth 2.0 bearer tokens for the client-side UI. Instead, it uses a Widget Key and Widget ID to establish a secure WebSocket connection to the Genesys Cloud infrastructure. However, if you are passing user identity (e.g., email, name) to pre-fill the conversation, you must ensure that data is fetched securely on the server side to avoid exposing secrets in the client bundle.
For this tutorial, we assume the Widget ID and Key are stored in environment variables:
NEXT_PUBLIC_GENESYS_WIDGET_IDNEXT_PUBLIC_GENESYS_WIDGET_KEY
Note: The NEXT_PUBLIC_ prefix exposes these variables to the browser. This is required for the widget to function but ensures that no private API secrets are leaked.
Implementation
Step 1: Install the Messenger SDK
Install the official Genesys Cloud Messenger package. This package provides the React component and the underlying configuration logic.
npm install @gencloud/messenger
# or
yarn add @gencloud/messenger
Step 2: Configure the Next.js Middleware or Server Handler
CORS errors in Next.js often stem from how the server handles preflight requests (OPTIONS) or how static assets are served. However, the most common cause of “CORS” errors with the Messenger widget is actually Mixed Content or Origin Mismatch when the widget tries to connect to *.mypurecloud.com from a local development server (localhost:3000) or a custom domain.
Genesys Cloud allows specific origins for the widget. You must ensure your development and production domains are whitelisted in the Genesys Cloud Admin Console under Admin > Channels > Messaging > Widget Settings.
If you are developing locally, localhost:3000 must be added to the allowed origins.
Step 3: Create the Messenger Wrapper Component
Directly importing the Genesys Cloud widget script in a React component can cause hydration mismatches because the widget manipulates the DOM directly. We must wrap the initialization in a useEffect hook to ensure it only runs on the client side.
Create a file named components/GenesysMessenger.tsx.
'use client';
import { useEffect, useRef } from 'react';
import { Messenger } from '@gencloud/messenger';
interface GenesysMessengerProps {
widgetId: string;
widgetKey: string;
environment?: 'prod' | 'qa' | 'dev';
userId?: string;
userEmail?: string;
userName?: string;
}
export const GenesysMessenger: React.FC<GenesysMessengerProps> = ({
widgetId,
widgetKey,
environment = 'prod',
userId,
userEmail,
userName,
}) => {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
// Check if we are in the browser environment
if (typeof window === 'undefined') return;
// Determine the base URL based on the environment
const baseUrl =
environment === 'prod'
? 'https://api.mypurecloud.com'
: environment === 'qa'
? 'https://api.qa.pure.cloud'
: 'https://api.dev.pure.cloud';
// Initialize the Messenger
const messenger = new Messenger({
widgetId,
widgetKey,
environment: environment as 'prod' | 'qa' | 'dev',
locale: 'en-US',
});
// Optional: Set user identity for pre-filled conversations
if (userId || userEmail || userName) {
messenger.setUserIdentity({
userId: userId || '',
email: userEmail || '',
name: userName || '',
});
}
// Mount the widget to the container
// The SDK handles the iframe creation and WebSocket connection
messenger.mount(containerRef.current);
// Cleanup on unmount
return () => {
messenger.unmount();
};
}, [widgetId, widgetKey, environment, userId, userEmail, userName]);
// Render a container div for the widget
return <div ref={containerRef} style={{ position: 'fixed', bottom: 0, right: 0 }} />;
};
Step 4: Addressing the CORS Preflight Issue in Next.js
If you are proxying requests through your Next.js server (e.g., to fetch user data to pass to the widget), you must handle CORS headers correctly. Next.js does not automatically handle CORS for API routes.
Create middleware.ts in the root of your project to handle preflight requests globally if your frontend is served from a different domain than your backend API.
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
// Allow CORS for your specific frontend domain
const allowedOrigins = ['http://localhost:3000', 'https://your-production-domain.com'];
const origin = request.headers.get('origin') || '';
if (allowedOrigins.includes(origin)) {
const response = NextResponse.next();
response.headers.set('Access-Control-Allow-Origin', origin);
response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
return response;
}
return NextResponse.next();
}
export const config = {
matcher: '/api/:path*',
};
Step 5: Handling the “Invalid Origin” Error
The most frequent “CORS” error with the Messenger widget is not a browser CORS error, but a 403 Forbidden returned by the Genesys Cloud API because the Origin header sent by the browser is not in the allowed list in the Genesys Cloud Admin Console.
Fix:
- Log in to the Genesys Cloud Admin Console.
- Navigate to Admin > Channels > Messaging > Widget Settings.
- Select your widget.
- Scroll to Allowed Origins.
- Add
http://localhost:3000for development. - Add
https://your-production-domain.comfor production.
If you do not see this option, ensure you have the Messaging admin permissions.
Complete Working Example
Below is a complete Next.js App Router page that integrates the Messenger widget. This example assumes you have the environment variables set.
app/page.tsx
import { GenesysMessenger } from '@/components/GenesysMessenger';
export default function Home() {
// Retrieve configuration from environment variables
const widgetId = process.env.NEXT_PUBLIC_GENESYS_WIDGET_ID;
const widgetKey = process.env.NEXT_PUBLIC_GENESYS_WIDGET_KEY;
if (!widgetId || !widgetKey) {
return (
<div className="p-4 text-red-500">
Missing Genesys Cloud Widget ID or Key in environment variables.
</div>
);
}
return (
<main className="flex min-h-screen flex-col items-center justify-center p-24">
<h1 className="text-4xl font-bold mb-8">Welcome to Our Support Portal</h1>
<p className="mb-4">Click the chat icon in the bottom right corner to start a conversation.</p>
{/*
The GenesysMessenger component handles the client-side initialization.
We pass static user data here for demonstration. In a real app,
you might fetch this from a server component and pass it as props.
*/}
<GenesysMessenger
widgetId={widgetId}
widgetKey={widgetKey}
environment="prod"
userId="user-12345"
userEmail="customer@example.com"
userName="John Doe"
/>
</main>
);
}
components/GenesysMessenger.tsx (Refined for App Router)
'use client';
import { useEffect, useRef } from 'react';
import { Messenger } from '@gencloud/messenger';
interface GenesysMessengerProps {
widgetId: string;
widgetKey: string;
environment?: 'prod' | 'qa' | 'dev';
userId?: string;
userEmail?: string;
userName?: string;
}
export const GenesysMessenger: React.FC<GenesysMessengerProps> = ({
widgetId,
widgetKey,
environment = 'prod',
userId,
userEmail,
userName,
}) => {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
// Guard against server-side rendering
if (typeof window === 'undefined') return;
// Initialize the Messenger SDK
const messenger = new Messenger({
widgetId,
widgetKey,
environment: environment as 'prod' | 'qa' | 'dev',
locale: 'en-US',
});
// Set user identity if provided
if (userId || userEmail || userName) {
messenger.setUserIdentity({
userId: userId || '',
email: userEmail || '',
name: userName || '',
});
}
// Mount the widget
if (containerRef.current) {
messenger.mount(containerRef.current);
}
// Cleanup function to unmount the widget when the component unmounts
return () => {
messenger.unmount();
};
}, [widgetId, widgetKey, environment, userId, userEmail, userName]);
return (
<div
ref={containerRef}
style={{
position: 'fixed',
bottom: 0,
right: 0,
zIndex: 9999,
}}
/>
);
};
Common Errors & Debugging
Error: Access to XMLHttpRequest at 'https://api.mypurecloud.com/...' from origin 'http://localhost:3000' has been blocked by CORS policy
Cause: The browser is blocking the request because the Genesys Cloud API does not recognize http://localhost:3000 as an allowed origin for the Messenger widget.
Fix:
- Verify that
http://localhost:3000is listed in Admin > Channels > Messaging > Widget Settings > Allowed Origins in the Genesys Cloud Admin Console. - Clear your browser cache and reload the page.
Error: Mixed Content: The page at 'https://...' was loaded over HTTPS, but requested an insecure resource 'http://...'
Cause: The widget is trying to load resources over HTTP instead of HTTPS. This can happen if the environment is misconfigured or if the widgetKey is invalid.
Fix:
- Ensure the
environmentprop is set correctly (prod,qa, ordev). - Verify that the
widgetKeyis correct and has not been rotated. - Check that your Next.js application is served over HTTPS in production. Local development over HTTP is acceptable if the allowed origins include
http://localhost:3000.
Error: TypeError: messenger.mount is not a function
Cause: The @gencloud/messenger package was not installed correctly, or the import statement is incorrect.
Fix:
- Run
npm install @gencloud/messengeragain. - Ensure the import is
import { Messenger } from '@gencloud/messenger';. - Verify that the
messengerobject is instantiated before callingmount.
Error: Widget failed to load: Invalid widget ID or key
Cause: The widgetId or widgetKey is incorrect, or the widget is disabled.
Fix:
- Copy the Widget ID and Key directly from the Genesys Cloud Admin Console under Admin > Channels > Messaging > Widgets.
- Ensure the widget is Enabled in the Admin Console.
- Check for typos in the environment variables.