Retrieve content in Xperience by Kentico

The approaches

ContentRetriever API is our primary API for fetching content. It includes many default settings that operate based on common scenarios and available Xperience context, such as automatic language selection, preview mode detection, secured content handling, and caching. You can easily override these defaults by providing parameters to the API.

The Content Item Query API is the underlying, low-level API used by ContentRetriever. Although it requires more development effort, it gives developers greater flexibility to customize content retrieval for specific scenarios.

Which approach to use

Always use ContentRetriever if possible. It:

  • Automatically resolves language, preview mode, and other request context for you
  • Allows for simple, more readable code
  • Provides built-in caching options, so you don’t need to set up IProgressiveCache yourself

Aim to use Content item query only for scenarios that ContentRetriever can’t cover, for example:

  • When your code runs outside a request tied to a specific website channel (e.g., background services, scheduled tasks), and you need to provide the website context, language and preview mode manually
  • You need to query items without knowing their concrete content types in advance (for example, mixed-type results from a Combined content selector) and don’t want to maintain/provide a list of every single content type to RetrieveContentOfContentTypes

Encode this decision logic into your repository’s instruction files for AI coding assistants (e.g., a *.instructions.md file scoped to **/*.cs). The Kentico Community Portal does this in its Xperience.instructions.md, which simply states: “Use the Kentico.Content.Web.Mvc.IContentRetriever interface when querying for content.”

A rule like this helps agents default to ContentRetriever instead of suggesting older or lower-level APIs.

The more ContentRetriever usage already exists in your codebase, the more context the agent has to follow the convention on its own.

Content retrieval in the Training guides repo

Our example Training guides repository centralizes content retrieval behind custom IContentItemRetrieverService, and that service builds nearly all of its methods on top of ContentRetriever.

This keeps the benefits described above – built-in caching, less boilerplate, and consistent default behavior for language, preview mode, and secured items – centralized in one place, so you don’t need to reimplement retrieval logic across all viewcomponents and controllers.

The main trade-off shows up when a page’s specific content type isn’t known ahead of time, such as when resolving a Combined content selector value that allows more than one content type. RetrieveWebPageByContentItemGuid has two overloads for this: a generic one that uses ContentRetriever directly once the concrete page type is known, and a non-generic one that falls back to the lower-level ContentItemQueryBuilder, since ContentRetriever’s generic methods require a concrete registered content type and won’t accept the shared IWebPageFieldsSource interface.

Anti-patterns to avoid

  • Re-implementing caching ContentRetriever already provides. Wrapping ContentRetriever calls in your own IProgressiveCache logic duplicates work the API already performs through its RetrievalCacheSettings parameter, and risks inconsistent cache keys or dependencies.
  • Requesting more linked item depth than a view actually uses. A high depth/LinkedItemsMaxLevel value resolves and maps linked content several levels deep, even if only the top-level fields end up rendered.
  • Mapping full content type fields when only shared schema fields are needed. When a query targets a reusable field schema and doesn’t use any type-specific fields, set IncludeContentTypeFields to false to skip mapping data your code won’t use.

For a real-world example of a content model that leans heavily on reusable field schemas, see Training guides commerce schemas.

What’s next

With these approaches in mind, see how the Training guides repository puts them to use in custom IContentItemRetrieverService.