Skip to main content
POST
cURL

Overview

The top recommendations endpoint lets headless storefronts fetch products without a seed anchor — unlike /recommendations and /recommendations/automatic, no product_ids are required. It is the right endpoint for:
  • Catalog / collection landing pages (“Bestsellers”, “New arrivals”)
  • Search results constrained by a strategy (e.g. bestsellers matching “wireless charger”)
  • Merchandising widgets that need filtered top-N lists with facet sidebars
The filter contract is identical to /recommendations/automatic — same filter shape, same Joi schema — extended with four additional dimensions (excluded_tags, collections, product_types, price). Those extensions are also accepted by the automatic endpoint going forward.
Authentication. Pass Authorization: Bearer <shop storefront token> and x-shop: <myshopify domain> on every call. See Get Started → Headless Authentication for token provisioning.

Ranking strategies

Filter dimensions

filter is fully optional. Each sub-field is independently optional and combined as an AND:
  • tags / excluded_tags — include / exclude by product tag.
  • vendors — vendor names (exact match).
  • product_types — product type values.
  • collections — collection IDs the product must belong to.
  • price.min / price.max — price range in shop currency.
  • variants.is_in_stock, variants.available_for_sale — variant-level availability (matches any variant).
  • variants.options[] — variant option matches (e.g. Color: Black).
  • variants.sku[] — variant SKU match.
  • metafields[] — match by {namespace, key, value}; requires a filterKey to exist on the indexed product.
Array or comma-separated string. The list-style fields tags, excluded_tags, vendors, product_types, and collections accept either a JSON array of strings or a single comma-separated string. Useful for clients whose query serializers can’t construct arrays from variables. Both forms below are equivalent:
Whitespace around commas is trimmed.

Text query

When query is provided, a multi_match clause is added across title^3, description, tags, vendor, productType with operator: AND, lenient: true. The strategy sort still wins — products matching the text query are ranked by sales (or recency), not by BM25 relevance. For relevance-first text search, use the AI Search endpoint instead.

Facets

Pass facets: ["vendor", "product_type", "tag", "price"] (any subset) to receive aggregations alongside the products. Each facet returns top values with counts. The price facet returns fixed buckets (0-50, 50-100, 100-250, 250+). Facet counts are computed using a post-filter model — each facet’s counts ignore that dimension’s filter so a sidebar UI can show “all available vendors” even when the user has selected one. Other filters still apply.

Pagination

Cursor-based, matching the rest of the v3 headless surface. The first request can pass pagination.limit (1–100, default 24). Subsequent pages pass the cursor returned in the previous response.
When paginating with a cursor, the filter, query, and strategy must stay identical to the request that produced the cursor — changing them invalidates the sort context and returns incoherent ordering.
The response includes pagination.total and pagination.totalRelation ("eq" or "gte"). Elasticsearch caps totals at 10,000 by default — when the relation is "gte", the real total is ≥ that value.

Examples

Each product carries trending_rank and sales_rank — shop-wide ranks refreshed daily; see the field reference.

Authorizations

Authorization
string
header
required

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

Headers

x-shop
string
required

Shopify store URL

Example:

"shop.myshopify.com"

Body

application/json

Request body

strategy
enum<string>
required

Ranking strategy to apply

Available options:
BESTSELLERS,
NEW_ARRIVALS
view
enum<string>
required

Response shape for each product entry.

Available options:
product_details,
product_ids
strategy_options
object

Strategy-specific tuning. Currently only BESTSELLERS uses this.

query
string

Optional free-text query. Applied as a multi_match across title, description, tags, vendor, and product_type. The strategy sort still wins; products matching the text query rank by sales/recency/trending score, not BM25.

filter
object

Same filter shape as /recommendations/automatic, extended with excluded_tags, collections, product_types, and price.

facets
enum<string>[]

Facet dimensions to return alongside the products. Facets are computed only when this array is non-empty.

Available options:
vendor,
product_type,
tag,
price
pagination
object
publication_ids
(string | integer)[]

Optional. Numeric Shopify publication (sales channel) ids. When present, only products published on at least one of these channels are returned and the default "published to the Online Store" gate is replaced by this filter; market and B2B filters still apply. A single id may be sent without the array wrapper. Each id must be one the merchant enabled under Settings → Sales channels; unknown ids return 400. The id is the numeric tail of gid://shopify/Publication/.

Maximum array length: 50
Pattern: ^[0-9]+$
Example:

Response

Top recommendations

status
enum<string>
Available options:
ok
serve_id
string

Unique identifier for this serve.

strategy
string

Echo of the ranking strategy that produced the results.

products
object[]
pagination
object
facets
object

Present only when the request specified facets. Each requested dimension is a top-level key.