Hello Umbraco Heartcore

Sneak peek at Umbraco Heartcore - the new headless CMS service from Umbraco HQ

Happy 1st of December Umbraco friends!

We, Morten and Rasmus from Umbraco HQ, are delighted to have this first post in this year’s “24 Days in Umbraco” where we get to share what we have been working on for the past ~5 months, and to give you a sneak peek at Umbraco Heartcore - our headless CMS offering on Umbraco Cloud, which officially launches tomorrow on December 2nd.

What makes Umbraco Heartcore a headless CMS?

But what is a headless CMS you ask? We could have just posted a wikipedia quote here and been on our way, but since it’s based on Umbraco it is worth highlighting what we have added. Sure we “chopped off the head” so the frontend part is decoupled from the CMS. But the friendly backoffice is still front and center, because that is a huge part of what makes Umbraco Umbraco. You might even say it’s the heart of Umbraco ;). In addition to the backoffice that we all know and love, we have added a managed API on top, which is divided into two parts: 
A Content Delivery API (cdn.umbraco.io) and a Content Management API (api.umbraco.io).

With the term “headless” being so popular among web developers and cms vendors it starts to mean many different things to many different people. We think we largely agree on it involving at least a CMS backend and an API, which is fair. The way we have chosen to approach is to expose more or less everything through RESTful APIs, which means that you can use the Content Delivery API for your presentation layer and the Content Management API for creation, updates and deletions (CRUD operations). We believe this will provide a lot of flexibility in terms of integration with other systems - in both push and pull scenarios. Whether you use content from Umbraco to enrich other systems (like ecommerce) or use other systems to enrich content already in Umbraco with tags, pictures or other types of data. The Content Management API and Webhooks will open up a lot of options, which we think are super interesting.

In addition to the REST APIs already mentioned, we have added a Content Delivery Network (CDN) at various levels to make the delivery of content and media extra great. We have chosen to go with Cloudflare as our CDN provider, because of their extensive network, security features and their ability to route traffic through the fastest routes to give our users the lowest latency.

For starters we are using a CDN for caching content fetched through the Content Delivery API and of course for media as well. The really cool thing about the media CDN (media.umbraco.io) is that we can provide the same image resizing and cropping options through the CDN as you get with regular Umbraco websites. So you get a lot of performance improvements and flexibility out of the box.

Let’s have a look …

Let us show you a few of the new things we have added to the Umbraco backoffice to make it easier for you to work with Umbraco as a headless CMS.

With REST APIs being the way to retrieve content (and potentially also a way to create content) we need authentication and authorization in place. With the ability to create API Keys through the backoffice we have made it easy to get you set up with the different types of permissions you need. An API Key is created for an Umbraco Backoffice User and the permissions for that user will be applied to the API Key. So if the API Key is used to create media the backoffice user must have access to the media section.


From the Users section you can get an overview of API Keys already created. To create a new API Key you click the user you want to create an API Key for and click the icon as shown below.


Give your API Key a name, so it’s easy to remember what its used for and optionally set an expiration date. Once you click create you can see the various options for using the API Key through HTTP Requests (if you are using the client libraries you don’t really need to think about this - then it’s just copy pasting the API Key into the configuration).


Oh, and you can of course always revoke an API Key so it stops working.

Protecting the Content Delivery API

The Content Delivery API exposes published content and media, which is public by default (just as when you publish content on your website). But you might want to protect that API so it requires the use of an API Key to access. From the headless tree you have a toggle where you can turn authentication for the Content Delivery API on and off.

Headless tree you say? Yes, we have put a few of the new Umbraco Heartcore features into a tree in the backoffice, so you have access to stuff like the API Browser and Webhooks, which we’ll show in greater detail in the sections below. It also shows you what your plan includes in terms of languages and user roles - and of course the Content Delivery API protection toggle.


API Browser

From within the API Browser in the Umbraco backoffice you can explore the two REST APIs without needing to dive into something like Postman or start writing code. You don’t even need to think about authentication as that is handled for you behind the scenes. It’s a great way to get familiar with the APIs and see the output when retrieving a single content item, when retrieving children of a specific content item and so forth.

You can access both the Content Delivery and the Content Management APIs from the API Browser.



Another feature you will find in the backoffice of an Umbraco Heartcore project is webhooks. The definition of a webhook is “a user-defined HTTP callback triggered by an event”, which basically means that when an event happens we will make a POST request to a URL defined by you. Right now the available events are Content-Saved/Published/Deleted and Media-Saved/Deleted, and specifically for Content we allow you to filter by Document Types. I believe the filter option was an idea that came about at Codegarden 2019, so hat-tip to the people who mentioned it after the “Headless Taco”-session :)

