In this tutorial, you will learn how to build a headless website that is powered by the new Umbraco 12 content delivery API. On June 2023, Umbraco v12 was released. v12 was the first version of Umbraco to ship with an official API that was designed to allow implementors to create headless websites. The benefit of using a CMS like Umbraco for headless over a SAAS equivalent is the added ability to customize things. As long as you know a little bit of .NET you will have the power to customize the CMS and the content delivery API to your needs.

The focus of this article is going to be on building a headless website using NextJS. As of writing, NextJs is still the most popular React framework for web development, however, the walk-through here will still be applicable to most Javascript website builds.

Read on, to learn how to connect a NextJS website using either SSR or SSG to the Umbraco content delivery API. For this tutorial, I will assume you know how to set up and configure Umbracos content delivery API. If you do not know how to do this, fear not because I have created a specific deep-dive video on this topic which you can find here. Watch that video before trying to implement this tutorial!

Installing your headless Umbraco website

The first thing you will need to do is install NextJS. You can do that via NPM. To do this you will need node installed and configured. The first step is to install the NextJS installation tool called create-next-app. You can do that using this command:

After installing create-next-app, you can run this command to create a NextJs website:

After executing this command the tool will create a new vanilla NextJS website. Starting with a blank website is cool as it means that you can build the site exactly how you want, however, if you are new to NextJS starting from scratch can add more confusion into the mix!

If this is your first time using NextJS and you want to make your life slightly easier, instead of starting from a blank canvas you should make use of a template.

NextJs has a number of free templates/starter kits. These kits ship with all the pages, styles, and scripts that you will need to get started quicker. You can see all the available templates from the Vercel site here. To xewRW new site using one of these templates, you would change the installation command like this:

This command will create a site using the blog starter site. The blog starter kit will be perfect for you to get some insight into the topics that I want to cover in this tutorial!

After creating your site, the first thing you should do is set the environment variables that your code will require to communicate with Umbraco. To do this, you will need to define three environment variables. I cover how to create these variables within Umbraco within my content delivery API video. For this tutorial, I will assume they exist, however, I will provide a summary now of what you will need to use:

  • Domain: This variable will be used to set which domain the API should call. The domain you will need to use will vary depending on where you are currently working, e.g. locally, on staging, or in production

  • API Key: A password that you need to supply with each request within the request header. This is required for requests made from your website to the CMS to be authenticated correctly

  • Preview: A bool that defines if the API should return draft content

    To store these settings, create a new file called .env file within the root of your project. The contents of this file should look something like this:

The benefit of storing these values within environment variables is that within your hosting provider, you can easily switch them as needed on a per-environment basis. Let us say that you want to host your site in Netlify, within Netlify you could create two sites, one for production use and the other for content editors to preview the site. To create such a setup the only thing you need to switch is the preview environment variable, simple!

Code Required To Connect NextJS with Umbraco

As the content delivery API is new, sadly there are no related Umbraco SDKs that we can use with it at the time of writing. This is a bit of a pat peeve of mine with CMS vendors. As content delivery API is new I get it, however, within the next few months, I would love to see a Node/javascript library, and some mobile ones like Kotlin or FLutter that wrap the API. Until these officially supported libraries are created it is left to you to implement the APIs manually.

The good news is that I have created the code you need to use from the related sample site which you can find here. For learning purposes, let us walk through what that code does. First I created a file called configManager.js. The purpose of this file is to get the environment variables and add them to an object. The purpose of this is simply to eliminate duplicate code in your codebase later. The code for this helper looks like this:

With this config builder done, you can start calling the content delivery API. Before we start to implement that code, let us talk about an error that you will encounter on your local dev machine.

When you create your v12 instance, .NET using the Umbraco template will configure your site to work with HTTPS. When you create your NextJS site, it will not use HTTPS by default and the installer will not create a SSL cert for you. This means that when you try to call the Umbraco content delivery API which will use HTTPS over HTTP, you will encounter an error:

DEPTHZEROSELFSIGNEDCERT, Error: self-signed certificate error:

To get rid of this error locally, you can add a hack to your code. I have added this hack in the config code above to prevent it:

The first thing to mention about this code is that it should not be used in production. It is great for development only, so if you want to use my code, remember to add an appropriate environment check on it! With that point made, let us start getting data from Umbraco!

Within your app, you will need to call the content delivery API from many files. To avoid lots of duplication, I recommend that you create a central utility file where you add all your content delivery API code:

. To allow for maximum re-use you will want to separate the code that calls content delivery API from the code that constructs the URL for the end-point that you need to call.

This separation of concerns is the reason why the url is passed into callContentDeliveryAPI. As mentioned in my content delivery API deep-dive video, each end-point takes additional parameters that allow you to control what data gets returned. Depending on what parameters you need to use will determine the end URL that you need to use. An example of this URL building code for the content end-point is shown below:

