Skip to content

Get Products

About

The products query returns a cursor-paginated list of catalog products with filtering and sorting. It is the canonical reference for both — Search Products is the same field with its query argument supplied, and uses the identical filter keys and sort keys documented below. Use it to:

  • Build product catalog browsing interfaces
  • Drive listing, filtering, and sorting experiences
  • Create product recommendation rails
  • Sync product data with external systems

Each product node carries its basic information (name, SKU, descriptions), pricing, images, categories and custom attributes, availability status, and timestamps.

Wishlist & Compare Flags

Every product carries two per-customer flags so the wishlist and compare icons can be rendered straight from the catalog response. The wishlist and compare endpoints paginate independently of the catalog, so matching those lists against catalog rows on the client is unreliable.

FieldDescription
isInWishlist"1" when the product is in the signed-in customer's wishlist for the active channel, "0" when it is not.
isInCompare"1" when the product is in the signed-in customer's compare list, "0" when it is not.

Both need the customer Bearer token and are always "0" for guests. GraphQL returns them as the strings "1" / "0"; the REST API returns the same flags as the integers 1 / 0.

Arguments

ArgumentTypeDescription
firstIntThe number of products to return per page. Used for forward pagination. Default: 30
afterStringThe cursor of the product to start after. Used with first for pagination.
lastIntThe number of products to return in reverse. Used for backward pagination. Default: 30
beforeStringThe cursor to start before. Used with last for reverse pagination.
sortKeyStringField to sort by: ID, TITLE (alias NAME), PRICE, CREATED_AT, UPDATED_AT. Case-insensitive. Default: ID
reverseBooleanReverse the sort order. Default: false
queryStringSearch query string for filtering products. Supports advanced search syntax.
filterStringJSON string of filter keys (see below). Pass as a single-line JSON string with escaped quotes.

Filter keys

The filter argument is a JSON object encoded as a string. Accepted keys:

KeyTypeDescription
typeStringProduct type: simple, configurable, bundle, grouped, virtual, downloadable, booking.
skuStringExact SKU match.
category_idIntRestrict to a category.
price_fromNumberMinimum price (inclusive).
price_toNumberMaximum price (inclusive).
newBooleantrue → only products flagged "new".
featuredBooleantrue → only products flagged "featured".
<attribute_code>StringAny filterable attribute code (e.g. color, size, brand). Value is the option id; comma-separate for multiple ("3,4").

Write the filter as a normal JSON object first:

json
{
  "type": "simple",
  "price_from": 10,
  "price_to": 200
}

Then pass it to filter as a single-line string with its quotes escaped:

graphql
query getFilteredProducts {
  products(
    filter: "{\"type\": \"simple\", \"price_from\": 10, \"price_to\": 200}"
    first: 10
  ) {
    totalCount
    edges {
      node {
        _id
        sku
        name
        price
        formattedPrice
      }
    }
  }
}

Escaping is avoided entirely by writing the filter as a GraphQL block string, which accepts embedded quotes as-is:

graphql
query getFilteredProducts {
  products(
    filter: """{"type": "simple", "price_from": 10, "price_to": 200}"""
    first: 10
  ) {
    totalCount
    edges {
      node {
        _id
        sku
        name
        price
        formattedPrice
      }
    }
  }
}

A variable keeps the query document static, which is what most clients want:

graphql
query getFilteredProducts($filter: String) {
  products(filter: $filter, first: 10) {
    totalCount
    edges {
      node {
        _id
        sku
        name
        price
        formattedPrice
      }
    }
  }
}
json
{
  "filter": "{\"type\": \"simple\", \"price_from\": 10, \"price_to\": 200}"
}

Filter behaviour

Four rules decide what a filter actually returns:

