Umbraco Content Delivery API Setup
Content Delivery API appeared in Umbraco 12 as a built-in headless mechanism. REST API is read-only for published content. Version 13 added Preview API for drafts.
Enabling
// appsettings.json
{
"Umbraco": {
"CMS": {
"DeliveryApi": {
"Enabled": true,
"PublicAccess": true,
"ApiKey": "your-api-key-for-preview",
"DisallowedContentTypeAliases": [],
"RichTextOutputAsJson": false,
"Media": {
"Enabled": true
}
}
}
}
}
Basic endpoints
GET /umbraco/delivery/api/v2/content
GET /umbraco/delivery/api/v2/content/item/{id}
GET /umbraco/delivery/api/v2/content/item/{path}
GET /umbraco/delivery/api/v2/content?filter=contentType:blogPost
GET /umbraco/delivery/api/v2/media
TypeScript client
const UMBRACO_URL = process.env.UMBRACO_URL!;
async function getContent(params: {
filter?: string;
sort?: string;
take?: number;
skip?: number;
expand?: string;
fields?: string;
}) {
const query = new URLSearchParams();
if (params.filter) query.set('filter', params.filter);
if (params.sort) query.set('sort', params.sort);
if (params.take) query.set('take', String(params.take));
if (params.skip) query.set('skip', String(params.skip));
if (params.expand) query.set('expand', params.expand);
if (params.fields) query.set('fields', params.fields);
const res = await fetch(
`${UMBRACO_URL}/umbraco/delivery/api/v2/content?${query}`,
{ next: { revalidate: 3600 } }
);
return res.json();
}
// Get blog posts
const { items, total } = await getContent({
filter: 'contentType:blogPost',
sort: 'createDate:desc',
take: 12,
expand: 'properties[author,categories]',
});
Filters and sorting
// Filter by content type and date
filter: 'contentType:blogPost,createDate>2024-01-01'
// Filter by tag (if using Umbraco Tags)
filter: 'contentType:blogPost,properties.tags:javascript'
// Sorting
sort: 'createDate:desc'
sort: 'properties.sortOrder:asc'
// Expand for related items
expand: 'all'
expand: 'properties[heroImage,author]'
// Select specific fields
fields: 'properties[title,slug,excerpt,heroImage]'
Preview API
// Headers for Preview Mode
headers: {
'Api-Key': process.env.UMBRACO_PREVIEW_API_KEY!,
'Preview': 'true',
}
Custom Content Delivery Selector
// Extend API via C# for filtering
using Umbraco.Cms.Core.DeliveryApi;
public class PublishedDateSelector : IContentIndexHandler
{
public IEnumerable<IndexFieldValue> GetFieldValues(IContent content, string? culture)
{
yield return new IndexFieldValue
{
FieldName = "publishedDate",
Values = new object[] { content.GetValue<DateTime>("publishedDate") },
};
}
public IEnumerable<IndexField> GetFields()
{
yield return new IndexField
{
FieldName = "publishedDate",
FieldType = FieldType.Date,
VariesByCulture = false,
};
}
}
Next.js integration
// app/blog/page.tsx
export const revalidate = 3600;
export default async function BlogPage() {
const { items, total } = await getContent({
filter: 'contentType:blogPost',
sort: 'createDate:desc',
take: 12,
expand: 'properties[heroImage]',
});
return <BlogGrid posts={items} total={total} />;
}
Setting up Content Delivery API with Next.js frontend — 1–2 days.







