> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://contentful.com/developers/docs/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://contentful.com/_mcp/server. # Using Draft Mode to fetch unpublished content from Contentful APIs > How to configure a route handler ## Overview To allow your users to preview content changes before publishing them, you will need to configure your application to fetch "preview" content from Contentful's APIs correctly. You can then leverage Vercel's [Draft Mode](https://vercel.com/docs/workflow-collaboration/draft-mode) feature inside your application to adapt your Contentful API calls to fetch preview content only when Draft Mode is enabled. *How* your specific applications constructs queries and fetches data from Contentful APIs will likely vary depending on your specific use case. This guide provides concrete examples that you can take as a starting point and hopefully adapt to your own application. ## Prerequisites You will need to provide a way for your content editors to "activate" Draft Mode in your application: * You can install the [Vercel app](https://www.contentful.com/marketplace/app/vercel/) and follow our guidance for [setting up a route handler to activate Draft mode](/tools/vercel/vercel-nextjs/setting-up-draft-mode-route-handler) in a separate topic in this guide. * You can follow Vercel's instructions [for enabling Draft Mode in the Vercel Toolbar](https://vercel.com/docs/workflow-collaboration/draft-mode#enabling-draft-mode-in-the-vercel-toolbar). (Note that the Vercel toolbar is not compatible with Contentful's side by side preview features, including Live Preview). ## Configuring Contentful API keys for accessing preview content Accessing Contentful's preview APIs requires a different access token than the token used for accessing production content. A preview token is included in every API key you create for your space. Following is how you might provision an API key and incorporate it into your Vercel-hosted Next.js project. In your Contentful space: 1. Navigate to **Settings > API Keys**. Create a new API key or find the existing API key being used for your project. 2. Take note of the values for "Content Delivery API - access token" and "Content Preview API - access token" for use in the next step. 3. Navigate to **Settings > General Settings** 4. Take note of the value for "Space ID" In your Vercel project: 1. Navigate to **Settings > Environment Variables** 2. Create an environment variable with key `CONTENTFUL_ACCESS_TOKEN` and use the value you copied for "Content Delivery API - access token" 3. Create an environment variable with key `CONTENTFUL_PREVIEW_ACCESS_TOKEN` and use the value you copied for "Content Preview API - access token" 4. Create an environment variable with key `CONTENTFUL_SPACE_ID` and use the value you copied for "Space ID" ## Accessing preview content via Contentful's GraphQL API If you are using GraphQL to fetch Contentful content, you will need to adapt your GraphQL queries and HTTP requests to access preview content when Draft Mode is enabled. In brief, you will need to adapt your Contentful GraphQL API calls to: * Use the preview access token instead of the default access token when accessing preview content in Draft Mode * Disable Next.js's [default caching behavior](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#caching-data) when fetching preview content in Draft Mode * Adapt your GraphQL queries to include a `preview` parameter that should be set to `true` when your application is in Draft Mode The example below illustrates what a working implementation of the above points might look like. > **Info** > > For complete documentation on how to use Contentful's GraphQL API see the [GraphQL reference documentation](/references/graphql/overview). ### Example: GraphQL API The examples below assume you followed the suggested guidance for provisioning an API key and adding the API tokens to your Vercel project as environment variables. 1. Create a "preview aware" fetch utility function: ```ts // lib/contentful/api.ts // preview parameter should be called with `true` when Draft Mode is enabled async function fetchGraphQL(query: string, variables = {}, preview = false) { const res = await fetch( `https://graphql.contentful.com/content/v1/spaces/${process.env.CONTENTFUL_SPACE_ID}`, { method: "POST", headers: { "Content-Type": "application/json", // use the preview access token when preview is enabled Authorization: `Bearer ${ preview ? process.env.CONTENTFUL_PREVIEW_ACCESS_TOKEN : process.env.CONTENTFUL_ACCESS_TOKEN }`, }, body: JSON.stringify({ query, variables, }), // disable caching in preview mode (via `no-store`); otherwise use `force-cache` which is the default cache: preview ? "no-store" : "force-cache", } ); return await res.json(); } ``` 2. Adapt your existing GraphQL queries to handle a "preview" boolean value correctly. (The example below assumes you have a "Blog Post" content model with some basic fields in Contentful.) ```ts // lib/contentful/queries.ts import { fetchGraphQl } from "../../../../../lib/contentful/api"; interface BlogPost { __typename: string; sys: { id: string }; slug: string; title: string; description: string; } interface BlogPostCollection { items: BlogPost[]; } interface FetchResponse { data?: { blogPostCollection?: BlogPostCollection; }; } const BLOG_POST_GRAPHQL_FIELDS = ` __typename sys { id } slug title description `; function extractBlogPost(fetchResponse: FetchResponse): BlogPost | undefined { return fetchResponse?.data?.blogPostCollection?.items?.[0]; } // preview parameters should be called with `true` when Draft Mode is enabled export async function getBlogPostBySlug(slug: string, preview: boolean = false): Promise { const entries = await fetchGraphQL( // the `preview` value is passed as an argument to the query to allow unpublished entries to be returned `query { blogPostCollection(where: { slug: "${slug}" }, preview: "${preview}", limit: 1) { items { ${BLOG_POST_GRAPHQL_FIELDS} } } }`, // the `preview` value is also passed as the third argument to the fetchGraphQL function to trigger correct access token and caching behavior preview, ); return extractBlogPost(entries); } ``` 3. When fetching Contentful content via GraphQL in your component, retrieve and pass through the current Draft Mode state as the `preview` parameter: ```ts // app/blogs/[slug]/post.tsx import { draftMode } from "next/headers"; import { getBlogPostBySlug } from "../../../../../lib/contentful/queries"; interface BlogPostProps { params: { slug: string }; } export default async function BlogPost({ params }: BlogPostProps) { const { isEnabled: isDraftModeEnabled } = draftMode(); const blogPost = await getBlogPostBySlug(params.slug, isDraftModeEnabled); return (

