How to

Filter products

Filter products using facets with includeMode and filterMode. Learn to build faceted navigation with parameters, categories, and brands using Geins Merchant API

Filter products

Build faceted product filtering with parameters, categories, and brands. Control filter logic with includeMode and facet count calculation with filterMode.

Prerequisites

  • Merchant API key

Goals

  • Fetch available facets for product filtering
  • Filter products using facet IDs with the include field
  • Understand includeMode (INTERSECT vs UNION) for combining filters
  • Understand filterMode (BY_GROUP vs CURRENT) for facet counts
  • Work with different facet types and ID formats
  • Build interactive faceted navigation

Architecture at a glance

  • Query products → Get available facets → User selects filters → Query products with facets applied → Get filtered results

APIs used

  • Merchant API: https://merchantapi.geins.io/graphql

Step-by-step

Get available facets

First, fetch products and include the filters field to get available facets. This shows you what filters users can apply.

Try it out in the GraphQL Playground using the query, headers and variables below.

Request example

query getAvailableFacets(
    $categoryAlias: String
    $skip: Int
    $take: Int
    $channelId: String
    $languageId: String
    $marketId: String
) {
    products(
        categoryAlias: $categoryAlias
        skip: $skip
        take: $take
        channelId: $channelId
        languageId: $languageId
        marketId: $marketId
    ) {
        products {
            productId
            name
            canonicalUrl
        }
        count
        filters {
            facets {
                filterId
                type
                group
                label
                order
                values {
                    facetId
                    label
                    count
                    order
                    hidden
                }
            }
        }
    }
}
The channelId, languageId, and marketId arguments are optional and can be left out to use default values.

Response example

200 OK
response.json
{
    "data": {
        "products": {
            "products": [
                {
                    "productId": 1234,
                    "name": "Premium Wireless Headphones",
                    "canonicalUrl": "/p/premium-wireless-headphones"
                }
            ],
            "count": 47,
            "filters": {
                "facets": [
                    {
                        "filterId": "Brand",
                        "type": "Brand",
                        "group": null,
                        "label": "Brand",
                        "order": 0,
                        "values": [
                            {
                                "facetId": "b_audiopro",
                                "label": "AudioPro",
                                "count": 15,
                                "order": 0,
                                "hidden": false
                            },
                            {
                                "facetId": "b_soundmax",
                                "label": "SoundMax",
                                "count": 8,
                                "order": 1,
                                "hidden": false
                            }
                        ]
                    },
                    {
                        "filterId": "Color",
                        "type": "Parameter",
                        "group": "Specifications",
                        "label": "Color",
                        "order": 1,
                        "values": [
                            {
                                "facetId": "p_1_5_black",
                                "label": "Black",
                                "count": 23,
                                "order": 0,
                                "hidden": false
                            },
                            {
                                "facetId": "p_1_5_white",
                                "label": "White",
                                "count": 12,
                                "order": 1,
                                "hidden": false
                            },
                            {
                                "facetId": "p_1_5_silver",
                                "label": "Silver",
                                "count": 7,
                                "order": 2,
                                "hidden": false
                            }
                        ]
                    },
                    {
                        "filterId": "Connectivity",
                        "type": "Parameter",
                        "group": "Features",
                        "label": "Connectivity",
                        "order": 2,
                        "values": [
                            {
                                "facetId": "p_2_8_bluetooth",
                                "label": "Bluetooth",
                                "count": 35,
                                "order": 0,
                                "hidden": false
                            },
                            {
                                "facetId": "p_2_8_wired",
                                "label": "Wired",
                                "count": 18,
                                "order": 1,
                                "hidden": false
                            }
                        ]
                    }
                ]
            }
        }
    }
}

Filter products with multiple facets

Apply multiple filters using the include field with facet IDs. The default INTERSECT mode groups facets and combines them logically.

Try it out in the GraphQL Playground using the query, headers and variables below.

Request example

