Solving Sanity Studio CORS errors with server-side architecture
- Bespoke development
- Integration
- Plugins & extensions
A client asked for something that seemed simple on a Jira ticket: every time an editor clicked the ‘Publish’ button in Sanity, we needed to log that event to an external system—specifically a Monday.com board. The goal was operational clarity through a lightweight audit trail and a shared space to see what content went live and when.
We engineered a solution by extending Sanity Studio with a custom publish action. When an editor published a document, the Studio sent a payload to a small API endpoint in our Next.js application, and that endpoint wrote the corresponding item to Monday.com. It worked. We tested it, it behaved as expected, and we moved on. However, the project then sat parked for a further 12 months.
When we returned to prepare for production, the integration started failing with a flood of CORS errors. While the business requirements remained the same, the production environment had changed—introducing a stricter cross-origin boundary than our earlier setup.
The root cause was an architectural boundary that is easy to overlook when moving quickly: Sanity Studio runs in the browser, meaning our publish logging code was making a browser-based request across domains.
While CORS provided the error message, the real failure was deeper: we had built a backend integration on a frontend foundation. This is the story of how we moved that logic to Sanity Functions to build something truly production-ready.
Understanding CORS and cross-origin request issues in Sanity Studio
When you open a website, your browser treats that page as originating from a specific “origin” (roughly: domain + protocol + port). As a security measure, the browser does not automatically allow that page to make requests to other origins.
For example, if your Sanity Studio is hosted at https://my-project.sanity.studio and your API endpoint resides at https://my-site.com/api/log-publish, the browser identifies this as a cross-origin request.
CORS (Cross-Origin Resource Sharing) is the mechanism that allows APIs to respond with headers that essentially say: “Yes, it is okay for pages from that origin to call this API.” If the API does not explicitly grant permission, the browser blocks the request—even if the API itself would have processed it successfully.
Identifying architectural bottlenecks in client-side integrations
At first, it is tempting to treat CORS as a simple configuration issue: add the right headers, handle ‘OPTIONS’ requests, and move on. However, once I stepped back, it was clear that CORS was a symptom of a deeper architectural mismatch.
The publish logger was running inside Sanity Studio, which operates client-side. This meant the task of notifying Monday.com that something was published depended entirely on an editor’s browser successfully making a cross-domain request at the exact moment they hit ‘Publish’.
This approach introduces several fragilities:
Reliability depends on the user’s session: If the editor closes the tab, loses their connection, or a browser extension interferes, the publish might succeed while the logging call silently fails.
Security is unnecessarily complex: Browser-based integrations often require you to expose an internet-facing endpoint and protect it using shared secrets, signatures, or allowlists. While achievable, these are extra considerations for a process that is not user-facing.
Configuration drift becomes a risk: A minor tweak to hosting settings, a new redirect, or a platform update can suddenly break the connection—even if your code remains unchanged. It is an unnecessary moving part that is easily overlooked during system updates.
It is the wrong environment for the task: Logging a publish event is fundamentally a server-to-server data transaction. The browser is not where that responsibility belongs.
While CORS provided the error message, the real issue was that we had built a backend integration on top of a frontend execution environment.
Leveraging Sanity Functions for robust content automation
Around the time I resumed the project, Sanity introduced Sanity Functions. It quickly became clear that this was a superior home for this kind of logic.
Sanity Functions are a managed, serverless way to run backend code in response to events in your Sanity dataset—such as documents being created, updated, or published.
This enabled a vital change: shifting the integration out of the editor’s browser and into server-side code that executes because Sanity detects a state change. Instead of the Studio attempting to call our API when someone clicks ‘Publish’, Sanity itself triggers the code. By moving this logic into a standalone function, we avoid the complexity of messy custom publish logic.
With Functions, the workflow is straightforward. When a document is published, the function receives the necessary details—document ID, type, slug, and timestamps—shapes that data for Monday.com, and calls the API to update the board.
Key benefits of adopting a server-side architecture
Switching to Sanity Functions made the entire workflow more robust and easier to ship with confidence:
Elimination of CORS issues: The call to Monday.com no longer originates from a browser, so cross-origin rules do not apply. There is no preflight request to fail and no “allowed origins” list to maintain.
Increased reliability: Because the function runs on the backend, it is not dependent on the editor’s hardware, network connection, or whether they keep their browser tab open.
Enhanced security: The Monday.com API token remains in a secure, server-side environment rather than being exposed to client-side code. You also avoid the need to maintain a public endpoint specifically for publish events.
Reduced coupling: The logging mechanism no longer relies on your Next.js app being reachable or perfectly configured. This separation is valuable when redeploying the site or evolving your routing and middleware.
A foundation for automation: Once this pattern is established, it is easy to extend. You can log unpublishes, enrich Monday.com items with additional metadata, or move other data-driven endpoints to Sanity Functions to create concise workflows with fewer moving parts.
Building for operational resilience
Ultimately, this migration was about more than just fixing a bug, it was about building for operational resilience. In a professional content environment, your workflows should not be at the mercy of browser settings or temporary network blips. By decoupling the integration from the frontend, we created a system that is silent, stable, and scalable.
This server-side approach ensures that your content operations remain consistent, regardless of how your website hosting or local browser environments evolve. It transforms a fragile, user-dependent process into a reliable piece of infrastructure that supports your team’s growth.
Is your content architecture ready for production?
If your current setup relies on client-side workarounds or fragile connections, it might be time to modernise your workflow. At Brew Digital, we help businesses build robust, future-proof digital platforms. Get in touch today to discuss how we can streamline your Sanity integration and strengthen your content operations.