---
title: Content Search API
slug: cms-12/api/content-search-api
docTags: 
createdAt: 2026-08-07T16:45:44.000Z
---

The Content Search API exposes the ability to query for content in Optimizely Search & Navigation, providing robust filtering and sorting with **OData** syntax, with support for personalization, proper access control, and a feature for loading referenced content in the same request.

For a complete list of valid endpoints and query parameters, see the [Content Delivery API SDK](https://world.optimizely.com/documentation/class-libraries/rest-apis/content-delivery-api/).

:::hint{type="info"}
**Note**
The Content Search API adds some properties and data filter to communicate to Optimizely Search & Navigation index. So after installing the Content Search API, you need to re-index your site before start using it to retrieve content.
:::

## Install

To use Content Search API endpoints to query contents in your site, install  `EPiServer.ContentDeliveryApi.Search`. After that, register the API in your `Startup.cs`:

```csharp
services.AddContentSearchApi(o => {	
  o.MaximumSearchResults = 10;
});
```

## Localize

You can retrieve content in one or more languages within the same request to the Content Search API endpoint. To indicate the desired languages of content to return, attach the `Accept-Language` header to your request.

```csharp
Accept-Language : en 
Accept-Language : en, sv 
Accept-Language : en-US,fr-CA 
```

## Access control

The Content Search API only returns published content that the current user can view.

Users can authorize with `Cookie` or `OpenID` using the `EPiServer.OpenIDConnect` package. See [Authenticate the API](docId\:GcwKCbUQUXLkDILm5DQmW).

## Personalize

The Content Search API leverages indexed data within Optimizely Search & Navigation to deliver search results. By default, personalized contents are not indexed and are not returned by Content Search API. To retrieve personalized content (based on the current user and context), pass the personalize query string parameter as **true**:

```csharp
?personalize=true
```

## Free text search

The Content Search API endpoint lets callers pass in a free-text query evaluated by Optimizely Search & Navigation.

```csharp
?query=apples
```

## Filter

You can filter search results using the OData v4 filter syntax, providing the capability to write queries to filter down to specific subsets of content.

You can pass OData filters in the filter query string, with support for the following operators and functions:

- **Logical Operators** – `eq`, `ne`, `ge`, `gt`, `le`, `lt`, `and`, `or`
- **String Functions** – `to lower`, `contains`
- **Collection Functions** – `any` (Limited support - see Filter by Content Type below)

For information on OData v4 syntax, see [URL Conventions for OData v4](http://docs.oasis-open.org/odata/odata/v4.0/odata-v4.0-part2-url-conventions.html).

**Filter by Content Type**

Content can be filtered by a specific content type name, or by the base types: Page, Block, Media, Image, Video.

```csharp
?filter=ContentType/any(t:t eq 'Page') 
?filter=ContentType/any(t:t eq 'ArticlePage') 
?filter=ContentType/any(t:t eq 'ArticlePage') or ContentType/any(t:t eq 'CategoryPage') 
?filter=ContentType/any(t:t ne 'Block')
```

:::hint{type="info"}
**Note**
The any function support is limited to matching single property expressions on built-in simple `Collection` properties, namely `ContentType`. To filter in other collections on all properties, such as by `Category` or by your own Content Area properties, use eq and ne filters (See Filter by Category, Filter by Content Reference, and Filter by Content Area Value below).
:::

When using `any` function, you must use the Pascal Case for the property name (for example, `ContentType`, `NOT contentType`). This is because any function uses the property name in the filter string to find the correct property in the C# model class. If you pass a Camel Case property name like `contentType`, the OData parser throws a parse exception. When working with other functions and operations, use Camel Case with a property name.

**Filter by Category**

```csharp
?filter=category/value/id eq 2 
?filter=category/value/name eq 'Category Name'
```

**Filter by Content Reference**

```csharp
?filter=contentLink/id eq 6 
?filter=contentLink/id ne 6
?filter=contentLink/id ge 10
```

**Filter by Content Area Value**

```csharp
?filter=contentAreaProperty/value/contentLink/id eq 17 
?filter=contentAreaProperty/value/contentLink/id ne 4
```

**Filter by Date Range**

```csharp
?filter=startPublish ge 2016-01-01T00:00:00Z and startPublish le 2017-01-01T00:00:00Z
?filter=startPublish ge 2016-01-01T00:00:00Z and startPublish le 2017-01-01T00:00:00Z
```

**Filtering with String Matching**

```csharp
?filter=tolower(name) eq 'start' 
?filter=contains(mainBody/value, 'Start') 
?filter=contains(tolower(mainBody/value), 'bees')
```

## Order

You can order search results using the OData v4 `orderby` syntax, with support for multiple sorting criteria.

`Orderby` expressions are passed in the `orderby` query string, with support for indicating sort direction with `asc` and `desc` descriptors. If a sort direction is not included when passing an orderby string, the direction is defaulted to Ascending.

If the `orderby` string is excluded or empty, search results are ordered by relevance.

For information on OData v4 syntax, see [URL Conventions for OData v4](http://docs.oasis-open.org/odata/odata/v4.0/odata-v4.0-part2-url-conventions.html).

**Order by Name**

```csharp
?orderby=name
```

**Order by Recently Changed**

```csharp
?orderby=changed desc
```

**Order by multiple properties**

```csharp
?orderby=name asc, changed desc
```

## Top or skip

`Top` and `skip` parameters paginate through search results returned from the Content Delivery API search endpoint. Use the `totalMatching` property of the search response to calculate the total number of pages.

```csharp
?top=10&skip=10
```

## Expand

`Expand` parameter returns data from reference properties in the same request.

```csharp
?expand=myContentReference 
?expand=myContentReference,myContentArea 
?expand=*
```

By default, you can expand the following property types:

- `ContentArea`
- `ContentReference`
- `ContentReferenceList`
- `LinkCollection`

When reference properties are expanded, the full object for the referenced `IContent` instances are returned in the response on the `expandedValue` property of that property's object.

Expanded properties are fully compatible with the personalize parameter, meaning that only anonymous content is returned when a given property is expanded and personalize is set to **false**.

Properties on objects that are returned in the `ExpandedValue` cannot be expanded further in the same request.

## Example request/response

See [Search & Navigation APIs and libraries](https://world.optimizely.com/documentation/class-libraries/search-navigation/) for the detailed Rest API SDK of Content Search API.