{blogPost.title}

{blogPost.description}
); } ``` You can adapt the above examples to your own use case, but the following files should hopefully make clear how you can take the state of Draft Mode from your page route and then adapt your query and API calls to ensure that preview content is fetched properly from Contentful. ## Accessing preview content via the Content Delivery/Preview API If you are using Contentful's [Content Delivery API Javascript SDK](https://github.com/contentful/contentful.js) to fetch content entries inside your Next.js application, you will need to make a few adjustments to your application to access preview content when Draft Mode is enabled. In brief you will need to: * Use the preview access token instead of the default access token when initializing the Contentful.js client in your application when Draft Mode is enabled * Specify the preview host (`preview.contentful.com`) during the same initialization call, again when Draft Mode is enabled. The example below illustrates what a working implementation of the above points might look like. ### Example: Content Delivery API Javascript SDK > **Info** > > This example assumes you have installed and are using Contentful's [Content Delivery API Javascript SDK](https://github.com/contentful/contentful.js) in your Next.js application. 1. Create a "preview aware" Contentful client initialization function: ```ts import { createClient } from "contentful"; // preview parameter should be called with `true` when Draft Mode is enabled export default function createContentfulClient(preview: boolean = false) { return createContentfulClient({ space: process.env.CONTENTFUL_SPACE_ID, // use the preview access token when preview is enabled accessToken: preview ? process.env.CONTENTFUL_PREVIEW_ACCESS_TOKEN : process.env.CONTENTFUL_ACCESS_TOKEN, // specify the preview host when preview is enabled host: preview ? "preview.contentful.com" : undefined, }); } ``` 2. Adapt your existing queries to handle a "preview" boolean value correctly. (The example below assumes you have a "Blog Post" content model with some basic fields in Contentful.) ```ts // lib/contentful/queries.ts import { EntryFieldTypes, Entry } from "contentful"; import createContentfulClient from "../../../../../lib/contentful/client"; interface BlogPost { contentTypeId: 'blogPost'; fields: { slug: EntryFieldTypes.Text, title: EntryFieldTypes.Text, description: EntryFieldTypes.Text, } }; export async function getBlogPostBySlug( slug: string, preview: boolean = false ): Promise | undefined> { const client = createContentfulClient(preview); const entries = await client.getEntries({ content_type: 'blogPost', 'fields.slug': slug, }); return entries.items[0]; } ``` 3. When fetching Contentful content in your component, retrieve and pass through the current Draft Mode state as the `preview` parameter: ```ts // app/blogs/[slug]/post.tsx import { draftMode } from "next/headers"; import { getBlogPostBySlug } from "../../../../../lib/contentful/queries"; interface BlogPostProps { params: { slug: string }; } export default async function BlogPost({ params }: BlogPostProps) { const { isEnabled: isDraftModeEnabled } = draftMode(); const blogPost = await getBlogPostBySlug(params.slug, isDraftModeEnabled); return (

{blogPost.title}

{blogPost.description}
); } ``` You can adapt the above examples to your own use case, but the following files should hopefully make clear how you can take the state of Draft Mode from your page route and then adapt your query and API calls to ensure that preview content is fetched properly from Contentful. > How to configure a route handler