Let's build on our understanding of the Platform Search Query Language. We know how to ask specific questions using compound and simple expressions. Now, let's explore how to get summaries and statistical information about our product data alongside the search results. This is where facets come in—they are essential for building interactive filtering experiences (faceted navigation) for your users.
Facets provide aggregated counts over your search results. They do not change which products are returned by your main
query
, but they give you extra metadata about the characteristics of those products.You request facets by adding a
facets
array to your main ProductSearchRequest
body. Each element in this array defines one facet calculation for the API to perform.// Structure of a request with facets
{
"query": {
/* Your main search query here */
},
"sort": [
/* Optional sorting */
],
"limit": 10,
"offset": 0,
"facets": [
// Array to define desired facets
{
/* Facet Definition 1 */
},
{
/* Facet Definition 2 */
}
// ... more facets
]
}
The results of these calculations appear in the
facets
field of the ProductPagedSearchResponse
.There are three main types of facets: distinct, ranges and count facets.
Distinct facets
- Purpose: Distinct facets count how many products (or variants) have specific, distinct values for a given field. This is useful for things like colors, brands, sizes (if they are discrete values), or categories.
- How it works: You specify a
field
(such asvariants.attributes.color.key
orcategories
). The API groups the products by the unique values found in that field and counts how many fall into each group (bucket). - Key configuration:
name
: A mandatory unique name you give this facet (for example, "colorFacet") to identify it in the results.scope
: Set this parameter toall
if the facet must consider all indexed products, not only the products resulting from the search query, which is the default behavior.field
(mandatory): The searchable product field to facet on.filter
: Additional filtering expression to apply to the facet result before calculating the facet.level
: Specify whether to count products (products
) or product variants (variants
).fieldType
: Required iffield
is a custom attribute.limit
: Maximum number of distinct value buckets to return. This improves query performance and is helpful when your UI does not need to display a large number of values. For example, only showing 10 different colors instead of 50 or more.sort
: How to sort the buckets, bykey
orcount
,asc
ordesc
. For example, sort color by count ascending.includes
: Only return buckets for these specific keys. For example, you only want colors red, blue, and green.missing
: A key to use for products that do not have the specifiedfield
. For example, some products do not have a color value; you can put these in a separate bucket like "misc" or "other colors".
Let’s consider how these concepts might map to a UI:

Example request
Let's count products by their
categories
attribute for results that match products with "white" or "White" in their name in this example request:{
"query": {
"fullText": {
"field": "name",
"language": "en",
"value": "white",
"caseInsensitive": true
}
},
"facets": [
{
"distinct": {
"name": "categoriesFacet",
"field": "categories",
"limit": 15,
"missing": "No Category"
}
}
]
}
In the response, you will notice that we received the category ID’s and count. The categories are in a flat structure. Some layered navigation user interfaces require to display hierarchical categories. To enable rendering the facet values and aggregations in a hierarchical view, you will need to persist the hierarchy in your application, in a shared cache. This should be safe to do because categories and their structure don’t change frequently. You can ready up more on caching strategies and categories in our Category queries best practices module.
Example response
{
"total": 244,
"offset": 0,
"limit": 20,
"facets": [
{
"name": "categoriesFacet",
"buckets": [
{
"key": "52e575d7-16ce-4186-ae67-39bec921e9ca",
"count": 65
},
{
"key": "2d1c1b7c-6e92-43c5-aa64-c10678793da5",
"count": 59
},
{
"key": "c2da8bae-daea-40e1-9e94-26753414e8d5",
"count": 49
},
{
"key": "06733ee5-0323-41e8-871d-bf58d5b6d093",
"count": 34
}
]
}
],
"results": [...]
}
Let’s take a look at how a standard product localized attribute facet query and response looks. We must specify the facet by their key. Because of this, you should consider how you get your application to store these keys, to ensure that you can quickly build the request.
{
"query": {
"fullText": {
"field": "name",
"language": "en",
"value": "white",
"caseInsensitive": true
}
},
"facets": [
{
"distinct": {
"name": "sizes",
"field": "variants.attributes.size.key",
"fieldType": "enum",
"limit": 15,
"missing": "No value"
}
}
]
}
In the response we have the attribute value keys.
{
"total": 244,
"offset": 0,
"limit": 20,
"facets": [
{
"name": "sizes", // Matches the name in the request
"buckets": [ // The results: distinct values and their counts
{ "key": "L", "count": 150 },
{ "key": "M", "count": 125 },
{ "key": "S", "count": 90 },
{ "key": "XL", "count": 70 },
{ "key": "Not Specified", "count": 20 }
]
}
],
"results": [...]
}
Ranges facets
- Purpose: Ranges facets count how many products fall into predefined numeric or date ranges. Ideal for price brackets, screen sizes, ratings, or date ranges.
- How it works: You define the boundaries (
from
,to
) for each range (bucket). The API counts how many products have a value in the specifiedfield
that falls within each range. - Key configuration:
name
(mandatory): Your unique name for this facet result.scope
: Whether the facet must consider only the products resulting from the search (query
) or all indexed products (all
).field
(mandatory): The numeric or date field to facet on (for example,variants.prices.centAmount
).level
: Specify whether to count products (products
) or product variants (variants
).fieldType
: Required for custom attributes.ranges
(mandatory): An array defining each bucket:key
: (Optional) A custom label for the bucket, for example,0-50
or51-100
. If omitted, a default like*-5000
or5000-10000
is generated by the API.from
: The lower bound (inclusive). Omit for "less than".to
: The upper bound (exclusive). Omit for "greater than or equal to".
Example request
Let's count products by price ranges (in cents).
{
"query": {},
"facets": [
{
"ranges": {
"name": "priceRanges",
"field": "variants.prices.centAmount", // Field must be numeric/date
"ranges": [
{ "key": "under-50", "to": 5000 }, // .. up to 4999 cents
{ "key": "50-to-100", "from": 5000, "to": 10000 }, // 5000 to 9999 cents
{ "key": "100-plus", "from": 10000 } // 10000 cents and above
]
}
}
]
}
Example response
{
// ... other response fields
"facets": [
{
"name": "priceRanges",
"buckets": [
{ "key": "under-50", "count": 85 },
{ "key": "50-to-100", "count": 112 },
{ "key": "100-plus", "count": 43 }
]
}
]
"results": [...]
}

Count facets
- Purpose: The count facet counts the number of products (or product variants).
- How it works: Returns a single value representing the count.
- Key configuration:
name
: Your unique name for this facet result.scope
: Whether the facet must consider only the products resulting from the search (query
) or all indexed products (all
).filter
: Additional filtering expression to apply to the facet result before calculating the facet.level
: Specify whether to count products (products
) or product variants (variants
).
You can use the count facet to get the total number of variants or products and display it in the UI as shown below.
The count for products should be the same value as the response
total
.
Example request
Let's get the total count of all products and all variants:
{
"query": {},
"facets": [
{
"count": {
"name": "totalProductCount",
"scope": "all" // Count ALL products, ignoring the main query
}
},
{
"count": {
"name": "totalVariantCount",
"level": "variants", // Count variants instead of products
"scope": "all" // Count ALL variants, ignoring the main query
}
}
]
}
Example response
{
"facets": {
"results": [
{
"name": "all-products",
"value": 200
},
{
"name": "all-variants",
"value": 1000
}
]
},
"results": [...]
}