Behind the scenes we’ll try to call your endpoint up to 10 times and for each request and failure you can see it in the log entries in the backoffice. A log entry will also contain the payload that we tried to POST to the URL along with status code, status description, number of retries and much more, which should provide sufficient insight in case something goes wrong.


Client Libraries

Up until now we have talked about features and various APIs available, so it feels like we should start showing some code!

HTTP is great and the REST APIs are relatively easy to implement in most programming languages, but it can be a bit cumbersome and maybe not the most interesting task to start with on any project. Luckily we have a few client libraries where all the available APIs are implemented in C# / .NET Standard and JavaScript / NodeJS, so it’s relatively easy to get started with. And we have done a lot of work to make it easy and intuitive to work with the Content Delivery (published content and media) and Content Management (creating/updating/deleting) APIs.

Here is an example of newing up the ContentDeliveryService and fetching the root content of an Umbraco Heartcore project running on Umbraco Cloud:

//New up service with the entered Headless Project Alias
var service = new ContentDeliveryService("my-headless-project");
//Retreive all Content items at the root
var root = await service.Content.GetRoot();

This is using the nuget package available here: https://www.nuget.org/packages/Umbraco.Headless.Client.Net/ 

The library is based on netstandard 2.0, so it should work for most things .net including Xamarin.

The nodejs client library is available on NPM: https://www.npmjs.com/package/@umbraco/headless-client

Example use of the .NET Core Client Library

Let us dive deeper into the .NET Core Client Library where we have two samples to show how the client library can be used - one with a .NET Core MVC Website and another one with a .NET Core Console. Here we’d like to highlight the Console sample, not only because of the amazing ASCII art, but also because it has examples of using both the Content Delivery API for fetching published content and media and the Content Management API for creating a media folder, media item and then uploading an image to that media item.

In the previous code snippet we showed you how to retrieve the root content. Retrieving all items from the root of the media library is very similar:

//New up service with the Project Alias
var service = new ContentDeliveryService("my-headless-project");
//Retreive all Media items at the root
var root = await service.Media.GetRoot();

We can now iterate over all the root media items.

