Product Projections
In modern commerce, every millisecond counts, and sometimes, the data you don't load is just as important as the data you do.
filter[attributes] query parameter. This allows you to surgically specify exactly which Product Attributes (on the Product, Master Variant, or other Variants) you want to be included in (or excluded from) the API response.filter[attributes] parameter is available across all core Product Projection endpoints, including queries, fetching by ID, fetching by key, and store-scoped requests.Using it is straightforward, supporting both inclusion (whitelist) and exclusion (blacklist) modes:
Including specific Attributes (Whitelist)
To request only a specific set of attributes, simply provide a list of the attribute names. Any attribute not listed will be omitted from the response.
filter[attributes]=attributeName1,attributeName2curl --get \
"https://api.{region}.commercetools.com/{projectKey}/product-projections/key=rustic-country-queen-bed?filter[attributes]=search-color&filter[attributes]=search-finish" \
--header "Authorization: Bearer {bearerToken}" \
| jq
{
"id": "70ab1f54-277e-4504-87f3-cdae3d5be73d",
"version": 3,
"productType": {
"typeId": "product-type",
"id": "415bec3b-e1de-4bbd-8c62-e537937ec817"
},
"name": {
"en-US": "Rustic Country Queen Bed",
"en-GB": "Rustic Country Queen Bed",
"de-DE": "Rustikales Queensize-Bett im Landhausstil"
},
...
"attributes": [
{
"name": "search-finish",
"value": {
"key": "brown",
"label": {
"en-US": "Brown",
"en-GB": "Brown",
"de-DE": "Braun"
}
}
},
{
"name": "search-color",
"value": {
"key": "yellow",
"label": {
"en-US": "Yellow",
"en-GB": "Yellow",
"de-DE": "Gelb"
}
}
}
],
...
}
Excluding Specific Attributes (Blacklist)
To fetch all attributes except a few, use the minus sign (-) prefix before the attribute name.
filter[attributes]=-attributeName1If we want to get all attributes except search-color:
curl --get \
"https://api.{region}.commercetools.com/{projectKey}/product-projections/key=rustic-country-queen-bed?filter%5Battributes%5D=-search-color" \
--header "Authorization: Bearer {bearerToken}" \
| jq
{
...
"attributes": [
{
"name": "search-finish",
"value": {
"key": "brown",
"label": {
"en-US": "Brown",
"en-GB": "Brown",
"de-DE": "Braun"
}
}
},
{
"name": "finish-code",
"value": "#8b4513"
},
{
"name": "productspec",
"value": {
"en-US": "- Leather upholstery\n- Standard Queen size\n- Assembly on site",
"en-GB": "- Leather upholstery\n- Standard Queen size\n- Assembly on site",
"de-DE": "- Leather upholstery\n- Standard Queen size\n- Assembly on site"
}
},
{
"name": "finish-label",
"value": {
"en-GB": "Saddle Brown",
"de-DE": "Sattel braun",
"en-US": "Saddle Brown"
}
},
{
"name": "color-label",
"value": {
"en-GB": "Tan",
"de-DE": "Bräunen",
"en-US": "Tan"
}
},
{
"name": "color-code",
"value": "#D2B48C"
}
],
...
}
filter[attributes] parameter into your next project or optimization sprint to unlock these benefits!Product Search
A strategic advantage in e-commerce, effective product search goes beyond a mere technical function. It directly impacts customer satisfaction, drives conversion rates, and is crucial for overall success. This is precisely why the Product Search API was introduced in 2024 and continuously improved throughout 2025. Let's have a look at some of the new features that have been introduced over the course of last year.
The Product Search API's speed comes from its ID-first design; it traditionally returned only the IDs of matching Products, requiring a second step to fetch product details via GraphQL.
Now, with Product Search functionality integrated directly into the GraphQL API, you can query and retrieve product details in a single streamlined step.
Now all we need is a tool that would help us create, validate, and test our GraphQL Product Search queries.
How about we use it to test out some new features that were introduced to Product Search in 2025?
Fuzzy search
Without the fuzzy query, a standard fullText search for a misspelling like "tarditional" would typically fail to find any relevant products. However, the introduction of the new fuzzy query increases the likelihood of successfully finding these products despite the typo:
query FuzzySearch {
productsSearch(
query: {fuzzy: {field: "name", value: "tarditional", level: 2, language: "en-GB"}}
) {
results {
product {
key
}
}
}
}
{
"data": {
"productsSearch": {
"results": [
{
"product": {
"key": "traditional-armchair"
}
},
{
"product": {
"key": "traditional-l-seater-sofa"
}
},
{
"product": {
"key": "traditional-three-seater-sofa"
}
}
]
}
}
}
Statistical facets
Let's use it to expand our previous request:
query FuzzySearchWithGermanPriceStats {
productsSearch(
query: {fuzzy: {field: "name", value: "tarditional", level: 2, language: "en-GB"}}
facets: {stats: {name: "priceStatistics", field: "variants.prices.centAmount", filter: {and:[{exact: {field: "variants.prices.currencyCode", value: "EUR"}}, {exact: {field: "variants.prices.country", value: "DE"}}]}}}
) {
results {
product {
key
masterData {
current {
allVariants {
prices {
country
value {
centAmount
currencyCode
}
}
}
}
}
}
}
facets {
... on ProductSearchFacetResultStats {
name
count
sum
min
max
mean
}
}
}
}
{
"data": {
"productsSearch": {
"results": [
...
],
"facets": [
{
"name": "priceStatistics",
"count": 3,
"sum": 629700,
"min": 29900,
"max": 359900,
"mean": 209900
}
]
}
}
}
We now have not only the count of prices that meet our requirements but also valuable statistical information about them.
Filter by discounted prices
query FuzzySearchForDiscountedProducts {
productsSearch(
query: {and: [{fuzzy: {field: "name", language: "en-GB", level: 2, value: "tarditional"}}, {exact: {field: "variants.prices.discounted", value: true}}]}
) {
offset
limit
results {
id
product {
key
masterData {
current {
allVariants {
prices {
discounted {
value {
centAmount
currencyCode
}
}
value {
centAmount
currencyCode
}
}
}
}
}
}
}
}
}
{
"data": {
"productsSearch": {
"offset": 0,
"limit": 10,
"results": [
{
"id": "58084c1e-ccde-4c6d-9fd7-afc2ecd05673",
"product": {
"key": "traditional-armchair",
"masterData": {
"current": {
"allVariants": [
{
"prices": [
{
"discounted": {
"value": {
"centAmount": 25415,
"currencyCode": "EUR"
}
},
"value": {
"centAmount": 29900,
"currencyCode": "EUR"
}
},
{
"discounted": {
"value": {
"centAmount": 25415,
"currencyCode": "GBP"
}
},
"value": {
"centAmount": 29900,
"currencyCode": "GBP"
}
},
{
"discounted": {
"value": {
"centAmount": 25415,
"currencyCode": "USD"
}
},
"value": {
"centAmount": 29900,
"currencyCode": "USD"
}
}
]
}
]
}
}
}
}
]
}
}
}
Search for Product Variants in Stores
A significant enhancement to Product Search is the new capability to locate Product Variants that are available in specific Stores, regardless of how many active selections that Store has, or within specific Store Selections. Previously, this was only feasible if the entire Product belonged to the selection. Let's give it a try:
query FindVariantsBelongingToStore {
productsSearch(
query: {exact: {value: "a748b5f7-54b3-48f4-b744-fafb4b5d9f2c", field: "variants.stores"}}
markMatchingVariants: true
) {
results {
product {
key
masterData {
current {
allVariants(onlyMatching: true) {
sku
}
}
}
}
}
}
}
{
"data": {
"productsSearch": {
"results": [
{
"product": {
"key": "modern-three-seater-sofa",
"masterData": {
"current": {
"allVariants": [
{
"sku": "MTSS-01"
}
]
}
}
}
},
{
"product": {
"key": "maya-pillow-cover",
"masterData": {
"current": {
"allVariants": [
{
"sku": "MPC-02"
}
]
}
}
}
}
]
}
}
}
The significant enhancements to Product Search in 2025—including fuzzy search, statistical facets, discounted price filters, and granular variant selection—collectively deliver a powerful, flexible, and high-performance search experience. By leveraging these new capabilities, Functional Architects can design storefronts that are more resilient to user error, provide deeper analytical insights on pricing, and offer precise control over store-specific product visibility, ultimately leading to improved conversion rates and a superior customer experience.
Product Projection Search
productProjectionSearch query in GraphQL), your search criteria might target specific attributes of a variant (for example, "red shirt, size medium"). While the search results correctly return the parent product, the variants and allVariants fields on that product traditionally returned all variants of that product.onlyMatching: Boolean argument to the variants and allVariants fields within the ProductProjection type.onlyMatching: true, the commercetools API takes on the responsibility of filtering the list of variants, ensuring that the response only includes the Product Variants that matched your original productProjectionSearch query.To illustrate the elegance and efficiency of this new feature, let's look at a GraphQL query example.
Let's take a product like "Nala Two-Seater Sofa" with seven variants (various colors and finishes). You search for a sofa that is blue:
query FindBlueSofa {
productProjectionSearch(
text: "sofa"
locale: "en-US"
filters: {model: {value: {path: "variants.attributes.search-color.key", values: "blue"}}}
markMatchingVariants: true
) {
results {
key
allVariants(onlyMatching: true) {
sku
}
}
}
}
{
"data": {
"productProjectionSearch": {
"results": [
{
"key": "nala-two-seater-sofa",
"allVariants": [
{
"sku": "NTSS-02"
},
{
"sku": "NTTS-04"
}
]
}
]
}
}
}
As you can see in the result, even though this product has seven variants, our search only returned the two which meet the search criteria.