Troubleshooting Visual Editing with Sanity and cookie issues

4 replies
Last updated: Oct 24, 2024
I’m trying to implement Visual Editing following this guide: https://www.sanity.io/guides/nextjs-app-router-live-preview .My implementation differs in that my studio is hosted on sanity.studio url instead of being embedded in Next.
Does Visual Editing (Presentation) require the studio to be on the same domain?

One of the issues i see is that the
__prerender_bypass
cookie does not work as expected.• I open my sanity.studio and go to “presentation”
• I can see in the network request that the cookie is actually being set once the
/api/draft
request is triggered• Editing and preview works as expected.
• However, when i open a new tab and visit the website, the
__prerender_bypass
cookie is not set.I suspect this might be because in sanity.studio, the preview is loaded inside and iframe and that the browser restrict the cookie on other tabs/windows.

Any thoughts or suggestions?
AI Update

You've correctly identified the issue! The __prerender_bypass cookie problem is indeed caused by third-party cookie restrictions when your Studio is hosted on a different domain (sanity.studio) than your Next.js site.

When the Presentation tool loads your Next.js site in an iframe, the draft mode cookies (__prerender_bypass and __next_preview_data) are set in a third-party context. Modern browsers increasingly block these third-party cookies by default for privacy reasons. This is why:

  • The preview works inside the iframe in Presentation (the cookie is set in that context)
  • Opening a new tab doesn't have the cookie (it's isolated to the iframe context)
  • The cookie doesn't persist across different browser contexts

Solutions

You have several options to resolve this:

In your /api/draft (or /api/draft-mode/enable) route handler, explicitly set the cookie with SameSite=None and Secure=true:

import { draftMode } from 'next/headers'

export async function GET(request: Request) {
  // Your authentication logic here
  
  draftMode().enable()
  
  // Manually set cookies with proper attributes
  return new Response(null, {
    status: 307,
    headers: {
      'Set-Cookie': '__prerender_bypass=...; SameSite=None; Secure; HttpOnly',
      'Location': '/',
    },
  })
}

However, this only works if the user's browser allows third-party cookies with SameSite=None.

2. Use the "Open in New Window" Feature

Configure your Presentation tool to open previews in a new window instead of an iframe. This makes the cookies first-party. You can add a button or configuration to open the preview URL directly:

import { presentationTool } from 'sanity/presentation'

export default defineConfig({
  plugins: [
    presentationTool({
      previewUrl: {
        previewMode: {
          enable: '/api/draft-mode/enable',
        },
      },
    }),
  ],
})

Then use the "Open in new window" icon in the Presentation tool interface, which should be available in the toolbar.

3. Embed Studio on Your Domain (Most Reliable)

Host your Studio at a path on your Next.js domain (e.g., yoursite.com/studio). This makes all cookies first-party and eliminates the issue entirely. You can do this by:

// app/studio/[[...index]]/page.tsx
import { NextStudio } from 'next-sanity/studio'
import config from '../../../sanity.config'

export default function StudioPage() {
  return <NextStudio config={config} />
}

4. Use Alternative Authentication

Instead of relying solely on cookies, pass authentication tokens via URL parameters or use the token prop in your data fetching. The Visual Editing with Next.js App Router guide shows how to handle token-based authentication for draft content.

Why This Happens

As noted in the Draft Mode documentation, browsers that block third-party cookies will prevent Draft Mode from working when the Studio and Next.js site are on different domains. This is an increasingly common scenario with Safari, Firefox, and Chrome's privacy features.

The iframe isolation is intentional browser security behavior - cookies set in an iframe from a different domain are treated as third-party cookies and are subject to stricter policies.

Recommendation

Your best path forward is likely option #3 (embedded Studio), as this avoids the third-party cookie issue entirely rather than trying to work around browser security policies. If that's not feasible, using the "open in new window" feature or passing tokens explicitly are good alternatives. The cookie-based approach alone won't work reliably across different tabs/windows when domains differ due to browser security restrictions.

👋 Visual editing doesn't require you to be on the same domain. Which browser are you using?
Brave.
I can see that the cookie response headers looks correct with SameSite=None and Secure.If i enable third party cookies in Brave, it works.
Right, but does it really require third party cookies to work?I mean, no browser will support this pretty soon… If this is by design, then i would suggest throwing up a big gotcha in the docs

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?