After you have constructed the URL for the end-point that you want to call successfully, you can use fetch to call it. Remember, the Umbraco content delivery API has three end-points. content is used to get multiple things, while the item end-point is used to get data about a single item. When it comes to using item, you can specify which item you want to call by adding in either use a route or an ID as the identifier.

The good news is that when it comes to calling the item end-point code-wise, regardless if you supply either the route or ID, the URL structure that you use is exactly the same. This means that you will only need to create one function in your website in order to call item. An example of what this code looks like is shown below:

Rendering a NextJS Page

Now that you have the code to call the content delivery API, the next step is to start creating pages within NextJS that can call Umbraco. An example of the code required to render content contained within the homepage in Umbraco is shown below. This code would be added within a file called index.js that is located in the root of the Pages folder within your website:

Let us walk through what this component is doing. Within NextJS, before the page is loaded, a call will be made to either getStaticProps() or getServerSideProps depending on if you are doing page creation using server-side rendering (SSR), or static site generation (SSG). In my example, I am doing SSG

As I'm doing SSG, I implement getStaticProps() and within this function, I have implemented the code to call Umbraco using the helper/utility function we created above. As we know the URL for the homepage is the root domain. To get information about the homepage from Umbraco, I need to use the content delivery API item end-point. Passing in an empty route will query Umbraco for / which will match on the homepage.

After I have my page data, I can then pass it via props into my component. After getStaticProps() has finished running, the main component function will then be triggered with the passed in props. I can then use the data in those props to render my CMS content on the page. Simples!

That covers how to get data about a single page within your website that has a direct mapping to a single page created within the CMS. The other difference with the homepage is that you know the URL you want to query when you are writing the code. The homepage URL will never change so you can hardcode the URL within the component. This situation is different compared to pretty much every other page on the site. As content editors have free range to create pages within the CMS, most of the time you will not know the URL for the majority of pages when you are creating your components in NextJS.

A perfect example of these types of pages is the classic, blog pages! Content editors might create as many blog pages as they like and in your website code, you will never know which URLs are valid and which are not. Unless you want to make a code release every time an editor creates a page within a CMS, you will need a way to dynamically render pages in NextJS!

In terms of NextJS, when you need to deal with x amount of pages where you do not know the URL, you will need to use the NextJs dynamic routing feature. A dynamic URL means an incoming URL will be mapped to a single Page template within NextJS. You can make any file within your Pages directory a dynamic template by wrapping the filename with []. For this example, within my root Page directory, I have created a file called [blogs].js. In this file, I added this code:

When looking at this code keep in mind this code uses SSG! Under the hood, NextJS will first call the getStaticPaths() function at build time. Here you need to make a call to Umbraco to get all the URLs for the content pages that you want to be converted into actual apps within your website. In this situation, I want to convert all the blog pages within the CMS to website pages.

To get all the URLs from Umrbaco, I can use the content end-point within the content delivery API. As I only want blog pages to be returned for this component, I pass the {filter:'blog'} command to the URL. This command will return data for every blog page, however, for this step, I only need the route of each page. You can access the segment that was defined per page within the CMS from item.route.path. After parsing the returned array, you then need to return this finalized list of URLs as a prop called paths.

After the getStaticPaths() function has finished, the framework will take each Url in the paths array and then call getStaticProps() for each item. Within getStaticProps(), you can then add the code to get the data about that URL from the CMS.

To accomplish this you will need to access the passed-in path data. You can get access to this using the params prop. Using the path variable, within getStaticProps() you can finally call the content delivery API item end-point passing in the route/segment/URL. This call will then return the data about each individual page, which you can then pass into the main function as props.

With the correct props passed in, within your main component code, you can then access the page-related data and render the appropriate HTML!

Rendering Images

The last thing that I want to cover that can also catch people out is rendering images. The image media picker in Umbraco will return data in an array, even if you are only allowing editors to pick a single image! This means that within NextJS you will need to access any image data as the first item in the returned JSON response contained within an image property. This can definitely catch you out, so be warned! The code to render an image is shown below:

If you tried to implement this code as it is, the image will not render. Instead, expect to encounter an error like this:

The reason why you will see this error is that NextJS blocks any external domains when rendering images by default. As your image URL will be coming from the CMS server domain, it will not render!

To fix this, you will need to add some config within a file called next.config.js to whitelist your CMS domain. If you do not have a next.config.js do not worry, simply create it within your project's root directory. Within next.config.js you will need to add some config that looks like this:

In my environment, I'm only going to run my site locally. This means that I just need to whitelist localhost. With the config added, reboot your server, and your images should start to render as expected!

The last hidden gotcha that you might bump into can occur when you need to render content within a rich-text field. By default, rich-text content will be returned from the content delivery API as HTML.

If for example, you are building a mobile app HTML might not be what you want. Within appsettings.json in your CMS solution, there is a setting called RichTextOutputAsJson that you can enable. Doing this will switch the returned data from the content delivery API from HTML to JSON. JSON will give you more control over how you render that content, however, unlike other CMS systems there are no supported packages to render this JSON data for you and it will be left up to you to parse and render the data yourself!

Happy Coding 🤘