RuleWhat it means
Keys combineEvery key you add narrows the result. Filters intersect — they never widen the set.
The value is always a stringfilter is a String scalar, not an input object, so a real JSON object is rejected before the query runs. Build the string in the client — JSON.stringify({ type: 'simple', price_from: 10 }) — and the escaping is handled for you.
A price range needs two keysUse price_from and price_to. The compound price=min,max form is REST-only and has no effect here.
Price matches the product's own priceThat attribute is 0 on configurable and bundle parents, whose real price lives in their variants or selections. Any price_from above 0 therefore drops both types — filter them by type and read minimumPrice / maximumPrice instead.

Sorting

Use sortKey to pick the column and reverse to flip the direction. The common combinations:

SortsortKeyreverse
A → Z"TITLE"false
Z → A"TITLE"true
Newest first"CREATED_AT"true
Oldest first"CREATED_AT"false
Cheapest first"PRICE"false
Most expensive first"PRICE"true

Omitting sortKey orders by product ID, so a listing that cares about order should always set one.

How price sorting works

Sorting by PRICE does not order on the price field. It orders on minimumPrice — the effective price the shopper sees, which accounts for:

  • Special price — a discounted price replaces the regular one.
  • Configurable variants — the parent takes the lowest price across its variants.
  • Neither appliesminimumPrice equals price.

Display minimumPrice alongside price-sorted results, otherwise the order and the numbers on screen disagree.

Possible Returns

FieldTypeDescription
edges[ProductEdge!]!Array of edges containing products and cursors. Each edge represents a connection between nodes.
edges.nodeProduct!The actual product object containing id, name, sku, price, and other product fields.
edges.cursorString!Pagination cursor for this product. Use with after or before arguments.
nodes[Product!]!Flattened array of products without edge information.
pageInfoPageInfo!Pagination metadata object.
pageInfo.hasNextPageBoolean!Whether there are more products after the current page.
pageInfo.hasPreviousPageBoolean!Whether there are products before the current page.
pageInfo.startCursorStringCursor of the first product on the current page.
pageInfo.endCursorStringCursor of the last product on the current page.
totalCountInt!Total number of products matching the query criteria.

Price Fields

FieldTypeDescription
priceFloatBase catalog price. Returns the converted numeric value based on the active currency set via X-Currency header.
formattedPriceStringSame as price but returned as a string with the currency symbol prefixed (e.g. "€84.99").
specialPriceFloatDiscounted price if a special price is set, otherwise null. Reflects currency conversion.
formattedSpecialPriceStringSame as specialPrice but with the currency symbol prefixed.
minimumPriceFloatThe lowest effective price — accounts for special price and configurable variant pricing. Used for price sorting. Reflects currency conversion.
formattedMinimumPriceStringSame as minimumPrice but with the currency symbol prefixed.
maximumPriceFloatThe highest effective price across all variants or configurations. Reflects currency conversion.
formattedMaximumPriceStringSame as maximumPrice but with the currency symbol prefixed.
regularMinimumPriceFloatThe regular (non-discounted) minimum price before any special price is applied. Reflects currency conversion.
formattedRegularMinimumPriceStringSame as regularMinimumPrice but with the currency symbol prefixed.
regularMaximumPriceFloatThe regular (non-discounted) maximum price before any special price is applied. Reflects currency conversion.
formattedRegularMaximumPriceStringSame as regularMaximumPrice but with the currency symbol prefixed.

Product Types

Use the filter argument with "type" to fetch products of a specific kind. The filter value must be a single-line JSON string with escaped quotes.

TypeFilter ValueKey Fields
Simple"{\"type\": \"simple\"}"price, specialPrice, images, attributeValues
Configurable"{\"type\": \"configurable\"}"variants, combinations, superAttributeOptions
Booking"{\"type\": \"booking\"}"bookingProducts (type, qty, location, availability)
Virtual"{\"type\": \"virtual\"}"price, specialPrice, attributeValues
Grouped"{\"type\": \"grouped\"}"groupedProductsassociatedProduct
Downloadable"{\"type\": \"downloadable\"}"downloadableLinks, downloadableSamples
Bundle"{\"type\": \"bundle\"}"bundleOptionsbundleOptionProductsproduct

Released under the MIT License.