mike.jarosch.dev

Sitecore AI + AppRouter + SSG + Vercel = Error!

Cover Image for Sitecore AI + AppRouter + SSG + Vercel = Error!

Update: April 27, 2026

Sitecore has posted an update on the issue. They received clarification from Vercel and accessing searchParams in draft mode is not the intended approach. Any draft mode parameters should be passed via the headers. Sitecore will be including a fix in Content SDK 2.1!

Original Post

When migrating your Sitecore AI website to AppRouter using SSG and hosting on Vercel you will find that the Pages editor will break. Sitecore is aware and the bug is in NextJS. Here is a workaround to keep you going while waiting for the fix.

The Issue

When using AppRouter with SSG and your Editing Host is hosted on Vercel, the Sitecore AI Pages editor preview will show the spinner and never load. This is caused by the rendering endpoint used by Pages erring and returning a 500 response. The rendering endpoint is doing a fetch request to the page being edited on the Editing Host using NextJS draft mode to by-pass SSG. This call passes query string parameters related to editing, like version, variantIds, etc. The page then checks if draft mode is enabled and then passes those values to get "preview" content for rendering.

Normally, when using SSG, you don't have access to query string parameters. But when in draft mode, you can get access to them. The bug comes when hosting on Vercel, the call to get query string parameters in draft mode returns nothing.

The Workaround

The idea for this workaround comes from a discussion about the NextJS issue. You can't access query parameters, but you can access request headers. This means we can introduce a Proxy that checks if we are in draft mode, grab the query parameters, and pass them along in the headers. We can then update the page to pull the editing parameters from the header instead of the query string.

The Implementation

First, we need to create the proxy that copies the parameters into the headers.

import { ProxyBase } from '@sitecore-content-sdk/nextjs/proxy';
import { NextRequest, NextResponse } from 'next/server';
import { headers } from 'next/headers'

const KEY = 'x-draft-mode-search-params';

export class DraftModeWorkaroundProxy extends ProxyBase {
  async handle(req: NextRequest, res?: NextResponse): Promise<NextResponse> {
    const response = res || NextResponse.next();

    // Exit if we aren't in preview mode
    if (!this.isPreview(req)) {
      return response;
    }

    const searchParams = Object.fromEntries(req.nextUrl.searchParams);

    response.headers.set(KEY, JSON.stringify(searchParams));

    return response;
  }
    
  public static async getSearchParams(): Promise<Record<string, string | string[] | undefined>> {
    const headerValues = await headers();
    const workaroundHeader = headerValues.get(KEY) ?? '{}';
    const searchParams = JSON.parse(workaroundHeader);
    return searchParams as Record<string, string | string[] | undefined>;
  }
}

Second, we need to add it to the proxy.ts file.

...
  const draftModeWorkaround = new DraftModeWorkaroundProxy({
    sites,
    skip: () => false; /// Logic for disabling if it isn't your editing host should go here
  });

  return defineProxy(locale, multisite, redirects, personalize, draftModeWorkaround).exec(req);
...

Finally, we need to update ithe page.tsx file to pull the value from the headers.

...
  if (draft.isEnabled) {
    const editingParams = await DraftModeWorkaroundProxy.getSearchParams(); // await searchParams;
    if (isDesignLibraryPreviewData(editingParams)) {
...

Conclusion

With the workaround proxy in place, the page is able to get it's editing parameters and render correctly. Hopefully the NextJS project will be able to resolve the bug and the workaround can be removed.