Skip to main content

Filter basics

The filter_group API parameter refines results by selecting only the products that match the given expressions and running the query on those products. The filter_group expects a filter expression.

Expressions and operators

Expressions are the core of the filter language.
  • property is the attribute of the field you want to filter on.
  • operator is the logical operator to apply (see full list below).
  • values is an array of values the operator compares against in the property.

Supported operators

Negative operators and missing values

Negative operators (neq, notIn, notBetween, doesNotContain, doesNotBeginWith, doesNotEndWith) also match products that have no value for the attribute. For example, tags notIn ["Outlet"] returns untagged products as well as products tagged with anything other than Outlet. This applies consistently across the Search and Browse APIs. If you want to exclude products that are missing the attribute entirely, combine the negative condition with notNull in an AND group:

Examples of basic conditions

A condition to find products of type Sweaters:
A condition to find products created after 1 January 2020 (UNIX Epoch time):
A condition to exclude gift card products:
A condition to find bundle products (products with variants that require components):
A condition to find products within a price range (e.g., between 10and10 and 50):
A condition to find products with variants available at specific location IDs (e.g., locations 1001 and 1002):
The variants.in_stock_location_ids field is not filterable. It is a sort-only field used for location-based product demotion in sort orders. See Sorting for details on using this field in priority rules.To filter by location — including “available for pickup near me” — use variants.pickup_locations. See Local pickup filtering.
A condition to find products that have at least one variant on sale (variant compare-at price greater than its price):
Use variants.on_sale instead to restrict to specific variants on sale, for example when combined with other variant-level conditions in the same expression group. See On-sale attributes for how the values are derived. A condition to find products whose title contains “organic”:
A condition to exclude products without a vendor (null check):
A condition to find products NOT in a price range (e.g., outside 10to10 to 50):
A condition to find products published in the last 30 days. inLast is evaluated against NOW() at query time, so the window stays evergreen. You can save it once on a sort order or merchandising rule and it tracks the calendar without re-saving:
A condition to find products created strictly after a fixed date:
A condition to find products created strictly before a fixed date:
inLast, after, and before are designed for attributes whose value type is date or timestamp. Both date-only values such as "2025-01-01" and full timestamp values such as "2025-01-01T00:00:00Z" are accepted.

Complex filter expressions

You can build advanced filter groups by combining expressions using AND and OR.

Example of complex expression

To include both Accessories and products from SUPREME published after 1 January 2020:

Variant-level conditions

Conditions on variant-level properties such as options.*, variants.*, and variant_metafields.* are matched against individual variants. When a group combines several variant-level conditions with AND, a single variant must satisfy all of them. A product that has a size M variant and a separate red variant does not match options.size eq M AND options.color eq Red. The available filter follows the same rule when you combine it with at least one variant-level condition in the same AND group. The variant that matches the other conditions must itself be in stock. For example, this filter returns only products that have an in-stock size M variant:
A product whose only M variant is sold out is excluded, even if other sizes are in stock. Layers checks variant availability with the same rules it uses to hide or demote out-of-stock products, including location-scoped inventory and variants set to continue selling when out of stock. On its own, available still matches any product that is in stock. Keep these rules in mind:
  • Shopper and merchant filters combine. Variant-level conditions from the request’s filter_group and from merchandising or collection filters form one AND group. The same variant must satisfy all of them.
  • OR branches match independently. Within each OR branch, one variant must satisfy all of that branch’s variant-level conditions. Different branches can match different variants.
  • The matched variant is returned. first_or_matched_variant returns the variant that satisfied the conditions, so the tile shows that variant’s image, price, and options.
  • Facet counts follow the matched variant. With options.size eq M and available selected, the color facet counts only the colors of in-stock M variants. Sibling variants in other sizes are not counted.

Best practices

When crafting filter expressions:
  • Test complex expressions in a controlled environment before deployment.
  • String operators (contains, doesNotContain, beginsWith, endsWith, doesNotBeginWith, doesNotEndWith) are case-insensitive. For example, filtering where title contains “organic” also matches “Organic” and “ORGANIC”.
  • Use the between operator instead of combining gte and lte for range queries.
  • Nested filter groups support up to two levels of depth.

Troubleshooting

If your filter expression isn’t returning the expected results:
  • Verify that operator names use the exact camelCase format shown above (e.g., notIn, not not_in).
  • Confirm that attribute names and values match exactly with the data.
  • Ensure the values field is always an array, even for single-value operators like eq.
  • Check that the conditional field uses uppercase AND or OR.