Skip to main content

ContentItem

Attach custom Markdown or HTML pages and external links to APIs, API Bundles, and API Portals.


Introduction

The ContentItem resource lets API Publishers enrich the API Portal with custom documentation and navigation links without modifying the portal's source code.

A ContentItem can be one of two things:

  • A Content page rendered inside the portal. Pages are written in Markdown and can include safe raw HTML.
  • A Link to an internal portal route or an external URL.

Each ContentItem is attached to a parent resource — an APIPortal, an API, or an APIBundle — which determines where it appears in the portal UI.

Typical use cases:

  • Document non-REST APIs (such as gRPC or GraphQL) that do not have an OpenAPI specification.
  • Add onboarding guides, tutorials, or FAQs next to an API or bundle.
  • Expose a "Contact us", "Status page", or "Changelog" link in the portal top navigation.
  • Provide a bundle-level overview page that describes the APIs it contains.

The ContentItem Object

The ContentItem object is a Kubernetes Custom Resource Definition (CRD).

A ContentItem must be declared in the same namespace as the parent resource it references. Cross-namespace parent references are not supported.

apiVersion: hub.traefik.io/v1alpha1
kind: ContentItem
metadata:
name: weather-overview
namespace: apps
spec:
title: Overview
order: 1
parentRef:
kind: APIBundle
name: weather-bundle
content: |
# Weather Bundle Overview

The Weather Bundle combines current conditions and forecast data in one
subscription. Use it to build dashboards, notification workflows, or
customer-facing weather experiences.

## Available plans

| Plan | Best for | Included limits |
| :--- | :------- | :-------------- |
| Standard Plan | Partner integrations and staging environments | 1 request per second and 10,000 requests per month |
| VIP Plan | High-volume production applications | 20 requests per second and 20,000 requests per month |

## Getting started with the Weather API

This tutorial walks you through your first request.

1. Create an API key from the **Settings** page.
2. Call `GET /forecast?city=Lyon`.
3. Read the response.
important

A ContentItem must define exactly one of content or link. Declaring both, or neither, is rejected by the Kubernetes admission controller.

Ordering

ContentItem entries attached to the same parent are sorted by order ascending (lowest first). When two items share the same order, the tie is resolved by namespace then name in alphabetical order.

At the portal level, custom content is always rendered after the built-in API catalog and Applications entries in the top navigation; order only controls the position of custom items relative to each other.

The behavior of a link is derived automatically from link.href:

link.hrefBehavior
Starts with / (relative URL)Opens in the same browser tab. Useful for linking to another page of the portal, for example a specific API.
Any other value (absolute URL)Opens in a new browser tab with rel="noopener noreferrer".

Content Support

Content pages are rendered as GitHub Flavored Markdown (GFM). The following Markdown elements are supported:

  • Headings, bold, italic, strikethrough, underline (++text++)
  • Inline code and fenced code blocks
  • Ordered and unordered lists
  • Tables
  • Links and images (via URL)
  • Block quotes

Nested ordered lists follow Markdown indentation rules. Indent child items so the child marker starts under the parent item's text. For example, a child item under 1. needs three leading spaces. Numbering patterns such as 1.1. or 1.2. are rendered as text, not as nested list markers.

1. Configure access
1. Create an API key
2. Store it securely
2. Send a request

Raw HTML can also be embedded in Markdown. HTML is parsed and sanitized before rendering to prevent cross-site scripting (XSS). The portal supports common safe HTML elements:

  • Text and structure elements such as <p>, <div>, <span>, <br>, <hr>, and <h1> through <h6>
  • Text formatting elements such as <strong>, <em>, <code>, <pre>, <kbd>, <samp>, <var>, <sub>, and <sup>
  • List and table elements such as <ul>, <ol>, <li>, <dl>, <dt>, <dd>, <table>, <thead>, <tbody>, <tr>, <th>, and <td>
  • Link and media elements such as <a>, <img>, <picture>, and <source>
  • Disclosure and annotation elements such as <details>, <summary>, <ruby>, <rp>, and <rt>

Unsafe HTML is removed during sanitization. <script> and <iframe> elements are stripped, event-handler attributes such as onclick or onerror are removed, and unsafe URL schemes such as javascript: or data: are rejected. Inline styling and unsupported attributes may also be removed, so avoid relying on custom CSS in portal content.

