CORS 403 when initializing GC Web Messaging SDK in Next.js SSR context

Running into a wall trying to embed the Genesys Cloud Web Messaging SDK into our React Next.js app. The setup works fine on static pages, but as soon as I hit a route that uses Server-Side Rendering, the browser console throws a CORS error when the widget tries to fetch the initial configuration.

Here’s the error I’m seeing:

Access to fetch at 'https://webchat-eu-west-1.genesiscloud.com/v2/config' from origin 'https://myapp.dev' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

The status code is 403 Forbidden. I’ve checked the network tab and the request headers look standard, including the Authorization Bearer token which is generated server-side via our Kotlin backend. The token is valid if I test it with Postman, so it’s not an auth issue per se, more of a transport layer block.

I’m initializing the SDK in a custom hook like this:

const initMessenger = async () => {
 const token = await getAuthToken();
 const widget = new Webchat({
 deploymentId: process.env.NEXT_PUBLIC_GC_DEPLOYMENT_ID,
 oauthToken: token,
 // ... other config
 });
 widget.start();
};

The issue seems to be that Next.js is trying to resolve the process.env variable or the new Webchat() call during the server render phase, which triggers the fetch before the browser environment is fully established or before the correct CORS headers are attached by the client-side runtime. I’ve tried moving the initialization to useEffect with an empty dependency array, but the error persists on the first load.

Has anyone managed to get the Webchat class to play nice with Next.js App Router? I’m wondering if I need to proxy the request through our own backend to avoid the cross-origin issue entirely, or if there’s a specific config flag I’m missing. The docs don’t mention SSR compatibility explicitly.

The issue isn’t really CORS on the Genesys side. It’s Next.js trying to execute the SDK client-side logic during server-side rendering (SSR). The fetch for /v2/config happens in the browser, but Next.js might be intercepting or failing to hydrate the component correctly, leading to that origin mismatch error.

I’ve seen this before with other web widgets. The fix is to ensure the SDK only initializes on the client. You can’t just import it at the top of a server component.

Try wrapping the initialization in a useEffect hook and checking for typeof window !== 'undefined'. Here is a pattern that works for us in React:

import { useEffect, useRef } from 'react';
import { WebChatClient } from '@genesyscloud/webchat-widget-sdk';

export default function ChatWidget({ deploymentId, region }) {
 const clientRef = useRef(null);

 useEffect(() => {
 // Ensure this runs only on the client
 if (typeof window !== 'undefined' && !clientRef.current) {
 const config = {
 deploymentId: deploymentId,
 region: region,
 // Add any other config here
 };
 
 try {
 clientRef.current = new WebChatClient(config);
 clientRef.current.init();
 } catch (error) {
 console.error("Failed to init GC chat:", error);
 }
 }
 }, [deploymentId, region]);

 return null; // Or render your UI trigger here
}

Make sure you aren’t importing WebChatClient at the module level in a file that gets bundled for the server. If you do, Next.js will try to run it on the server, fail, and then the client-side fetch behaves weirdly.

Also double check your next.config.js. Sometimes adding the Genesys endpoints to rewrites or headers helps if you are proxying, but usually just keeping it client-side is enough.