Over the past few weeks I've been working on a headless CraftCMS integration with Nuxt for the frontend. I use Apollo and GraphQL to fetch the data from the CMS. Almost there now, but there's one feature I can not get to work. It's the live preview from CraftCMS which needs to show the updated page, loaded from a different domain.

I have been checking out numerous of tutorials, like these:

https://nystudio107.com/blog/headless-preview-in-craft-cms https://www.trevor-davis.com/blog/setting-up-live-preview-with-craft-cms-in-headless-mode

So far, I've been able to extract the params from the URL. I've added them to my query params, and although the right template is being loaded in the preview URL, it's not updating it with my (draft) changes.

This is (part of) my Nuxt page query:

    async asyncData({error, app, route, params}) {
      const curSiteId = app.i18n.locales.find(locale => locale.code === app.i18n.locale).siteId ?? process.env.DEFAULT_SITE_ID;

      const entry = await app.apolloProvider.defaultClient.query({
        query: aboutEntry,
        variables: {
          slug: 'over-ons',
          siteId: curSiteId,
          token: route.query.token ?? '',
          'x-craft-preview': route.query['x-craft-live-preview'] ?? '',
          'x-craft-live-preview': route.query['x-craft-live-preview'] ?? '',
      }).then(({data}) => data && data.entry)

      if (!entry) {
        return error({
          'statusCode': 404

      return {
        headData: await app.seomaticMeta(route, curSiteId),

The token and the x-craft-preview variables have the correct values. I've tested this by outputting it to the console.

  slug: 'over-ons',
  siteId: '2',
  token: 'v_FXkP_Hx2m7iKmjfc9CnSrVhKW4xBke',
  'x-craft-preview': '5QxCvjPZVg',
  'x-craft-live-preview': '5QxCvjPZVg'

So it seems that GraphQL is not passing it to Craft or Craft is not accepting the params.

This is my config/general.php

 * General Configuration
 * All of your system's general configuration settings go in here. You can see a
 * list of the available settings in vendor/craftcms/cms/src/config/GeneralConfig.php.
 * @see \craft\config\GeneralConfig

use craft\config\GeneralConfig;
use craft\helpers\App;

return GeneralConfig::create()
    // Set the default week start day for date pickers (0 = Sunday, 1 = Monday, etc.)
    // Prevent generated URLs from including "index.php"
    // Enable Dev Mode (see https://craftcms.com/guides/what-dev-mode-does)
    ->devMode(App::env('DEV_MODE') ?? false)
    // Allow administrative changes
    ->allowAdminChanges(App::env('ALLOW_ADMIN_CHANGES') ?? false)
    // Disallow robots
    ->disallowRobots(App::env('DISALLOW_ROBOTS') ?? false)
    // Control panel
    ->cpTrigger(App::env('CP_TRIGGER') ?? 'admin')
    // Run CraftCMS headless
    ->headlessMode(App::env('ENABLE_HEADLESS_MODE') ?? false)
    ->enableGraphQlCaching(App::env('ENABLE_GQL_CACHING') ?? false)
        'checkOrigin' => false

I am running Craft 4.4.13 and Nuxt 2.16.2. My CraftCMS is running locally on https://backend.XXX.local, while I'm running Nuxt on http://localhost:3000.

1 Answer 1


The tokens need to be in the request headers or query string, not in the body of the request. We use a different request lib, but try something like this:

      const entry = await app.apolloProvider.defaultClient.query({
        query: aboutEntry,
        variables: {
          slug: 'over-ons',
          siteId: curSiteId,
        headers: {
          'X-Craft-Token': route.query.token ?? ''
      }).then(({data}) => data && data.entry)

This is the relevant section from the Craft 4 docs:

You can pass the token via either a query string parameter named after your tokenParam config setting, or an X-Craft-Token header.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.