Where Content Appears in the Portal

The placement of a ContentItem in the portal is determined by the combination of its parentRef.kind and its type (Markdown page or link).

Attached to an APIPortal

TypeLocation
linkPortal top navigation bar, to the right of the API catalog and Applications entries.
contentPortal left sidebar, below the list of APIs and API Bundles.

Attached to an API or an APIBundle

Both Markdown pages and links attached to an API or an APIBundle are rendered as tabs in the API (or Bundle) page navigation, next to the default Documentation tab. Links follow the same same-tab vs. new-tab rule as portal-level links.

Custom content is shared across all versions of a versioned API. Attaching a ContentItem directly to an APIVersion is not supported.

https://portal.example.com
API Portal with Custom ContentAPI Portal with Custom Content

Configuration Examples

This example adds two items to the portal: a Markdown contact page (rendered in the left sidebar) and an external link to the company website (rendered in the top navigation bar, in a new tab).

APIPortal resource
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortal
metadata:
name: my-portal
namespace: apps
spec:
title: My Portal
description: API Developer Portal
trustedUrls:
- https://portal.example.com
https://portal.example.com
API Portal with Custom ContentAPI Portal with Custom Content

Document an API Without an OpenAPI Specification

When an API does not expose an OpenAPI specification — for example, a gRPC or GraphQL backend — a Markdown ContentItem can be used as its primary documentation page.

API resource without an OpenAPI specification
apiVersion: hub.traefik.io/v1alpha1
kind: API
metadata:
name: events-api
namespace: apps
spec:
title: Events API
https://portal.example.com
API Portal with Custom ContentAPI Portal with Custom Content

Add HTML to a Content Page

Use HTML when Markdown is not expressive enough for structured content such as collapsible sections, definition lists, or custom tables. HTML is still declared in the content field.

Markdown page with sanitized HTML
apiVersion: hub.traefik.io/v1alpha1
kind: ContentItem
metadata:
name: support-policy
namespace: apps
spec:
title: Support policy
order: 2
parentRef:
kind: APIPortal
name: my-portal
content: |
# Support policy

<p>Use this page to find the right support channel for your API consumers.</p>

<table>
<thead>
<tr>
<th>Plan</th>
<th>Response time</th>
</tr>
</thead>
<tbody>
<tr>
<td>Standard</td>
<td>Next business day</td>
</tr>
<tr>
<td>Enterprise</td>
<td>Four business hours</td>
</tr>
</tbody>
</table>

<details>
<summary>Escalation process</summary>
<p>Open a ticket with the impacted API, environment, and request ID.</p>
</details>
https://portal.example.com
API Portal with Custom ContentAPI Portal with Custom Content

Configuration Options

FieldDescriptionRequiredDefault
titlePublic-facing name of the content item. Displayed as the menu label in the portal. 1–253 characters.Yes
orderNon-negative integer (int32) that controls the display order. Items are sorted by order ascending, so lower values appear first.Yes
parentRef.kindKind of the parent resource. Must be one of APIPortal, API, or APIBundle.Yes
parentRef.nameName of the parent resource. The parent must exist in the same namespace as the ContentItem.Yes
contentMarkdown body of the page. Can include sanitized raw HTML. Up to 1,500,000 characters. Mutually exclusive with link.Conditional
link.hrefURL of the link. Must be a valid URL. Can be a relative path (for example /api-catalog/my-api@apps) or an absolute URL. Mutually exclusive with content.Conditional

Status

When Traefik Hub reconciles a ContentItem, it updates the status.conditions field. The ParentRefResolved condition reports whether the referenced parent resource exists in the same namespace.

kubectl describe contentitem contact-us -n apps

If the parent cannot be resolved, the ContentItem is ignored by the portal and the condition reports an error message. Check that:

  • The parentRef.kind is one of APIPortal, API, or APIBundle.
  • A parent resource with the given name exists in the same namespace as the ContentItem.
  • Learn more about APIPortal and how to configure the developer portal.
  • Learn more about the API object.
  • Learn more about the APIBundle object.
  • Read the API Portal Overview from a consumer's perspective.