Fixing Contentful Preview in Next.js Draft Mode

Hero image for Fixing Contentful Preview in Next.js Draft Mode. Image by Logan Voss.
Hero image for 'Fixing Contentful Preview in Next.js Draft Mode.' Image by Logan Voss.

In Brief

Preview usually fails because one part of the chain is out of step: the Contentful preview URL, Draft Mode route, cookies, iframe behaviour, environment variables, query choice, cache bypass, or linked draft data. Check the editor's real preview path first, not just a copied production URL in a browser tab.

Preview is one of those features that looks like a small implementation detail until it fails. Then it becomes the thing that decides whether editors trust the whole platform.

On paper, the job is straightforward. Contentful has draft content. Next.js has a way to bypass static generation for preview sessions. The editor clicks a preview button and sees the page as it will look when published.

Preview sits at the join between CMS configuration, URL construction, route handling, cookies, authentication, iframe behaviour, caching, draft APIs, and editor workflow. The failure modes can feel slippery because each layer can be technically correct while the whole flow still fails. Preview works locally but not in production. It works in a new tab but not inside the CMS. It works for articles but not landing pages. It works after clearing cookies. It works for one editor but not another.

That is not a content problem. It is a trust problem.

If preview is being reviewed during a platform move, treat it as a migration requirement rather than a late implementation detail. The article on why CMS preview should be a migration requirement covers that planning layer more directly.


Preview Has to Match the Editor's Real Path

The first mistake is testing preview from a copied URL and declaring it fixed.

Editors do not usually preview content by pasting a route into a browser. They open an entry, click a preview action, sometimes inside a live preview pane, sometimes in a new tab, and expect the page to show the current draft state. Contentful's own help documentation describes both live preview and preview in a new tab as editorfacing workflows, not developer conveniences.

If the bug only appears inside the CMS iframe, test inside the iframe. If it only appears when the editor is already logged in to a protected preview environment, test with that auth state. If the problem is contenttype specific, test the content type that fails rather than the simplest blog post.

Preview debugging should reproduce the editorial path, not the developer shortcut.


Draft Mode is a Boundary, Not the Whole Feature

Next.js Draft Mode is the mechanism that lets a statically generated page render dynamically for a preview session. In the Pages Router, the Draft Mode guide uses an API route to enable the preview cookie and then fetch draft data from the CMS. In the App Router, the current Draft Mode API is async, so server code checks it with await draftMode() and Route Handlers enable or disable the preview cookie for that browser session.

That mechanism is important, but it is only one part of preview.

A reliable preview flow still has to answer several questions:

  • How does the CMS build the preview URL?
  • How is the preview request authenticated?
  • Which route receives the request?
  • How does the route validate the slug?
  • Does the preview session fetch draft content or published content?
  • Does the route bypass static cache correctly?
  • Is the editor looking at the correct environment?
  • Does the browser accept the cookie in the context being used?

If any of those answers is fuzzy, Draft Mode may be working perfectly while preview still feels broken.


The Preview URL is Part of the Contract

Preview URLs should be boring, explicit, and hard to misuse.

A useful preview URL usually carries a secret, a content identifier or slug, and enough context for the front end to route the editor to the correct page. It should not blindly redirect to any arbitrary URL passed in a query string. It should validate that the requested content exists, belongs to the expected content type, and maps to a route the site can render.

Teams often cut a corner here. The CMS preview config is set up quickly for one content type, then copied across other types as the model grows. Six months later, the article preview path works, the campaign page path half works, and a shared block cannot be previewed because it is not a page.

That is not unusual. Headless content models usually contain page entries and supporting entries. Editors may still expect to preview both. The implementation needs a clear rule for supporting entries: either route them to the page that uses them, show a useful preview shell, or explain that this content type cannot be previewed directly.

Silence is what makes editors lose trust.


Live preview often uses an embedded view. That makes browser behaviour part of the system.

Cookies that work in a normal tab may fail or behave differently inside an iframe depending on domain, protocol, browser privacy settings, SameSite attributes, secure flags, auth tooling, and local development setup. The Next.js Draft Mode documentation notes that local HTTP testing may require browser support for thirdparty cookies and local storage access. That is not trivia. It is exactly the sort of detail that makes a preview bug look random.