query filterProducts(
    $categoryAlias: String
    $include: [String]
    $includeMode: IncludeMode
    $filterMode: FilterMode
    $skip: Int
    $take: Int
    $channelId: String
    $languageId: String
    $marketId: String
) {
    products(
        categoryAlias: $categoryAlias
        skip: $skip
        take: $take
        filter: {
            include: $include
            includeMode: $includeMode
            filterMode: $filterMode
        }
        channelId: $channelId
        languageId: $languageId
        marketId: $marketId
    ) {
        products {
            productId
            name
            canonicalUrl
            productImages {
                fileName
            }
            unitPrice {
                sellingPriceIncVat
                sellingPriceIncVatFormatted
            }
            brand {
                name
                alias
            }
        }
        count
    }
}
The channelId, languageId, and marketId arguments are optional and can be left out to use default values.

Response example

200 OK
response.json
{
    "data": {
        "products": {
            "products": [
                {
                    "productId": 1234,
                    "name": "Premium Wireless Headphones - Black",
                    "canonicalUrl": "/p/premium-wireless-headphones",
                    "productImages": [
                        {
                            "fileName": "headphones-black.jpg"
                        }
                    ],
                    "unitPrice": {
                        "sellingPriceIncVat": 299.00,
                        "sellingPriceIncVatFormatted": "$299.00"
                    },
                    "brand": {
                        "name": "AudioPro",
                        "alias": "audiopro"
                    }
                },
                {
                    "productId": 1235,
                    "name": "Premium Wireless Headphones - White",
                    "canonicalUrl": "/p/premium-wireless-headphones-white",
                    "productImages": [
                        {
                            "fileName": "headphones-white.jpg"
                        }
                    ],
                    "unitPrice": {
                        "sellingPriceIncVat": 299.00,
                        "sellingPriceIncVatFormatted": "$299.00"
                    },
                    "brand": {
                        "name": "SoundMax",
                        "alias": "soundmax"
                    }
                }
            ],
            "count": 12
        }
    }
}
With includeMode: INTERSECT (default), this returns products from (AudioPro OR SoundMax) AND (black OR white) AND (Bluetooth). See Understanding include modes below for details.
Other filtering options:
  • UNION mode: Set includeMode: UNION to apply OR logic across all facets (products match ANY selected facet).
  • Exclude facets: Use exclude: ["facetId"] to filter out products with specific attributes.
  • Alternative methods: brandIds, categoryIds, excludeBrandIds, and excludeCategoryIds provide shortcuts, but facets are more flexible.

::

Understanding include modes

The includeMode parameter controls how multiple facets are combined logically.

INTERSECT mode (default)

Facets are grouped by type or parameter group, then combined using:

  • OR within groups - Products match any value in the group
  • AND between groups - Products must match at least one value from each group

Example:

include: ["b_audiopro", "b_soundmax", "p_1_5_black", "p_1_5_white", "p_2_8_bluetooth", "p_2_8_wired"]

// Automatic grouping:
// - Brand: b_audiopro, b_soundmax
// - Color (param group 1): p_1_5_black, p_1_5_white  
// - Connectivity (param group 2): p_2_8_bluetooth, p_2_8_wired

// Logic applied:
(b_audiopro OR b_soundmax) AND (p_1_5_black OR p_1_5_white) AND (p_2_8_bluetooth OR p_2_8_wired)

UNION mode

All facets treated as a flat list with OR logic:

Example:

include: ["b_audiopro", "p_1_5_black", "p_2_8_bluetooth"]
includeMode: UNION

// Logic: b_audiopro OR p_1_5_black OR p_2_8_bluetooth
Use INTERSECT for standard faceted navigation (users select from different categories). Use UNION for "show me anything matching these" scenarios.

Understanding filter mode

The filterMode parameter controls how facet counts are calculated in the filter results. This affects the numbers shown next to each filter option in your UI.

Most common when users interact with filters. Shows counts as if each facet group is selected independently, helping users understand available combinations.

How it works:

  • For each facet, shows the count excluding filters in its own group
  • But including filters from other groups
  • Users see realistic counts for what they'll get if they change their selection within a group

Example: User has selected "AudioPro" brand and "Black" color:

filter: {
    include: ["b_audiopro", "p_1_5_black"]
    includeMode: INTERSECT
    filterMode: BY_GROUP
}