In the Console sample on github (available here https://github.com/umbraco/Umbraco.Headless.Client.Net/blob/master/samples/Umbraco.Headless.Client.Samples.Console) we use a recursive method to print out the root items and then for each of them, retrieve the children and the children’s children in order to print out the entire tree in the console.

static async Task Main(string[] args)
    var service = new ContentDeliveryService("my-headless-project");
    var root = await service.Media.GetRoot();
    foreach (var media in root)
        await PrintTree(service.Media, media, "", true);

private static async Task PrintTree(IMediaDelivery contentDelivery, Media media, string indent, bool last)
    System.Console.WriteLine(indent + "+- " + media.Name);
    indent += last ? "   " : "|  ";

    if (media.HasChildren)
        var paged = await contentDelivery.GetChildren(media.Id);
        var items = paged.Media.Items.ToArray();
        for (int i = 0; i < items.Count(); i++)
            await PrintTree(contentDelivery, items[i], indent, i == items.Count() - 1);

Creating a media folder, a media item and uploading an image.

First we need to new up the ContentManagementService and you can provide it with a backoffice username and password or simply an API-Key. In the console sample we ask for username and password for the sake of simplicity:

System.Console.WriteLine("Enter the Project Alias of your Umbraco Heartcore Project");
var projectAlias = System.Console.ReadLine();

System.Console.WriteLine("Enter your username:");
var username = System.Console.ReadLine();

System.Console.WriteLine("Enter your password:");
var password = GetConsolePassword();

var managementService = new ContentManagementService(projectAlias, username, password);

Then we ask for a name for the media item to create and a path to the image that you want to upload.

System.Console.WriteLine("Enter path to an image (png, jpg)");
var imagePath = System.Console.ReadLine();

System.Console.WriteLine("Enter a name for the Media item to create");
var mediaName = System.Console.ReadLine();

In the sample we have a few different checks to see if a folder called “Console” already exists and if it does we will reuse it - if not we will need to create the folder before we can put a media item in it. In the snippet below we create a new media folder.

var managementService = new ContentManagementService(projectAlias, username, password);
var createdFolder = await managementService.Media.Create(new Media { MediaTypeAlias = "Folder", Name = "Console" });
var folderId = createdFolder.Id;

With the id of the “Console” media folder we can create the media item and upload the image as follows:

//Image variables - could be input from console from previous snippet
var mediaName = "Han Solo";
var imagePath = @"C:\images\han-solo.png";
var fileName = Path.GetFileName(imagePath);
var extension = Path.GetExtension(imagePath).Trim('.');
//Create Media object where the Parent Id is the id of Console folder from the previous snippet
var media = new Media {Name = mediaName, MediaTypeAlias = "Image", ParentId = folderId};
media.SetValue("umbracoFile", new { src = fileName }, new FileInfoPart(new FileInfo(imagePath), fileName, $"image/{extension}"));
var image = await managementService.Media.Create(media);

//Retrieve the image through the Content Delivery API to get the Url and Crops
var service = new ContentDeliveryService(projectAlias);
var newlyCreatedImage = await service.Media.GetById(image.Id);

The response will contain the URL to the image on the CDN, so it will look something like this: media.umbraco.io/<project-alias>/path/to/media.png

And voila! We just uploaded an image to the Umbraco media library in a few lines of code.

If you had added crops to the standard image cropper in Umbraco the response would also have contained URLs to the various crops. Below is an example of the response for the umbracoFile-part with crops

    "umbracoFile": {
    "cropUrls": {
      "Hero": "https://media.umbraco.io/test/rbundogg/han-solo.png?crop=0,0.16333333333333333,0,0.55185654008438823&cropmode=percentage&width=1580&height=600",
      "List": "https://media.umbraco.io/test/rbundogg/han-solo.png?crop=0.0000000000000001263187085796,0.14166666666666666,0,0.46393678160919533&cropmode=percentage&width=580&height=305"
    "focalPointUrlTemplate": "https://media.umbraco.io/test/rbundogg/han-solo.png?width={width}&height={height}&mode=crop&center=0.5,0.5",
    "src": "/media/rbundogg/han-solo.png",
    "focalPoint": {
      "left": 0.5,
      "top": 0.5
    "crops": [
        "alias": "Hero",
        "width": 1580,
        "height": 600,
        "coordinates": {
          "x1": 0,
          "y1": 0.16333333333333333,
          "x2": 0,
          "y2": 0.5518565400843882
        "alias": "List",
        "width": 580,
        "height": 305,
        "coordinates": {
          "x1": 1.263187085796e-16,
          "y1": 0.14166666666666666,
          "x2": 0,
          "y2": 0.4639367816091953

Heartcore Documentation

What about documentation? We have a lot of documentation in place already. It’s worth mentioning that we updated the regular backoffice tour and included a few more tours related to the new features in the backoffice, so we highly recommend checking those out.

All the REST APIs are documented with everything that you'd expect in terms of query strings, headers, optional string and sample response bodies.

From the API Documentation section you can find everything you need to know about authentication and authorization (oAuth and API-Keys) and references for all endpoints with both the Content Delivery and the Content Management APIs: https://our.umbraco.com/documentation/Umbraco-Heartcore/API-Documentation/

We have a few Getting Started articles with the basics of getting setup with a project, creating API-Keys and we have a few articles related to the two client libraries available. And we are actively working on more articles related to how Umbraco Heartcore can be used in different contexts. So check-out the Umbraco Heartcore section under Documentation on OUR: https://our.umbraco.com/documentation/Umbraco-Heartcore/

And yes, we are always happy to hear suggestions for specific docs/articles that you would like to see added. Drop us an email on headless@umbraco.com to tell us more.

Try it out starting - tomorrow!

We hope that you found this article interesting and hopefully left you with the desire to try out Umbraco Heartcore and the samples or maybe even create your own little sample to get started. We look forward to seeing the cool projects that will be built using this new headless offering, and we very much look forward to adding new and awesome features to Umbraco Heartcore to make it even more interesting to work with. At least we have a million ideas to get us started :)

From tomorrow it will also be possible to get a glimpse of what the future has in store for Umbraco Heartcore, as the public roadmap will be updated with what we are working on Now, Next and Later.
One of the things that we are most excited about is GraphQL 

Umbraco Heartcore will officially launch tomorrow, December 2nd. I would have written the exact time of day, but because of timezones (my nemesis) I’ll leave this part to the HQ communications  team at Umbraco - and they’ve told me to tell you to keep an eye on  Twitter for more info.  Along with the launch, you’ll also find all the information about plans, prices etc. on Umbraco.com
And this is also where  you can sign-up for a 14 day free trial of Umbraco Heartcore which should hopefully give you a bit of time to try it out (before you use it on your next Umbraco project 🤞). // Morten

PS: If you lit your Christmas candle before you started reading this article and it’s now down to December 5th, I’m sorry. There was a lot of things to cover in one article 😅

Morten Christensen

Morten is on Twitter as

Rasmus John Pedersen

Rasmus is on Twitter as