Frame policies can also block the preview entirely. If the application sends headers that prevent it being embedded, the CMS preview pane may show a blank frame or a browser error. If the app requires authentication, the auth provider may refuse to run inside the embedded context. If preview is served from a different deployment domain, cookies may be set for the wrong host.

The fix is not to weaken every header until preview works. The fix is to decide which origins are allowed to embed preview, which environments support it, and how preview authentication should behave.


Separate Draft Data from Published Data

Many preview bugs are actually datasource bugs.

The route enters Draft Mode correctly, but still calls the published Contentful API. Or it fetches draft data for the main entry, but shared navigation, related articles, or linked entries still come from the published API. The editor sees a halfupdated page and reasonably concludes that preview cannot be trusted.

Linked entries make this more obvious. A draft article might reference a draft author, a draft hero image, or an unpublished related entry. If the query only handles the toplevel draft, the rendered page can become a strange mix of current and stale content.

For each page type, preview needs to define how deep draft resolution should go. That does not mean every preview request should fetch the entire universe. It means the important fields and linked entries should behave predictably.

Contentful preview should answer the editor's question: "If I publish this, what will users see?" If the page cannot answer that, the interface should say why.


Preview Performance Matters More than Teams Admit

A slow preview path is a broken preview path in disguise.

Editors tolerate a little delay when they know the system is doing real work. They do not tolerate waiting ten seconds for every change, guessing whether the page refreshed, or opening three tabs to confirm a title. Slow preview creates workarounds. Workarounds create publishing risk.

Preview routes are often slower because they bypass static output, fetch draft data, include heavier linkedentry graphs, and run inside authenticated or embedded contexts. That is expected. It does not mean the performance can be ignored.

Measure the actual preview path. Which query is slow? Which content type carries too many references? Are images transformed during preview? Are related articles or global modules fetched when the editor only needs the page body? Does the same request run several times because the route, preview shell, and client component all fetch independently?

Preview is not public performance, but it is still product performance. The user is the editor.


The Useful Debugging Order

Start with one content type that matters.

Open a real entry in Contentful. Use the same preview action an editor uses. Capture the request path, response status, redirects, cookies, frame headers, and data source. Then change one field and try again.

If preview does not open at all, look at URL construction, auth, redirects, and frame policy. If it opens but shows published content, look at Draft Mode, cookie state, and which Contentful API is being called. If it shows some draft content but not all of it, inspect linked entries and shared data. If it works in a tab but not inside the CMS, focus on iframe, cookie, and header behaviour. If it works for one route but not another, compare the routing and contenttype mapping.

Do not start by rewriting the preview architecture. Most preview bugs have a smaller first cause. Find that before changing the shape of the system.


Make Failure Understandable

Editors should not have to learn Draft Mode internals, but they do need useful failure states.

If a content type cannot be previewed directly, say so. If a preview route needs a published parent page, explain that. If draft content is unavailable because the entry has no slug or required field, make the error visible. If preview is only supported in a specific environment, do not let the CMS point at a dead URL.

A plain failure message is better than a silent fallback to published content. Silent fallback teaches editors that preview lies.


Wrapping Up

Contentful preview in Next.js is not just a route handler. It is an editorial contract.

Draft Mode enables the technical boundary, but reliable preview needs correct CMS URLs, safe validation, draft data, iframecompatible headers, cookie behaviour, auth decisions, and performance that editors can live with.

Preview does not need to be clever. It needs to be boring enough that editors stop asking whether the page they are seeing is real.

Key Takeaways

  • Test preview through the same Contentful path editors actually use.
  • Draft Mode is necessary for many static preview flows, but it is not the whole feature.
  • Iframe, cookie, auth, and frameheader behaviour explain many productiononly preview bugs.
  • Preview must fetch draft data consistently, including important linked entries.
  • Slow preview damages editorial trust even when the public site is fast.

Want to find out more?

If you need senior handson support with a complex React or Next.js platform, migration, performance issue, or technical SEO problem, send me the context and I'll tell you where I can help.