query, but they give you extra metadata about the characteristics of those products.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
]
}
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.keyorcategories). 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 toallif 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 iffieldis 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, bykeyorcount,ascordesc. 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
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"
}
}
]
}
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 specifiedfieldthat 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-50or51-100. If omitted, a default like*-5000or5000-10000is 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.
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": [
{
"name": "all-products",
"value": 200
},
{
"name": "all-variants",
"value": 1000
}
],
"results": [...]
}
Stats facets
- Purpose: Stats facets calculate statistical aggregations—minimum, maximum, average (mean), sum, and count—on numeric and date fields. This provides insights into product data (such as price ranges or average ratings) without requiring separate queries or client-side calculations.
- How it works: You specify a numeric or date
field(for example,variants.prices.centAmountorcreatedAt). The API analyzes values across matching products and returns statistical metadata. For number fields, all five values are returned; for date fields, onlymin,max, andcountare provided (mean and sum are not applicable to dates). - 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).filter: Additional filtering expression to apply to the facet result before calculating statistics.field(mandatory): The numeric or date field to calculate statistics on.fieldType: Required iffieldis a custom attribute.
Example request
Let's calculate price statistics for all product variants:
{
"query": {},
"facets": [
{
"stats": {
"name": "priceStats",
"field": "variants.prices.centAmount",
"scope": "query" // Calculate stats for search results only
}
}
]
}
Example response
{
"facets": [
{
"name": "priceStats",
"min": 10000, // Lowest price: $100.00
"max": 150000, // Highest price: $1,500.00
"mean": 65000, // Average price: $650.00
"sum": 1300000, // Total of all prices: $13,000.00
"count": 20 // Number of prices counted
}
],
"results": [...]
}
Use these values to display dynamic UI elements like "Prices from $100 to $1,500" or "Average price: $650" without manual calculation.
Choosing between ranges and stats facets
Both ranges and stats facets operate on numeric and date fields but serve different purposes:
- Ranges facets: Use when implementing UI filters (checkboxes/radio buttons) allowing users to select price brackets. Returns counts per predefined bucket (for example,
$0-50: 15 products). - Stats facets: Use when displaying statistical metadata without filtering UI. Returns calculated values (min, max, average) for showing price ranges or average ratings as informational text.
For comprehensive UIs, use both: ranges facets for interactive filters and stats facets for displaying dynamic metadata headers.