CORS error when embedding NICE CXone Messenger in Next.js

Trying to drop the CXone Messenger widget into a Next.js app. Getting a CORS error on the initial handshake. The script loads, but the WebSocket connection to wss://api.nice.incontact.com fails with Access-Control-Allow-Origin missing. I’ve tried adding headers in next.config.js, but the browser blocks the request before it hits the server. Has anyone got this working with SSR?

// next.config.js
const nextConfig = {
async rewrites() {
return [
{
source: ‘/api/nice-cxone/:path*’,
destination: ‘https://api.nice.incontact.com/:path*’,
},
];
},
};

module.exports = nextConfig;


You're fighting the browser, not the server. That CORS header is missing because the NICE CXone endpoint isn't configured to accept your Next.js domain as a valid origin for direct browser requests. It's a security feature, not a bug. You can't fix this by adding headers in `next.config.js` because those headers only apply to requests your server makes, not the WebSocket handshake the client initiates.

The trick is to proxy the connection through your own domain. By setting up a rewrite rule in Next.js, you mask the actual destination. The browser sees it talking to `yourdomain.com/api/nice-cxone`, which is same-origin and bypasses the CORS check entirely. Your server then forwards that request to the actual NICE endpoint.

Make sure you update the Messenger initialization script to point to this new proxy path instead of the raw `api.nice.incontact.com` URL. Something like:

```javascript
// In your component or layout
<script>
 window.niceCXoneMessenger = {
 endpoint: '/api/nice-cxone/messenger', // Use the proxy path
 // other config...
 };
</script>

This approach works well for SSR because the server handles the forwarding logic cleanly. Just be aware that if NICE changes their WebSocket endpoint structure, you’ll need to adjust the rewrite pattern. It’s a bit of extra setup, but it saves you from fighting CORS policies that you can’t control.

Also, double-check that your proxy isn’t stripping any necessary headers from the initial HTTP handshake before it upgrades to WSS. Sometimes Next.js rewrites can be picky about that. If you hit a 101 Switching Protocols error, that’s usually the culprit.