// Results show:
// Brands:
//   - AudioPro (15) ← count excludes brand filter, includes color filter
//   - SoundMax (8)  ← count excludes brand filter, includes color filter
// Colors:
//   - Black (15)    ← count excludes color filter, includes brand filter
//   - White (10)    ← count excludes color filter, includes brand filter

CURRENT mode

Shows counts for the current filter results exactly as applied. All selected filters affect all facet counts.

Example: Same selection as above:

filter: {
    include: ["b_audiopro", "p_1_5_black"]
    includeMode: INTERSECT
    filterMode: CURRENT
}

// Results show:
// Brands:
//   - AudioPro (15) ← count includes all filters
//   - SoundMax (0)  ← filtered out by current selection, not included in results
// Colors:
//   - Black (15)    ← count includes all filters
//   - White (0)     ← filtered out by current selection, not included in results

Understanding facet types

Facets can represent different types of filterable attributes. The type field in FilterType indicates what kind of filter it is:

Facet types

  • Parameter - Product parameters/attributes (e.g., Color, Size, Material, Connectivity)
    • Grouped by parameter group (specified in group field)
    • Custom sort order supported via order field
    • Most common type for product filtering
  • Brand - Product brands
    • No parameter group
    • Used for brand filtering
  • Category - Product categories
    • Can have hierarchical structure (use parentId in FilterValueType)
    • Used for category-based filtering
  • Sku - SKU-level attributes
    • Represents variant-specific attributes
Use the type field to organize filters in your UI. Group all Parameter type filters together, and display Brand and Category filters separately.

Facet ID formats

Facet IDs follow specific naming patterns based on the facet type:

Standard facet formats

  • Brand facets: b_{brandAlias} (e.g., b_audiopro, b_soundmax)
  • Category facets: c_{categoryAlias} (e.g., c_headphones, c_electronics)
  • Parameter facets: p_{groupId}_{parameterId}_{value} (e.g., p_1_5_black, p_2_8_bluetooth)
  • SKU facets: sku_{value} (e.g., sku_large, sku_xl)

Special facet formats

  • Stock status facets:
    • In stock: ss_in_stock
    • Out of stock: ss_out_of_stock
    • Order item: ss_order_item
  • Discount campaign facets: dc_{campaignAlias}_{currency} (e.g., dc_summer-sale_usd)
  • Price range facets: price_{from}_{to}_{currency} (e.g., price_100_500_usd)
  • Reduced price facets: rp_{type}_{currency} (e.g., rp_sale_usd, rp_campaign_eur)
While facet IDs typically should be obtained from the filters response, there are valid use cases for using known facet IDs directly—such as programmatically excluding out-of-stock items with exclude: ["ss_out_of_stock"] or filtering by specific campaigns. However, use this approach with caution: facet ID formats and availability can vary based on configuration and market settings. When possible, rely on dynamically fetched facets to ensure compatibility.

Advanced filtering options

Combining with other filters

Facets can be combined with sorting, price filters, and search:

filter: {
    include: ["b_audiopro", "p_1_5_black"]
    includeMode: INTERSECT
    sort: PRICE
    price: { min: 50.00, max: 500.00 }
    searchText: "wireless"
}

Alternative methods

For simple filtering, you can use shortcuts (converted to facets internally):

  • brandIds: [123] - Filter by brand IDs
  • categoryIds: [456] - Filter by category IDs
  • productIds: [789] - Filter by specific product IDs
  • articleNumbers: ["SKU-001"] - Filter by article numbers
  • excludeBrandIds / excludeCategoryIds - Exclude specific brands/categories
Check current merchant api documentation for the latest available filtering options.

Multi-market support

The query supports optional parameters for multi-market configurations:

Read more about channelId, languageId, and marketId in the multi-market support guide.

Common pitfalls

  • Not showing facet counts - Display the count field to help users understand filter options
  • Using hardcoded facet IDs - Always fetch facets dynamically; they change based on available products
  • Ignoring hidden facets - Check the hidden field before displaying facet values
  • Misunderstanding INTERSECT mode - Remember: OR within groups, AND between groups (see Understanding include modes)
  • Not refreshing facets - Re-fetch filters after applying filters to show relevant options only
Related