CORS Preflight Fail on Messenger Widget Embed in Next.js App Router

Running into a wall with the Web Messaging SDK. Trying to embed the NICE CXone Messenger widget into a Next.js 14 app using the App Router. The widget loads fine in development mode, but as soon as I build for production and hit the deployed Vercel edge, the initial handshake fails.

The browser console throws a CORS error on the OPTIONS preflight request to https://api.niceincontact.com/api/v2/... (specifically the session creation endpoint). The response is a 403 Forbidden. It seems like the browser is blocking the request before the actual POST even happens.

Here is the setup in the layout.tsx file:

'use client';
import { useEffect } from 'react';

export default function RootLayout({ children }: { children: React.ReactNode }) {
 useEffect(() => {
 const script = document.createElement('script');
 script.src = 'https://assets.nicecxone.com/messenger/sdk/1.0.0/nice-messenger.js';
 script.async = true;
 script.onload = () => {
 // Initialize widget
 window.NiceMessenger.init({
 orgId: 'my-org-id',
 queueId: 'my-queue-id',
 locale: 'en-US'
 });
 };
 document.head.appendChild(script);
 }, []);

 return (
 <html lang="en">
 <body>{children}</body>
 </html>
 );
}

I’ve checked the next.config.js to ensure the asset domains are allowed, but that shouldn’t affect the API calls made by the widget script itself. The widget code runs in the browser, so it’s hitting the NICE APIs directly.

I tried adding a next.config.js rewrites rule to proxy the API calls to our own backend to avoid CORS, but the SDK doesn’t seem to have a configuration option to override the base API URL. It hardcodes the api.niceincontact.com domain.

Is there a known issue with the SDK and modern React frameworks? Or is there a specific header I need to send from the client side that the SDK isn’t handling? The error log shows the request origin is https://my-app.vercel.app, but the preflight isn’t getting the Access-Control-Allow-Origin header back.

Looking for a workaround or a fix in the SDK config. Don’t want to rewrite the whole widget integration.