---
title: ContentRetriever API
related:
  - https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/reference-content-retriever-api.md
  - https://docs.kentico.com/documentation/developers-and-admins/development/content-retrieval.md
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

`IContentRetriever` provides a unified API to fetch various types of content managed by Xperience from within web applications. It's intended as the primary service for the retrieval of:

- Pages
- Reusable content items
- Content that shares [reusable field schemas](https://docs.kentico.com/documentation/developers-and-admins/development/content-types/reusable-field-schemas.md)

The simplest way to use `IContentRetriever` is directly calling each method with the default settings, which are optimized for most common scenarios:

```csharp title="Retrieve the current page"
using Kentico.Content.Web.Mvc;

// ...

// Retrieves the current page
var currentPage = await contentRetriever.RetrieveCurrentPage<HomePage>();
```

```csharp title="Retrieve pages of a specific content type"
using Kentico.Content.Web.Mvc;

// ...

// Retrieves all pages of a specific content type
var articles = await contentRetriever.RetrievePages<ArticlePage>();
```

```csharp title="Retrieve reusable content items"
using Kentico.Content.Web.Mvc;

// ...

// Retrieves content items by content type
var testimonials = await contentRetriever.RetrieveContent<TestimonialItem>();
```

Functionally, the API serves as an abstraction layer over [content query](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/content-item-query-api.md), where it handles common retrieval scenarios by providing default, recommended configuration for various aspects like [query construction](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/content-item-query-api.md#build-queries), [language fallback](https://docs.kentico.com/documentation/developers-and-admins/configuration/languages.md#language-fallbacks) handling, and [linked item retrieval](https://docs.kentico.com/documentation/developers-and-admins/development/content-retrieval/retrieve-content-items.md#retrieve-linked-content-items). However, it also provides developers the option to override these defaults by exposing parts of the retrieval lifecycle (e.g., query construction, model mapping) via function delegates.

This page introduces concepts shared by all methods available on the service, together with relevant examples. For a complete method reference, see [Reference - ContentRetriever API](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/reference-content-retriever-api.md).

> **Tip:** **AI-assisted content retrieval**
>
> Use [KentiCopilot](https://docs.kentico.com/guides/development/kenticopilot.md) when you write, review, or troubleshoot retrieval code. The `content-retrieval` skill in the [web development plugin](https://github.com/Kentico/xperience-by-kentico-kenticopilot/tree/main/plugins/kentico-web-development) helps the agent choose between the ContentRetriever API and the lower-level [content item query API](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/content-item-query-api.md), pick the correct selector identifier type, and account for [caching](https://docs.kentico.com/documentation/developers-and-admins/development/caching.md), linked-item depth, projection, and paging.

## Shared aspects of the API

### Configurable retrieval behavior

`IContentRetriever` method overloads accept an optional parameter object, named according to the retrieval scenario (e.g., [RetrieveCurrentPageParameters](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/reference-content-retriever-api.md#retrieve-the-current-page), [RetrievePagesParameters](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/reference-content-retriever-api.md#retrieve-pages-of-a-single-content-type)). These objects allow you to configure the high-level behavior and scope of the content retrieval operation. They primarily control how and under what context data is fetched.

These parameter objects define behavior such as:

- The desired [content language](https://docs.kentico.com/documentation/developers-and-admins/configuration/languages.md) (`LanguageName`, `UseLanguageFallbacks`).
- Whether to retrieve preview or live content (`IsForPreview`).
- The depth of linked content to include (`LinkedItemsMaxLevel`).
- Whether [content type fields](https://docs.kentico.com/documentation/developers-and-admins/development/content-types.md#add-fields) are included in the results (`IncludeContentTypeFields`).
- Whether to include content items requiring [authentication](https://docs.kentico.com/documentation/business-users/website-content/secure-pages.md) (`IncludeSecuredItems`).
- Whether URL path data is included in the query (`IncludeUrlPath`). For more information, see [URL retrieval behavior](#url-retrieval-behavior).
- Scope limitations like specific [content tree paths](https://docs.kentico.com/documentation/developers-and-admins/development/content-retrieval/retrieve-page-content.md#filter-pages-based-on-content-tree-structure) (`PathMatch`) or [workspaces](https://docs.kentico.com/documentation/developers-and-admins/configuration/users/role-management/workspaces.md) (`WorkspaceNames`).

When you call a retriever method without providing a specific parameters object – often by using the simpler extension method overloads – or if you provide a default instance (`new RetrieveCurrentPageParameters()` for example), the API uses sensible defaults.

These defaults are designed for the most common use cases, typically relying on the current request's context (e.g., using the detected preferred language, respecting the current preview mode status) and opting for safer, less resource-intensive settings (like `LinkedItemsMaxLevel = 0` and `IncludeSecuredItems = false`). This results in concise and performant queries.

The flexibility of this approach is in overriding the defaults when instantiating these objects. This allows you to tailor the retrieval to specific requirements. For example:

- You might need to display content in a specific language regardless of the user's preference:
  ```csharp noheader
  new RetrievePagesParameters { LanguageName = "spanish" }
  ```

- You might need to fetch related items linked from a main article:
  ```csharp noheader
  new RetrieveCurrentPageParameters { LinkedItemsMaxLevel = 1 }
  ```

- You might need to ensure you're always getting the latest, unpublished content:
  ```csharp noheader
  new RetrieveContentParameters { IsForPreview = true }
  ```

- You might need to retrieve pages only within a specific section of the site:
  ```csharp noheader
  new RetrievePagesParameters { PathMatch = PathMatch.Children("/products") }
  ```

- You might want to omit page URL data to improve performance when URLs are not needed:
  ```csharp noheader
  new RetrievePagesParameters { IncludeUrlPath = false }
  ```

By using these parameter objects, you gain explicit control over the retrieval context and scope, ensuring the retriever fetches the right content based on your application's requirements, rather than relying on provided defaults.

All `*Parameters` objects also include a `Default` property. This property provides a default instance of the specific parameter type when no custom configuration is needed. Useful when a configuration action is syntactically required but no additional configuration is necessary (for instance, when using certain advanced overloads of the available methods). However, note that the default object is only populated in certain scenarios, see: [Request context requirements](#request-context-requirements).

### Optional query configuration

Certain overloads of `IContentRetriever` methods accept an `additionalQueryConfiguration` parameter. This parameter allows you to directly configure the underlying [content query builder](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/content-item-query-api.md#build-queries) instance, providing advanced control over the database query construction beyond what is possible using the [retrieval parameters](#configurable-retrieval-behavior) described above.

You can use this to apply various query modifications, such as:

- **Filtering** – limiting results using [Where](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/reference-content-item-query.md#where) conditions.

- **Sorting** – defining [OrderBy](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/reference-content-item-query.md#orderby) clauses.

- **Projection** – specifying exact database columns to retrieve using [Columns](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/reference-content-item-query.md#columns).

  > **Note:** **Security considerations**
  >
  > Column expressions in `Columns`, `OrderBy`, and the left-hand column operands in `Where` methods are not parameterized against SQL injection. Only use trusted, developer-controlled values. If these values originate from external input, validate them against an allowlist. See [Protect against SQL injection](https://docs.kentico.com/documentation/developers-and-admins/api/objectquery-api.md#protect-against-sql-injection) (the principles described for the ObjectQuery API apply).

- **Paging** – limits results using:
  - [TopN](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/reference-content-item-query.md#topn) – returns only the first `N` records according to the specified order. Cannot be combined with `Offset`.
  - [Offset](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/reference-content-item-query.md#offset) – skips the first `offset` records and then retrieves the next `fetch` records. This is the recommended method for implementing paging and requires an `OrderBy` clause to ensure consistent results. Cannot be combined with `TopN`.

- **Linked items configuration** – options for retrieving [linked items](https://docs.kentico.com/documentation/business-users/content-hub/content-items.md#link-content-items) via [WithLinkedItems](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/reference-content-item-query.md#withlinkeditems). Linked item depth is reflected from the corresponding [method configuration object](#configurable-retrieval-behavior).

- **Method-specific options** – certain configuration options are unique to specific methods. For example:
  - [UrlPathColumns()](#optimize-retrieved-data-for-url-generation) is available only for page queries. It keeps the database columns required for URL resolution when you limit retrieval via `Columns()`.
  - [InSmartFolder()](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/reference-content-item-query.md#insmartfolder) is available only for content item queries.

Query configuration objects are named according to the corresponding retrieval method (e.g., `RetrieveCurrentPageQueryParameters`, `RetrievePagesQueryParameters`, `RetrieveContentQueryParameters`). All `*QueryParameters` objects also include a `Default` property. This property provides a default instance of the specific parameter type when no custom configuration is needed. Useful when a configuration action is syntactically required but no additional configuration is necessary (for instance, when using certain advanced overloads of the available methods).

### URL retrieval behavior

By default, `IContentRetriever` includes URL path data for every page it retrieves, including pages retrieved by content item methods such as `RetrieveContentByGuids`. The `IncludeUrlPath` property of the [retrieval parameter objects](#configurable-retrieval-behavior) controls this behavior:

- `IncludeUrlPath = true` (default) – enables page URL retrieval via [GetUrl()](https://docs.kentico.com/documentation/developers-and-admins/development/content-retrieval/retrieve-page-content/retrieve-page-urls.md#using-the-geturl-extension-method). The [IWebPageUrlRetriever](https://docs.kentico.com/documentation/developers-and-admins/development/content-retrieval/retrieve-page-content/retrieve-page-urls.md#using-the-iwebpageurlretriever-interface) overloads that accept a page object also use the prefetched URL path.
- `IncludeUrlPath = false` – omits URL path data from the query, which improves query performance. Calling `GetUrl()` on the results throws an exception. To get the URLs of these pages, use the `IWebPageUrlRetriever` overloads that accept a page identifier, which query the database.

URL path data applies only to pages – reusable content items have no URL paths. Pages retrieved as linked items (via `LinkedItemsMaxLevel`) always include URL path data, regardless of `IncludeUrlPath`.

For further URL customization, such as column selection and URL language behavior, use the [additionalQueryConfiguration delegate](#optional-query-configuration).

#### Optimize retrieved data for URL generation

To improve query performance when you only need page URLs (for example, for navigation menus or sitemaps), limit the retrieved columns using `Columns()` in `additionalQueryConfiguration` and call `UrlPathColumns()`. Calling `Columns()` alone can exclude columns required to build page URLs. `UrlPathColumns()` keeps those columns in the selection.

`UrlPathColumns()` is available for page queries only. The method selects the URL path data added by `IncludeUrlPath`, so keep `IncludeUrlPath` set to `true` (the default) when calling it.

```csharp title="Retrieve pages optimized for URL generation" highlight="8-10"
using Kentico.Content.Web.Mvc;

// ...

var pagesWithUrlsOnly = await contentRetriever.RetrievePages<ArticlePage>(
    parameters: RetrievePagesParameters.Default,
    // Retrieves the title and all columns required for URL resolution
    additionalQueryConfiguration: query => query
              .Columns("ArticleTitle")
              .UrlPathColumns(),
    cacheSettings: new RetrievalCacheSettings(
        cacheItemNameSuffix:
            $"{nameof(RetrievePagesQueryParameters.Columns)}|ArticleTitle|" +
            $"{nameof(RetrievePagesQueryParameters.UrlPathColumns)}"
        )
);
```

[GetUrl()](https://docs.kentico.com/documentation/developers-and-admins/development/content-retrieval/retrieve-page-content/retrieve-page-urls.md#using-the-geturl-extension-method) works only with prefetched data and never queries the database. If you limit columns without calling `UrlPathColumns()`, `GetUrl()` throws an exception.

#### Control URL language with fallbacks

When a page is served in a [fallback language](https://docs.kentico.com/documentation/developers-and-admins/configuration/languages.md#language-fallbacks), its URL can follow either the requested language or the fallback language. By default, `IContentRetriever` builds the URL in the requested language (`UrlLanguageBehavior.UseRequestedLanguage`). To build URLs in the language of the retrieved content instead, call `SetUrlLanguageBehavior(UrlLanguageBehavior.UseFallbackLanguage)` in the `additionalQueryConfiguration` delegate.

> **Note:** **Language-specific domains**
>
> When using `UrlLanguageBehavior.UseFallbackLanguage` with channels that use [language-specific domains](https://docs.kentico.com/documentation/developers-and-admins/configuration/languages.md#content-languages-and-channel-url-formats), use the absolute URL of the retrieved page. Relative URLs don't include the host, which can cause the fallback URL to resolve incorrectly.

For the available language behaviors and a full example, see [URL language behavior](https://docs.kentico.com/documentation/developers-and-admins/development/content-retrieval/retrieve-page-content/retrieve-page-urls.md#url-language-behavior).

### Omit content type fields

By default, retriever methods include [content type-specific fields](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/content-item-database-structure.md#content-items) in their queries. Set `IncludeContentTypeFields` to `false` in the parameters object to omit those fields. Use this option when your code only needs data shared by all retrieved items.

```csharp title="Retrieve items of a reusable field schema without content type fields" highlight="8"
using Kentico.Content.Web.Mvc;

// ...

var schemaNames = new[] { IMetadataFields.REUSABLE_FIELD_SCHEMA_NAME };
var items = await contentRetriever.RetrieveContentOfReusableSchemas<IMetadataFields>(
    schemaNames,
    parameters: new RetrieveContentOfReusableSchemasParameters { IncludeContentTypeFields = false }
);
```

The results still contain:

- Content item metadata from the [CMS\_ContentItem table](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/content-item-database-structure.md#content-items)
- [Reusable field schema](https://docs.kentico.com/documentation/developers-and-admins/development/content-types/reusable-field-schemas.md) fields
- Page URL data
- The concrete content type of each item

Only [content type fields](https://docs.kentico.com/documentation/developers-and-admins/development/content-types.md#add-fields) are omitted – the ones stored in the content type's [ContentItemData table](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/content-item-database-structure.md#content-items). If the model you retrieve into declares such fields, they remain unpopulated.

The gain is largest when you retrieve items by reusable field schema. Every content type has its own ContentItemData table. With content type fields included, the query combines the tables of all content types that use the schema, so the cost grows with each content type added to the schema. Without them, the query stays flat.

Unlike [query modifications](#optional-query-configuration) such as `Columns()` or `UrlPathColumns()`, this parameter needs no `cacheItemNameSuffix`. The system includes the parameter in the generated cache key, so the two variants never share a cache entry.

### Implicit result caching

The `IContentRetriever` API supports implicit result [caching](https://docs.kentico.com/documentation/developers-and-admins/development/caching/data-caching.md). By default, caching is enabled for all retrieval methods unless explicitly disabled using `RetrievalCacheSettings.CacheDisabled`.

You can configure [caching behavior](https://docs.kentico.com/documentation/developers-and-admins/development/caching/data-caching.md#cache-reusable-content-items-and-pages) using the `RetrievalCacheSettings` parameter. This parameter allows you to:

- **Enable or disable caching** – Use `RetrievalCacheSettings.CacheDisabled` to disable caching for specific retrieval operations.
- **Set cache item name suffix** – If you [modify the default query](#optional-query-configuration) used when retrieving data, you must ensure a unique cache item name for the data via a suffix appended to the cache key. See [Ensure unique cache keys](#ensure-unique-cache-keys).
- **Set cache expiration** – Specify the cache expiration time using the `CacheExpiration` property.
- **Use sliding expiration** – Enable sliding expiration by setting `UseSlidingExpiration` to `true`.
- **Add additional cache dependencies** – Use the `AdditionalCacheDependencies` property to define custom dependencies for cache invalidation.

#### Default cache settings

- The default cache expiration time is set to **10** minutes. This value is used when no specific expiration is provided in `RetrievalCacheSettings`. You can set a default expiration time globally for all requests made via the content retriever API using `ContentRetrieverCacheOptions`. See [Set global cache expiration time](#set-global-cache-expiration-time).
- Sliding expiration is **disabled** by default, meaning the cache duration is fixed and doesn't get extended when the cached item is accessed.
- Data retrieved for preview is never cached, regardless of the cache settings.

#### Configure custom cache settings

```csharp title="Use custom caching configurations" highlight="11-16,21"
using System;

using CMS.ContentEngine;

using Kentico.Content.Web.Mvc;

// ...

// Configures cache settings with a 30-minute expiration and sliding expiration enabled
var cacheSettings = new RetrievalCacheSettings(
    // Adds a unique suffix to identify the cached data
    cacheItemNameSuffix: $"{nameof(ContentTypesQueryParameters.OfContentType)}|ArticleGenerated",
    // Expires cache entries 30 minutes after their last access
    cacheExpiration: TimeSpan.FromMinutes(30),
    // Resets the expiration timer on each access to keep frequently accessed items in the cache
    useSlidingExpiration: true);

var result = await contentRetriever.RetrieveCurrentPage<ArticleGenerated>(
    parameters: RetrieveCurrentPageParameters.Default,
    additionalQueryConfiguration: RetrieveCurrentPageQueryParameters.Default,
    cacheSettings: cacheSettings
);
```

#### Disable result caching

```csharp title="Disable caching for queries" highlight="9"
using Kentico.Content.Web.Mvc;

// ...

var result = await contentRetriever.RetrieveCurrentPage<ArticleGenerated>(
    parameters: RetrieveCurrentPageParameters.Default,
    additionalQueryConfiguration: RetrieveCurrentPageQueryParameters.Default,
    // Disables result caching for the query
    cacheSettings: RetrievalCacheSettings.CacheDisabled
);
```

#### Ensure unique cache keys

When you use the `additionalQueryConfiguration` parameter to customize the query, you must provide a `cacheItemNameSuffix` in `RetrievalCacheSettings`. This suffix ensures that the cache key is unique for your specific query variation, as the system **does not** reflect the additional query configuration in the final constructed cache item name.

A recommended pattern for the suffix is to combine the name of the query configuration object with a string representation of its parameters. For example:

```csharp title="Ensure unique cache item names for parameterized queries" highlight="8-10,15-17"
using Kentico.Content.Web.Mvc;

// ...

var cacheSettings = new RetrievalCacheSettings(
    // Constructs a unique suffix by combining the string representation of the parameter values
    // so that different query configurations result in different cache keys
    cacheItemNameSuffix:
        $"{nameof(RetrievePagesQueryParameters.Columns)}|ArticleTitle|" +
        $"{nameof(RetrievePagesQueryParameters.TopN)}|3"
);

var articles = await contentRetriever.RetrievePages<ArticlePage>(
    parameters: RetrievePagesParameters.Default,
    additionalQueryConfiguration: query => query
        .Columns("ArticleTitle")
        .TopN(3),
    cacheSettings: cacheSettings
);
```

Generate suffixes deterministically. The same query configuration must always produce the same suffix, and different configurations must produce different suffixes. Otherwise, identical results get cached repeatedly under different keys, or distinct results collide under a single key.

In requests that don't modify the retrieval query in any way, the suffix can be defined as an empty string.

For the values that the system automatically includes in generated cache keys, see [IContentRetriever cache settings](https://docs.kentico.com/documentation/developers-and-admins/development/caching/data-caching.md#icontentretriever-cache-settings).

#### Set global cache expiration time

Results returned by the API are by default cached for 10 minutes, unless overridden directly at the point of the retrieval operation by a specific instance of `RetrievalCacheSettings`. You can set this default caching period using `ContentRetrieverCacheOptions` and the [options pattern](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options).

```csharp title="Program.cs - Set global cache expiration time" highlight="16"
using System;

using Kentico.Content.Web.Mvc;

using Microsoft.Extensions.DependencyInjection;

// ...

// Sets the global default cache expiration for IContentRetriever instances.
// This value is used if no specific RetrievalCacheSettings.CacheExpiration is provided
// at the point of a retrieval operation, allowing for both global defaults and granular overrides.
builder.Services.Configure<ContentRetrieverCacheOptions>(options =>
{
    // Sets the default cache duration to 30 minutes.
    // Individual IContentRetriever calls can override this via RetrievalCacheSettings.
    options.DefaultCacheExpiration = TimeSpan.FromMinutes(30);
});
```

#### Gather generated cache dependencies

The `IContentRetriever` API automatically collects generated [cache dependencies](https://docs.kentico.com/documentation/developers-and-admins/development/caching/cache-dependencies.md) for all retrieved items. This is achieved using the `CacheDependencyCollector` class, which operates in a scoped context. You can access the collected dependencies by creating an instance of `CacheDependencyCollector` and calling its `GetCacheDependency()` method.

This is particularly useful when you have a broader caching strategy that needs to incorporate the dependencies of data fetched by multiple content retriever calls. For example, you can disable caching for individual requests, collect cache dependencies generated for the retrieved data, and use them as dependencies in a broader cached section.

```csharp title="Gather cache dependencies using CacheDependencyCollector" highlight="8,19,26,33"
using CMS.Helpers;

using Kentico.Content.Web.Mvc;

// ...

// Initializes a new collector scope
using (var dependencyCollector = new CacheDependencyCollector())
{
    // Caches the combined data of the outer section for 10 minutes under the 'PageWithArticlesData' key
    var cacheSettings = new CacheSettings(cacheMinutes: 10, cacheItemNameParts: "PageWithArticlesData");

    var cachedData = await progressiveCache.LoadAsync(async (cs) =>
    {
        var page = await contentRetriever.RetrieveCurrentPage<Home>(
            parameters: RetrieveCurrentPageParameters.Default,
            additionalQueryConfiguration: RetrieveCurrentPageQueryParameters.Default,
            // Disables caching for the request
            cacheSettings: RetrievalCacheSettings.CacheDisabled
        );

        var relatedArticles = await contentRetriever.RetrievePages<ArticlePage>(
            parameters: RetrievePagesParameters.Default,
            additionalQueryConfiguration: RetrievePagesQueryParameters.Default,
            // Disables caching for the request
            cacheSettings: RetrievalCacheSettings.CacheDisabled
        );

        // Gets the combined dependencies from all IContentRetriever calls
        // within the CacheDependencyCollector's scope up until this point.
        // The current set of dependencies continues to accumulate
        // until the parent scope gets disposed.
        cs.CacheDependency = dependencyCollector.GetCacheDependency();

        // ...
    }, cacheSettings);
}
```

The collector also supports nested scopes. If you create multiple `CacheDependencyCollector` instances in a nested fashion (e.g., within a method that calls another method, both using a collector), dependencies from inner scopes are automatically propagated to outer scopes upon disposal of the inner collector.

You can also use the `CacheDependencyCollector.AddCacheDependency(CMSCacheDependency dependency)` method to manually add dependencies to the current scope. Call the method from inside an initialized collector scope. Otherwise, the method throws an `InvalidOperationException`.

### Request context requirements

Certain `IContentRetriever` method parameters (`ChannelName`, `LanguageName`, `IsForPreview`) can be detected automatically when the request's domain matches a configured [website channel](https://docs.kentico.com/documentation/developers-and-admins/configuration/website-channel-management.md).

```csharp title="Automatic context detection"
using Kentico.Content.Web.Mvc;

// ...

// Callable from any route where request domain
// matches an existing website channel domain.
var articles = await contentRetriever.RetrievePages<ArticlePage>();
```

Additionally, the `RetrieveCurrentPage` method is only intended to be called from inside code handled by [content tree-based routing](https://docs.kentico.com/documentation/developers-and-admins/development/routing/content-tree-based-routing.md), which provides all required parameters for the retrieval (page ID, etc.).

```csharp title="RetrieveCurrentPage context requirements"
using Kentico.Content.Web.Mvc;

// ...

// Callable from code handled by content tree-based routing
var currentPage = await contentRetriever.RetrieveCurrentPage<HomePage>();
```

When automatic detection is not possible, you need to provide these parameters explicitly:

```csharp title="Specify context parameters explicitly"
using Kentico.Content.Web.Mvc;

// ...

var articles = await contentRetriever.RetrievePages<ArticlePage>(
    new RetrievePagesParameters
    {
        ChannelName = "MyWebsite",
        LanguageName = "en",
        IsForPreview = false
    }
);
```

Explicit parameterization is needed when:

- Request domain does not match any configured [website channel](https://docs.kentico.com/documentation/business-users/website-content.md).
- Executing code in background jobs or [scheduled tasks](https://docs.kentico.com/documentation/developers-and-admins/customization/scheduled-tasks.md).
- Running code in [console applications or CLI tools](https://docs.kentico.com/documentation/developers-and-admins/api/use-the-xperience-by-kentico-api-externally.md).

If context cannot be detected automatically, the API throws an `InvalidOperationException` with messages such as:

- "The HTTP context is not available. Ensure that the `IContentRetrieverWebsiteContextProvider` is used within a valid HTTP request context."
- "Website data context could not be retrieved. Parameters `ChannelName`, `LanguageName`, and `IsForPreview` need to be specified manually."

### Custom model mapping

The `IContentRetriever` API provides flexible model mapping capabilities that support both registered content types and custom model classes. The underlying model mapping system uses the following priority:

1. **Registered content types** – If a model type is registered for the content type via [RegisterContentTypeMappingAttribute](https://docs.kentico.com/documentation/developers-and-admins/api/generate-code-files-for-system-objects.md#registercontenttypemapping-attribute) and your target model type (provided via the generic method parameter) is assignable from the registered type, the registered type is used for mapping.

2. **Direct model mapping** – If no registered type is found or it's not assignable, your specified model type is used directly for mapping. The model must be a non-abstract class, struct, or record with a parameterless constructor. The API attempts automatic mapping to your specified model, using case-insensitive property matching with the columns retrieved by the query. This flexibility allows you to use any custom, simplified models containing only the properties you need.

![Content retriever default model mapping flow](https://docs.kentico.com/docsassets/documentation/content-retriever-api/ContentRetrieverDefaultMapping.png "Content retriever default model mapping flow")

#### Custom mapping with configureModel delegate

Additionally, `IContentRetriever` method overloads include an optional `configureModel` parameter, which allows you to inject custom logic into the model mapping pipeline for even more advanced scenarios.

![Content retriever model mapping flow with 'configureModel'](https://docs.kentico.com/docsassets/documentation/content-retriever-api/ContentRetrieverCustomMappingFlow.png "Content retriever model mapping flow with 'configureModel'")

The parameter has the following signature:

```csharp noheader
Func<IContentQueryDataContainer, TInput, Task<TResult>> configureModel;
```

This parameter gives you control over how the retrieved data is mapped to your resulting model class.

- `IContentQueryDataContainer` – contains the database row (page, content item) being mapped. You can access column values via `GetValue<TValue>(string columnName)`.
- `TInput` – the intermediate mapped object. This could be either a registered content type model or your custom model type, depending on the mapping priority. For example, when calling:

  ```csharp noheader
  contentRetriever.RetrievePages<ArticleGenerated>()
  ```

  `TInput` contains an instance of `ArticleGenerated` for each mapped item from the result set. You can use this intermediate representation to fetch the data, run additional transformations (combining fields, or enriching the model with external data) and any other custom logic.
- `TResult` – the final type you want to return from the content retrieval operation. This is the type of object that your `configureModel` delegate creates and returns.

> **Tip:** See the [Run queries and map the result](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/content-item-query-api.md#run-queries-and-map-the-result) documentation to learn about the content item query model mapping lifecycle. `IContentRetriever` methods simply expose certain parts of the lifecycle.

#### Direct model mapping without registration

You can use any custom model class directly without needing to register it using `RegisterContentTypeMappingAttribute`. If you leave `configureModel` as `null`, the content retriever attempts automatic mapping to your specified model type, using case-insensitive property matching with the columns retrieved by the query. This works for both [generated model classes](https://docs.kentico.com/documentation/developers-and-admins/api/generate-code-files-for-system-objects.md) and custom classes that match the underlying content type structure.

```csharp title="Direct mapping to a custom model class"
using System;

using Kentico.Content.Web.Mvc;

// ...

// Custom model class without content type registration
public class SimpleArticle
{
    public string Title { get; set; }
    public string Summary { get; set; }
    public DateTime PublishedDate { get; set; }
}

var contentTypes = new[] { ArticlePage.CONTENT_TYPE_NAME, BlogPage.CONTENT_TYPE_NAME };

// Direct mapping to custom model 'SimpleArticle' that does not need to be registered
var articles = await contentRetriever.RetrievePagesOfContentTypes<SimpleArticle>(contentTypes);
```

```csharp title="Direct mapping to a generated class"
using Kentico.Content.Web.Mvc;

// ...

// 'ArticleGenerated' is a model class generated by Xperience
// Works the same way as before - uses registered mapping if available
var articles = await contentRetriever.RetrievePages<ArticleGenerated>();
```

#### Advanced mapping with configureModel delegate

For more complex scenarios, you can provide a custom mapping function using the `configureModel` delegate. This function receives the raw data for each retrieved item and the intermediate mapped object, allowing you to implement custom transformation logic.

```csharp title="Advanced mapping with configureModel delegate"
using Kentico.Content.Web.Mvc;

// ...

// Custom view model for complex transformations
public class CustomArticleViewModel 
{ 
    public string PageTitle { get; set; }
    public string PageAdminTitle { get; set; }
    public string FormattedDate { get; set; }
}

// Using configureModel for complex transformations
// TInput could be either a registered model or custom model based on mapping priority
var customViewModels = 
    await contentRetriever.RetrievePages<SimpleArticle, CustomArticleViewModel>(
        parameters: new RetrievePagesParameters(),
        additionalQueryConfiguration: null,
        cacheSettings: RetrievalCacheSettings.CacheDisabled,
        configureModel: async (container, mappedResult) =>
        {
            // 'mappedResult' is the intermediate SimpleArticle object
            // 'container' provides access to raw database data
            return new CustomArticleViewModel
            {
                PageTitle = mappedResult.Title ?? "Default Title",
                PageAdminTitle = container.GetValue<string>("WebPageItemName"),
                FormattedDate = mappedResult.PublishedDate.ToString("MMM dd, yyyy")
            };
        }
);
```

> **Tip:** See [Usage scenarios](#usage-scenarios) for common use cases and recommendations for when to use either approach.

This mechanism offers flexibility, allowing simple mapping for standard cases and complex, custom transformations for advanced scenarios.

#### Usage scenarios

##### Direct mapping to custom models

- _Use case:_ Using custom model classes without requiring content type registration. Create simplified models with only the properties you need, or use models that don't exactly match the content type structure.
- _Approach:_ Use methods like `contentRetriever.RetrieveCurrentPage<YourCustomClass>()` directly. The model must be a non-abstract class with a parameterless constructor.

##### Simple direct mapping to registered models

- _Use case:_ Retrieving content directly into [generated model classes](https://docs.kentico.com/documentation/developers-and-admins/api/generate-code-files-for-system-objects.md) or other registered content type models when your class structure matches the content type fields.
- _Approach:_ Use methods like `contentRetriever.RetrieveCurrentPage<YourRegisteredClass>()`.

##### Small adjustments or conformance to shared models (Minimal custom mapping)

- _Use case:_ Making small changes like formatting dates, providing default values, renaming properties for view models, or when the intermediate mapped object needs slight modifications.
- _Approach:_ Use the `configureModel` delegate with simple transformations or object-to-object mapping.

##### Complex transformations and custom view models (Extensive custom mapping)

- _Use case:_ Transforming fetched content into view models with significantly different structures, combining multiple source fields, performing calculations or conditional logic, or accessing data not directly available through standard mapping.
- _Approach:_ Leverage the `configureModel` delegate extensively to build your target C# object with full control over the transformation process.

### Use shared types for bulk content retrieval

[Generated model classes](https://docs.kentico.com/documentation/developers-and-admins/api/generate-code-files-for-system-objects.md#icontentitemfieldssource-interfaces) implement shared interfaces that provide access to system properties:

- [Page content type model classes](https://docs.kentico.com/documentation/developers-and-admins/api/generate-code-files-for-system-objects.md) implement `IWebPageFieldsSource`
- [Reusable content type model classes](https://docs.kentico.com/documentation/developers-and-admins/api/generate-code-files-for-system-objects.md) implement `IContentItemFieldsSource`

However, the way `IContentRetriever` methods work with these interfaces depends on how content types are identified and resolved during retrieval operations.

The following `IContentRetriever` methods:

- `RetrievePages`
- `RetrievePagesByGuids`
- `RetrieveContent`
- `RetrieveContentByGuids`

determine the target content type from the provided generic. This identification happens through the [RegisterContentTypeMappingAttribute](https://docs.kentico.com/documentation/developers-and-admins/api/generate-code-files-for-system-objects.md#registercontenttypemapping-attribute) present on [generated model classes](https://docs.kentico.com/documentation/developers-and-admins/api/generate-code-files-for-system-objects.md).

Since `IWebPageFieldsSource` and `IContentItemFieldsSource` are shared interfaces without specific content type mappings, using them directly as generic type parameters is not supported by these methods. The system cannot determine which specific content type to retrieve:

```csharp title="Unsupported approaches"
using CMS.ContentEngine;
using CMS.Websites;

using Kentico.Content.Web.Mvc;

// ...

// Not supported -- no content type can be determined
var pages = await contentRetriever.RetrievePages<IWebPageFieldsSource>();
var content = await contentRetriever.RetrieveContent<IContentItemFieldsSource>();
```

#### Multi-content type page retrieval with RetrieveAllPages

When you need to retrieve pages across multiple content types without knowing the specific types at compile time, use the `RetrieveAllPages` method. This method retrieves all web pages that match the specified [parameterization](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/reference-content-retriever-api.md#retrieve-all-pages):

```csharp title="Retrieve all page content types" highlight="11"
using System.Collections.Generic;

using CMS.Websites;

using Kentico.Content.Web.Mvc;

// ...

// Retrieves all page content types matching the specified criteria
IEnumerable<IWebPageFieldsSource> allPages =
    await contentRetriever.RetrieveAllPages<IWebPageFieldsSource>(
        new RetrieveAllPagesParameters 
        {
            LanguageName = "en-US",
            PathMatch = PathMatch.Children("/articles")
        }
);
```

#### Retrieve pages by GUIDs across content types

When you need to retrieve pages of any content type by specific GUIDs, use the [RetrieveAllPagesByGuids](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/reference-content-retriever-api.md#retrieve-all-pages-by-guids) method:

```csharp title="Retrieve pages by GUIDs across all content types" highlight="10-12"
using CMS.Websites;

using Kentico.Content.Web.Mvc;

// ...

// A collection of page GUIDs (typically obtained from Page selector)
var webPageItemGuids = new[] { guid1, guid2, guid3 };

var pagesByGuids = await contentRetriever.
    RetrieveAllPagesByGuids<IWebPageFieldsSource>(
        webPageItemGuids);
```

The method automatically sets up cache dependencies based on the provided GUIDs.

#### Limitations for reusable content items

The `RetrieveAllPages` (`RetrieveAllPagesByGuids`) approach is only available for page content types. For reusable content items, you must use one of the following approaches:

- Specify exact content types you want to retrieve.
- Use [reusable field schemas](https://docs.kentico.com/documentation/developers-and-admins/development/content-types/reusable-field-schemas.md) to group related content types that share common properties.

You can cast results to the shared `IContentItemFieldsSource` interface when retrieving across multiple reusable field schemas or content types:

```csharp title="Reusable content item retrieval requires specific content types"
using System.Collections.Generic;

using CMS.ContentEngine;

using Kentico.Content.Web.Mvc;

// ...

// Retrieves a specific reusable content type
var testimonials = await contentRetriever.RetrieveContent<TestimonialItem>();

// Retrieves multiple specific content types using reusable field schema
var schemaNames = new[] { IMetadataFields.REUSABLE_FIELD_SCHEMA_NAME };
IEnumerable<IMetadataFields> itemsWithSchema =
  await contentRetriever.RetrieveContentOfReusableSchemas<IMetadataFields>(schemaNames);

// Retrieves across multiple reusable schemas and casts to shared interface
var multiSchemaNames = new[] {
    IMetadataFields.REUSABLE_FIELD_SCHEMA_NAME,
    ISeoFields.REUSABLE_FIELD_SCHEMA_NAME
};
IEnumerable<IContentItemFieldsSource> itemsWithSchemas =
  await contentRetriever.RetrieveContentOfReusableSchemas<IContentItemFieldsSource>(multiSchemaNames);
```

## Method reference

See [Reference - ContentRetriever API](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/reference-content-retriever-api.md) for a reference of all methods available on `IContentRetriever`.
