Sitecore XM Cloud: How To Setup Sitecore Headless SXA And Next.js

Getting Started With XM Cloud and Sitecore 10.x

December 25, 2022

By Dan Cruickshank

Setting Up Sitecore 10.x with SXA, Headless & Next.js

We are not looking at getting Headless SXA running with Docker. That would be too easy. 😄

Jump to

This is of course formative work for getting started on XM Cloud which is based on SXA, Headless & Next.js. Though if you have access to environment, you may want to start using SXA Starter repo that is docker-based. Without access to XM Cloud, or maybe you can't run Docker, this is one way you can get started.

For this Install we're going a little more old school, hoping to gain a deeper understanding by hooking up the pieces manually. Here's what we'll be doing:

  • Setting up your tenant and site
  • Installing JSS
  • Creating your Sitecore-based Next.js project
  • Updating all the settings and config required
  • Confirming your rendering host and Experience Editor work

We also be running in connected mode which means that we're getting our content Sitecore from a live Sitecore instance.

Prerequisites

We're not starting from ground zero. We will assume you've already done the following activities:

  • Installed Sitecore 10.3
  • HTTP binding in IIS for your site (e.g. http://s103demo1cm.dev.local - Next.js needs some coaxing to connect to an HTTPS server)
  • Installed Sitecore Powershell
  • Installed Sitecore Headless Services
  • Installed SXA 10.3
  • Solr schema have been populated, indexes have been built
  • Have the latest version of Node running

I used the Sitecore Installation Assistant (SIA) program to install Sitecore 10.3 then installed.

The hostname for our website is s103demo1cm.dev.local (specified as s103demo1cm during SIA). I'll be referencing the Sitecore instance by that hostname throughout. Use the same hostname or replace that with your own as we go through.

Troubleshooting Tips

Added Jan 14, 2023: I've just published a guide addressing the common errors encountered when setting up the initial Sitecore Headless SXA / Next / XM Cloud Dev stack.

Will This Work For XM Cloud?

Yes. When working with XM Cloud, it's important to use the Sitecore CLI to sync up your items between the environments. You'll want to pull down from XM Cloud and push those items into your local. I would also create a separate rendering host item for you local environment to not overwrite the default XM Cloud configuration.


Setting Up Your Headless SXA Tenant & Site

In SXA you have tenants and sites. A tenant can have many sites (or in this case one). And configurations can be set at the tenant or site modules, though most settings are going to be at the site level.

Step By Step Site Creation

  • Right-click on sitecore\content, select Insert / Headless Tenant
  • Our tenant name is getfishtank and select all the modules (yolo)
  • Right-click on sitecore\content\getfishtank select Insert / Headless Site
  • General tab: Our site name is www
  • Modules tab: Select all the modules (yolo)
  • Site Settings tab: the GraphQL endpoint can stay as default and Deployment secret can be blank (we'll get to that later)

Note for later: Calling our site www gives us the www item name that we want in our tree, but we'll ultimately be renaming the site's name within SXA site definition so it matches the name given to our Next.js app.

Step By Step Visual For SXA Site Creation

Sitecore 10.3 Desktop

Of course we'll start in the Content Editor or select Desktop then the Content Editor.

Select a Headless Tenant

Right-click on sitecore\content, select Insert / Headless Tenant.

SXA Headless tenant name and modules to install

Our tenant name is getfishtank and select all the modules.

Successful tenant creation.

Create a Headless Site inside your Headless Tenant

Right-click on sitecore\content\getfishtank select Insert / Headless Site.

General tab in SXA Site selection wizard.

General tab: Our site name is www

Modules tab in SXA Site selection wizard.

Modules tab: Select all the modules (yolo)

Site settings tab in SXA Site selection wizard.

Site Settings tab: the GraphQL endpoint can stay as default and Deployment secret can be blank (we'll get to that later)

Site has been successfully created.

Standard site structure for a Sitecore SXA Headless site.

Now you'll see the general structure of your SXA-based site.


Configuring The Rendering Host For SXA

Sitecore needs to know where our Next.js front-end is located. This allows Sitecore to essentially proxy the site into Experience Editor and Preview modes to create a seamless (and super impressive) experience.

Configuring your SXA rendering host for Next.js

 

Your SXA site will by default point to this /sitecore/system/Settings/Services/Rendering Hosts/Default as its rendering host. Values should be as follows:

 

  • Rendering Engine Endpoint URL: http://localhost:3000/api/editing/render
  • Rendering Engine Application URL: http://localhost:3000
  • Application Name: fishtank-nextjs-app (of course change if appropriate)

Note: If you were deploying to XM Cloud (or have a more complicated environment setup) you will want multiple rendering hosts. For instance, XM Cloud will point to a hosted application server (likely on Vercel), not localhost. To that end, its important to have distinct rendering host items (I'd recommend naming them per environment) so that they are not overwritten or in conflict when using the Sitecore CLI.

Selecting your Rendering Host within SXA site grouping.

To see how this connects to your SXA site, you can see and change the selected rendering host at /sitecore/content/getfishtank/www/Settings/Site Grouping/www under the Settings and Predefined application rendering host.


Creating Our JSS API Key

A quick bit of setup to create an API Key to communicate with Sitecore. You can have multiple API Keys with different setups, we'll setup a very plain one here for development.

Create an API Key in your Sitecore Headless SXA tenant.

Navigate to /sitecore/system/Settings/Services/API Keys, right-click and an insert API Key item. The name is only informational, name it as you like.

Sitecore SXA Headless Key Settings

We'll set CORS Origin: * and Allowed Controllers: * to leave it open as we're in development.

He have no need for a Throttling Strategy (see the item below) nor Impersonation.

This API Key value is important.

Item ID as your Sitecore API Key.

Grab the Item ID of the API Key. Save it. Copy it to notepad.

We'll need it for the jss setup steps soon.

Save and publish the item.

When we use the API Key in the setup we will drop the curly brackets but keep the dashes.


Install JSS / Sitecore Headless Services For SXA

Sitecore JSS is a big part of the magical glue that helps our headless app interact so seamlessly with Sitecore.

You'll need the latest (or very recent) version of node installed for this to work. I use NVM for Windows to manage multiple node versions locally. It is not necessary but if you want to try it, you can download NVM for Windows here. There are other Node Version Management tools available as well.

Load up your favourite terminal.

We are working out c:\code\ and will create the folder nextjs-sxa-intro-1 as the base of our overall install. Move into that folder.

PS C:\code\nextjs-sxa-intro-1>

Install Sitecore JSS CLI

Run npm install @sitecore-jss/sitecore-jss-cli to install the latest CLI for Sitecore. It should look like this.

PS C:\code\nextjs-sxa-intro-1> npm install @sitecore-jss/sitecore-jss-cli

added 221 packages, and audited 222 packages in 15s

25 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
PS C:\code\nextjs-sxa-intro-1>

You can try to install this package globally, but later we'll run a jss setup command which will prompt us for a non-global install.

Run jss --help to verify the setup. It should look something like:

PS C:\code\nextjs-sxa-intro-1> jss --help
jss <command>


Commands:
  jss setup    Sets up the scjssconfig.json config file, which defines how this
                application connects to a Sitecore instance for content or
                deployment.
  jss deploy    Deploys the JSS app artifacts to a Sitecore instance. Use `jss
                deploy --help` for subcommands.
  jss package  Generates a JSS manifest package file that can be deployed to
                Sitecore. Nothing is deployed. See also jss deploy package,
                which takes the package and deploys it to Sitecore. `jss package
                --help` for options.
  jss manifest  Generates a JSS manifest file which defines app assets to import
                into Sitecore. Nothing is deployed or added to a deployment
                package; this just collects assets. See `jss package`, which
                takes the manifest and turns it into a deployable package. `jss
                manifest --help` for options.
  jss clean    Cleans the contents of a directory, by default the
                buildArtifactsPath.


Options:
  --version  Show version number                                      [boolean]
  --help    Show help                                                [boolean]
PS C:\code\nextjs-sxa-intro-1>

Create Your Next.js Project

From that folder, enter the following command, note the hostname. This Sitecore link regarding JSS App Initialization is a useful reference.

npx create-sitecore-jss --templates nextjs,nextjs-sxa --appName fishtank-nextjs-app --hostName s103demo1cm.dev.local --fetchWith GraphQL

When asked for application location we'll leave it blank.

When asked how to prerender our application select SSG for static site generation.

Note that we're asking to build an app using the nextjs and nextjs-sxa app templates. The nextjs-sxa will install the code to run the OOTB Headless SXA components we installed earlier.

Using --fetchWith GraphQL is actually the default, but I'm including it specifically to reenforce the idea that we're running in *connected mode

The output should look like:

PS C:\code\nextjs-sxa-intro-1> npx create-sitecore-jss --templates nextjs,nextjs-sxa --appName fishtank-nextjs-app --hostName s103demo1cm.dev.local --fetchWith GraphQL

Need to install the following packages:
  [email protected]
Ok to proceed? (y) y
? Where would you like your new app created? C:\code\nextjs-sxa-intro-1\fishtank-nextjs-app
Initializing 'nextjs'...
? How would you like to prerender your application? SSG
Initializing 'nextjs-sxa'...
Installing packages...
> npm install

(I removed a lot of output for brevity)


                      __________
                  __ / / __/ __/
                / // /\ \_\ \
                \___/___/___/


JSS application fishtank-nextjs-app is ready!


Next steps:
* Connect to Sitecore with jss setup (optional)
* Enable source control (i.e. git init) (optional)
* Check out the JSS documentation at https://jss.sitecore.com


Enjoy!
PS C:\code\nextjs-sxa-intro-1>

Connecting Our Next.js App To Sitecore

First thing, let's navigate up into our newly created Next.js application folder. This Important because with app now created, this will be our new base for commands.

PS C:\code\nextjs-sxa-intro-1\> cd fishtank-nextjs-app
PS C:\code\nextjs-sxa-intro-1\fishtank-nextjs-app>

Now run jss setup. This will create /scjssconfig.json which contains most of the connectivity configuration for your app. See the comments below.

PS C:\code\nextjs-sxa-intro-1> cd .\fishtank-nextjs-app\
PS C:\code\nextjs-sxa-intro-1\fishtank-nextjs-app> jss setup
Is your Sitecore instance on this machine or accessible via network share? [y/n]: y
Path to the Sitecore folder (e.g. c:\inetpub\wwwroot\my.siteco.re): c:\inetpub\wwwroot\s103demo1cm.dev.local
Sitecore hostname (e.g. http://myapp.local.siteco.re; see /sitecore/config; ensure added to hosts): http://s103demo1cm.d
ev.local
Sitecore import service URL [http://s103demo1cm.dev.local/sitecore/api/jss/import]:
Sitecore API Key (ID of API key item): 32DC90FC-7E18-4303-BA5E-496255DC0568
Please enter your deployment secret (32+ random chars; or press enter to generate one):
Deployment secret has been generated. Ensure the JSS app config on the Sitecore end has the same secret set.
Deploy secret Sitecore config written to C:\code\nextjs-sxa-intro-1\fishtank-nextjs-app\sitecore\config\fishtank-nextjs-
app.deploysecret.config
Ensure this configuration is deployed to Sitecore.
JSS connection settings saved to C:\code\nextjs-sxa-intro-1\fishtank-nextjs-app\scjssconfig.json


NEXT STEPS
* Ensure the hostName in /sitecore/config/*.config is configured as s103demo1cm.dev.local, and in hosts file if needed.
* Deploy your configuration (i.e. 'jss deploy config')
* Deploy your app (i.e. 'jss deploy app -c -d')
* Test your app in integrated mode by visiting http://s103demo1cm.dev.local
PS C:\code\nextjs-sxa-intro-y\fishtank-nextjs-app> cd ..

Here is how we answer the questions. Please note that the hostname, folder and especially the API Key could have unique values.

  • Accessible via network share: Y
  • Path to Sitecore folder: C:\inetpub\wwwroot\s103demo1cm.dev.local
  • Sitecore hostname: http://s103demo1cm.dev.local (URL, not hostname )
  • Sitecore import service URL: [Leave blank]
  • Sitecore API Key: 32DC90FC-7E18-4303-BA5E-496255DC0568 (Use your Item ID here from the previous API Key step)
  • Deployment secret: [Leave blank to auto generate]

Note that for the API Key, we keep the dashes but remove the curly brackets.

Also look at the file .\sitecore\config\fishtank-nextjs-app.deploysecret.config that was created. That will get copied into our Sitecore website configs when we eventually run jss deploy config.

Almost there. Next step is to clean-up some of the standard configs and make sure they'll work for Headless SXA.


Final Configuration Updates in Next.js & Sitecore

For our final bit of configuration, we're going to do the following this.

  • Setup the JSS Editing Secret
  • Remove the site definition from the Next.js config file (SXA creates the site definition)
  • Update the app definition to point to SXA site root
  • Add our rootItemId to the DictionaryServiceFactory code
  • Update the site name in Sitecore to match the app name

Setup JSS Editing Secret

We have two places we need to config the the JSS Editing Secret. It's used to "secure the Sitecore editor endpoint exposed by your Next.js app".

Updating The App

Open the .env file in your Next.js app root.

Find the JSS_EDITING_SECRET= and create and add a long alphanumeric value. (I used my API Key GUID with brackets and dashes removed)

PUBLIC_URL=http://localhost:3000

# To secure the Sitecore editor endpoint exposed by your Next.js app
# (`/api/editing/render` by default), a secret token is used. This (client-side)
# value must match your server-side value (see \sitecore\config\fishtank-nextjs-app.config).
# We recommend an alphanumeric value of at least 16 characters.
JSS_EDITING_SECRET=32DC90FC7E184303BA5E496255DC0568

Updating The Sitecore Patch Config

Now we'll set this same value 32DC90FC7E184303BA5E496255DC0568 as the JSS Editing Secret in our Sitecore patch file (that will be pushed by jss deploy config).

Around line 41 of .\sitecore\config\fishtank-nextjs-app.config update the JavaScriptServices.ViewEngine.Http.JssEditingSecret setting.

Please note, in my experience testing I needed to restart IIS to get this config patched in as no DLLs were deployed and the config was net-new. The file containing an empty secret that should be patched is at \App_Config\Sitecore\JavaScriptServices\Sitecore.JavaScriptServices.ViewEngine.Http.config.

  <!--
        JSS EDITING SECRET
        To secure the Sitecore editor endpoint exposed by your Next.js app (see `serverSideRenderingEngineEndpointUrl` below),
        a secret token is used. This is taken from an env variable by default, but could be patched and set directly by uncommenting.
        This (server-side) value must match your client-side value, which is configured by the JSS_EDITING_SECRET env variable (see the Next.js .env file).
        We recommend an alphanumeric value of at least 16 characters.
    --> 
        <setting name="JavaScriptServices.ViewEngine.Http.JssEditingSecret" value="32DC90FC7E184303BA5E496255DC0568" />

Be aware that you'll need to uncomment this setting.

Remove Hardcoded Site Definition

Around line 65 of .\sitecore\config\fishtank-nextjs-app.config comment out the OOTB site definition. This is managed by SXA configuration items within Sitecore so its not needed.

      <site patch:before="site[@name='website']"
            inherits="website"
            name="fishtank-nextjs-app"
            hostName="s103demo1cm.dev.local"
            rootPath="/sitecore/content/fishtank-nextjs-app"
            startItem="/home"
            database="master" />
      -->

Update App's SitecorePath Definition

Near line 91, update the sitecorePath in the app definition the website's root item: /sitecore/content/getfishtank/www.

        <app name="fishtank-nextjs-app"
            layoutServiceConfiguration="default"
            sitecorePath="/sitecore/content/getfishtank/www""
            useLanguageSpecificLayout="true"
            graphQLEndpoint="/sitecore/api/graph/edge"
            inherits="defaults"
            serverSideRenderingEngine="http"
            serverSideRenderingEngineEndpointUrl="http://localhost:3000/api/editing/render"
            serverSideRenderingEngineApplicationUrl="http://localhost:3000"
        />

Add RootItemId To The DictionaryServiceFactory

Open the file .\src\lib\dictionary-service-factory.ts and look at around line 19. We will add the property rootItemId : {home-item-guid}.

export class DictionaryServiceFactory {
  create(): DictionaryService {
    return process.env.FETCH_WITH === constants.FETCH_WITH.GRAPHQL
      ? new GraphQLDictionaryService({
          endpoint: config.graphQLEndpoint,
          apiKey: config.sitecoreApiKey,
          siteName: config.jssAppName,
          rootItemId: "{C81EAB15-5486-4604-AD74-4DB61E3363F2}"
          /*
            The Dictionary Service needs a root item ID in order to fetch dictionary phrases for the current
            app. If your Sitecore instance only has 1 JSS App, you can specify the root item ID here;
            otherwise, the service will attempt to figure out the root item for the current JSS App using GraphQL and app name.
            rootItemId: '{GUID}'
          */
        })
      : new RestDictionaryService({
          apiHost: config.sitecoreApiHost,
          apiKey: config.sitecoreApiKey,
          siteName: config.jssAppName,
        });
  }
}

The rootItemId is the item ID of Home item at /sitecore/content/getfishtank/www/Home. The home page of your SXA site. There is a handy comment in the file as well.

If this step is not completed you will see the following error:

Error: Valid value for rootItemId not provided and failed to auto-resolve app root item

Update Site Name To Match The App Name

The site name is used in requests to Sitecore to resolve the headless content. The app name and the name attribute of the site definition in SXA must be made to match.

In the content editor navigate to /sitecore/content/getfishtank/www/Settings/Site Grouping/www.

Sitecore Headless SXA - match the site name to the app name

Update the Site name field to fishtank-nextjs-app. Now the site and the app have the same name and will work together.

We should be pointing at the master database running in live mode, but just incase feel free to publish.

Alternatively, we could have named our app www and these values would naturally align. Or named our website after our app. But I really think our site should be called www and our app should be called fishtank-nextjs-app.

It's important to understand how these names and fields link up!


Starting Your Website (Finally!)

Now that we've done all this setup, we will deploy the config files in the ./sitecore/config folder.

Run: jss deploy config

PS C:\code\nextjs-sxa-intro-1\fishtank-nextjs-app> jss deploy config
Creating nonexistant destination path C:\inetpub\wwwroot\s103demo1cm.dev.local\App_Config\Include\zzz...
Copying ./sitecore/config to C:\inetpub\wwwroot\s103demo1cm.dev.local\App_Config\Include\zzz...

JSS app build artifacts have been deployed to Sitecore.

Note: Restart your IIS to be safe. I've found new configs did always trigger an IIS restart. For example, when I checked ShowConfig.aspx I did not see my JSS Editing Secret until after a restart.

Then start our Next.js site in connected mode.

Run: jss start:connected

PS C:\code\nextjs-sxa-intro-1\fishtank-nextjs-app> jss start:connected
> npm run start:connected --
> fishtank-nextjs-app@21.0.2 start:connected
> npm-run-all --serial bootstrap --parallel next:dev start:watch-components
> fishtank-nextjs-app@21.0.2 bootstrap
> ts-node --project tsconfig.scripts.json scripts/bootstrap.ts
Writing runtime config to C:\code\nextjs-sxa-intro-1\fishtank-nextjs-app\src\temp\config.js
Registering JSS component ColumnSplitter

(... output deleted in this post for brevity ...)

Registering next-config plugin sitemap
Writing next-config plugins to C:\code\nextjs-sxa-intro-1\fishtank-nextjs-app\src\temp\next-config-plugins.js
> fishtank-nextjs-app@21.0.2 start:watch-components
> ts-node --project tsconfig.scripts.json scripts/generate-component-factory.ts --watch
> fishtank-nextjs-app@21.0.2 next:dev
> cross-env NODE_OPTIONS='--inspect' next dev
Debugger listening on ws://127.0.0.1:9229/4c9d2d6c-bb0b-43df-b034-8102dca47a68
For help, see: https://nodejs.org/en/docs/inspector
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
info  - Loaded env from C:\code\nextjs-sxa-intro-y\fishtank-nextjs-app\.env
Watching for changes to component factory sources in src/components...
info  - Disabled SWC as replacement for Babel because of custom Babel configuration ".babelrc" https://nextjs.org/docs/messages/swc-disabled
info  - automatically enabled Fast Refresh for 1 custom loader
info  - Using external babel configuration from C:\code\nextjs-sxa-intro-y\fishtank-nextjs-app\.babelrc

Load http://localhost:3000 to see it in action!

Now since you probably haven't added anything to your home page, it will be blank. But the page title in the browser should have a value like www

A beautiful blank page, no errors, means Headless SXA is working

Check Experience Editor

Go back into Sitecore, navigate to your home item at /sitecore/content/getfishank/www/home, right-click the item and select Experience Editor.

Experience Editor in Sitecore SXA Headless loading without errors.

Oh my goodness. I can't believe we made it this far. Looks like we're all up and running. 🙂

In Conclusion

I know we're at very early days with Sitecore 10 and Headless SXA. I it wasn't easy to find my way through the documentation to set it up (especially without Docker). There is documentation on SXA, documentation on JSS & Next.js but nothing that really pulled together the two (or three) so I hope you found this useful. I found this article on JSS App Initialization and running JSS In Connected Mode to be helpful. Be sure to check them out.

This is all related to XM Cloud which will leverage Headless SXA. It's good to get ahead. Perhaps what I've documented here could help with future product versions and documentation.

My goal is create another post soon highlighting all the errors and troubleshooting I encountered during this process. This was long enough without. Thanks everyone for reading.

Dan Headshot

Dan Cruickshank

President | Sitecore MVP x 11

Dan is the founder of Fishtank. He's a multi-time Sitecore MVP and Coveo MVP award winner. Outside of technology, he is widely considered to be a top 3 father (routinely receiving "Father of the Year" accolades from his family) and past his prime on the basketball court.