Advanced Filtering Guide

April 16, 2026 · View on GitHub

This guide explains how to express Delivery API filtering using the SDK’s fluent filtering DSL. The underlying API merges multiple filtering parameters using logical AND (more restrictive queries). See the Delivery API docs: Filtering parameters.

Overview

Filtering is added via .Where(...) on query builders. A single .Where(...) call can add multiple conditions:

var result = await client.GetItems()
    .Where(f => f
        .System("type").IsEqualTo("article")
        // [contains] is for arrays (e.g. taxonomy, linked items, multiple choice), not strings.
        // See Delivery API docs: https://kontent.ai/learn/docs/apis/delivery-api/filtering-parameters?sl=1
        .Element("category").Contains("coffee")
        .System("last_modified").IsGreaterThan(DateTime.UtcNow.AddDays(-30)))
    .ExecuteAsync();

You can also chain multiple .Where(...) calls; all conditions are still ANDed together.

Property paths

The DSL builds property paths for you:

  • System("<property>")system.<property>
    • Examples: system.type, system.codename, system.language, system.last_modified, system.collection, system.workflow_step
  • Element("<codename>")elements.<codename>
    • Examples: elements.title, elements.price, elements.tags, elements.publish_date

Operator reference

Equality

  • IsEqualTo(...)[eq]
  • IsNotEqualTo(...)[neq]
// system.type[eq]=article
.Where(f => f.System("type").IsEqualTo("article"))

// elements.status[neq]=draft
.Where(f => f.Element("status").IsNotEqualTo("draft"))

Comparison

  • IsLessThan(...)[lt]
  • IsLessThanOrEqualTo(...)[lte]
  • IsGreaterThan(...)[gt]
  • IsGreaterThanOrEqualTo(...)[gte]
.Where(f => f.Element("price").IsGreaterThan(100.0))
.Where(f => f.System("last_modified").IsLessThanOrEqualTo(DateTime.UtcNow.AddDays(-7)))

Range (inclusive)

  • IsWithinRange(lower, upper)[range] with lower,upper
.Where(f => f.Element("price").IsWithinRange(100.0, 500.0))
.Where(f => f.System("last_modified").IsWithinRange(DateTime.Parse("2024-01-01"), DateTime.Parse("2024-06-30")))

Collection membership

  • IsIn(...)[in]
  • IsNotIn(...)[nin]
.Where(f => f.System("type").IsIn("article", "blog_post", "news"))
.Where(f => f.Element("rating").IsIn(4.0, 5.0))

Arrays

  • Contains("...")[contains] (array contains a value)
  • ContainsAny(...)[any] (array contains at least one)
  • ContainsAll(...)[all] (array contains all)
.Where(f => f.Element("category").Contains("coffee"))
.Where(f => f.Element("tags").ContainsAny("featured", "trending"))
.Where(f => f.Element("required_features").ContainsAll("warranty", "manual"))

Empty checks

  • IsEmpty()[empty]
  • IsNotEmpty()[nempty]
.Where(f => f.Element("seo_description").IsEmpty())
.Where(f => f.Element("summary").IsNotEmpty())

Combining filters with other query parameters

var result = await client.GetItems()
    .Where(f => f
        .System("type").IsEqualTo("article")
        .Element("tags").ContainsAny("beginner", "intermediate"))
    .WithLanguage("en-US")
    .WithElements("title", "summary")
    .Depth(2)
    .OrderBy("system.last_modified", OrderingMode.Descending)
    .Limit(10)
    .ExecuteAsync();

Language fallback control

Kontent.ai language fallbacks are controlled by how you combine the Delivery API language parameter with filtering on system.language.

  • Default behavior (fallbacks allowed): .WithLanguage("es-ES") requests the Spanish variant, and the API may fall back to the default language for items that are not translated.
  • Fallbacks disabled (only translated items, list/feed queries): .WithLanguage("es-ES", LanguageFallbackMode.Disabled) automatically adds system.language[eq]=es-ES to the query, so only items actually translated into es-ES are returned.

Single-item queries (GetItem<T>(...) and dynamic GetItem(...)) do not support fallback disabling. They use only language=<lang> and rely on Kontent.ai fallback configuration.

Manual equivalent:

var result = await client.GetItems()
    .WithLanguage("es-ES")
    .Where(f => f.System("language").IsEqualTo("es-ES"))
    .ExecuteAsync();

Instead of building “filter objects”, use normal C# branching:

var query = client.GetItems();

if (onlyArticles)
{
    query = query.Where(f => f.System("type").IsEqualTo("article"));
}

if (!string.IsNullOrWhiteSpace(searchText))
{
    // Note: Delivery API doesn't support substring contains on strings.
    // Use [contains]/[any]/[all] only for arrays (taxonomy, linked items, multiple choice).
    query = query.Where(f => f.Element("category").Contains(searchText));
}

var result = await query.ExecuteAsync();

Troubleshooting

  • Unexpected no-results: remember filters are ANDed; temporarily comment out filters to isolate the restrictive one.
  • Special characters: string values are URL-encoded automatically (e.g. & becomes %26).
  • Date filtering: the SDK serializes all DateTime filter values to UTC (Z). Local values are converted to UTC; Unspecified values are treated as UTC (no offset conversion). Prefer DateTime.UtcNow/UTC values, or use DateTimeOffset and convert to UTC explicitly before filtering. The Delivery API compares date-time strings; be explicit about bounds (see Delivery docs: Filtering parameters).