Skip to main content

Complementary Recommendations

Complementary recommendations​

POST /api/v1/indexes/{index_name}/recommendations/complementary

Purpose​

Drive cross-sell by suggesting items frequently purchased or interacted with together. Complementary recommendations use machine learning to analyze purchase patterns, co-occurrence data, and product relationships to identify items that naturally pair with what the customer is already considering. Unlike similar recommendations that offer alternatives, complementary suggestions work synergistically with the base product to optimize for increased Average Order Value (AOV).

When to use​

  • Cross-sell opportunities: When customers are viewing or have added items that commonly pair with accessories, add-ons, or complementary products
  • Bundle optimization: To suggest logical product combinations that increase basket size
  • Cart abandonment recovery: To add value perception through relevant add-ons

Example uses​

Use CaseDescriptionInput ProductsBusiness Impact
Frequently Bought TogetherSuggest items commonly purchased alongside the current productMain product from PDP or cartDrives cross-sell, leverages proven purchase patterns
Cart CompletionRecommend add-ons or accessories before checkoutAll items currently in cartLast-chance revenue boost, reduces post-purchase regret
Bundle SuggestionsShow products that work together as a logical set or packagePrimary product or category anchorCreates value perception, increases basket size
Cross-Sell OpportunitiesSuggest complementary items from different categoriesAny product as anchor pointDiversifies purchase, introduces new product categories

Event types (eventType)​

The eventType parameter controls which co-interaction signal is used to generate recommendations:

  • ClickEvent — "customers also viewed". Based on products that users frequently view together.
  • AddToCartEvent — "customers also added to cart". Based on products that users frequently add to cart together.
  • PurchaseEvent — "frequently bought together". Based on products that users frequently purchase together.

How multiple docIds work​

When multiple docIds are provided, results are products that are complementary to any of the input items. This is useful for checkout-page cross-sell where you want to recommend items based on the entire cart.

Example (cURL)​

curl -X POST https://ecom.marqo-ep.ai/api/v1/indexes/${index_name}/recommendations/complementary \
-H "x-marqo-index-id: ${MARQO_INDEX_ID}" \
-H "Content-Type: application/json" \
-d '{
"docIds": ["shirt_123"],
"eventTypes": ["ClickEvent", "AddToCartEvent", "PurchaseEvent"],
"limit": 6
}'

Multi-doc example (checkout cross-sell)​

curl -X POST https://ecom.marqo-ep.ai/api/v1/indexes/${index_name}/recommendations/complementary \
-H "x-marqo-index-id: ${MARQO_INDEX_ID}" \
-H "Content-Type: application/json" \
-d '{
"docIds": ["shirt_123", "pants_456"],
"eventTypes": ["ClickEvent", "AddToCartEvent", "PurchaseEvent"],
"minFrequency": 5,
"limit": 4,
"filter": "in_stock:true"
}'

Parameters​

Filters use the Marqo Filter DSL. The input item(s) are never returned. The endpoint uses strict validation: any unrecognised parameter returns a 400 error. sortBy is not accepted on this endpoint; results are ordered by co-interaction strength.

NameTypeRequiredDescriptionExample
docIdsarray[string]yesAn array of 1-10 Marqo document IDs (the _id field) to anchor the complements. Note the name: this endpoint uses docIds, while /similar and /complete-the-look use documentIds.["shirt_123"]
eventTypestringone of eventType / eventTypesA single co-interaction type: ClickEvent, AddToCartEvent or PurchaseEvent."PurchaseEvent"
eventTypesarray[string]one of eventType / eventTypesThe co-interaction types to base recommendations on. At least one of ClickEvent, AddToCartEvent, PurchaseEvent.["ClickEvent", "AddToCartEvent", "PurchaseEvent"]
limitintegernoMax number of results (default 10).6
offsetintegernoPagination offset (default 0).0
filterstringnoConstrain by stock, brand, category, price ranges. See Marqo Filter DSL."in_stock:true"
attributesToRetrievearray[string]noAttributes to return for each document. If omitted, the attribute list configured for the index is returned, the same default as search.["title", "price", "image_url"]
minFrequencyintegernoMinimum number of co-interactions required for a product to appear in results. Acts as a quality threshold; set higher to only surface strong signals. Must be a positive integer. Defaults to 1.5
userIdstringnoShopper identifier. Personalises the shelf when personalisation is enabled for the index."abc123"
sessionIdstringnoShopper session identifier, used together with userId."xyz789"
profileIdstringnoA named search configuration profile for the request (e.g. different behaviour on PDP vs checkout). If the profile does not exist, Marqo falls back to the default configuration."pdp_default"
merchandisingProfileIdstringnoThe merchandising profile whose rules (pins, exclusions, boosts, buries, filters) are applied to this shelf. This is separate from profileId, which selects search configuration. If no such profile matches, or the value is empty, the shelf's published rules apply."summer_campaign"

Exactly one of eventType or eventTypes must be provided. Sending both, or neither, returns a 400.

limit and offset must be whole, non-negative numbers. The API does not check this itself: a fractional or negative value is passed to the search engine, which rejects the request with Complementary recommendations failed: <reason>.

How the shelf is filled​

  • Top-up for thin results: on the first page (offset 0), when the co-interaction search finds fewer than five results (or fewer than limit, if limit is lower), the shelf is topped up with related products. Marqo takes products similar to the seeds and adds their complements, repeating up to three times until the target is met. Later pages (offset greater than 0) are not topped up.
  • Pins and merchandising rules: rules published for the Complementary Recommendations context in the Marqo console apply to the shelf. When exactly one docIds value is sent, the pins published for that product are placed at their positions; with several seeds, only the index-wide rules apply. merchandisingProfileId swaps in the rules of a merchandising profile instead; a profile's per-product rules are looked up only when exactly one seed is sent.
  • Personalisation: when userId is sent and personalisation is configured for the index, results are re-ranked toward the shopper's interaction history. See Personalization.

Response (example)​

{
"hits": [
{
"_id": "belt_789",
"_score": 1003.0,
"title": "Leather Belt",
"price": 59.0,
"image_url": "https://cdn.example.com/belt_789.jpg"
}
],
"processingTimeMs": 52,
"limit": 6,
"offset": 0,
"totalHits": 14,
"personalized": false
}
FieldTypeDescription
hitsarray[object]The recommended documents, each with _id, _score and the retrieved attributes. Pinned products carry the score of their neighbour so the shelf stays sortable by _score.
processingTimeMsintegerTotal server processing time in milliseconds, including any top-up rounds.
limitintegerThe limit applied to the request.
offsetintegerThe offset applied to the request.
totalHitsintegerTotal matching products, counting any pinned products inserted. When the shelf was topped up it is a single page, so totalHits equals the number of hits returned.
personalizedbooleanPresent only when userId was sent. true when the results were re-ranked toward the shopper's history.
HeaderDescription
x-marqo-cache-hit-count, x-marqo-cache-miss-countHow many of the underlying searches were served from cache and how many were not.
x-marqo-results-personalizedPresent when userId was sent. true or false, matching the personalized field.

Errors​

Error responses have the body {"error": "<message>"}.

StatusMessage
400Parameter 'docIds' is required and must be a non-empty array
400All docIds must be non-empty strings
400Number of 'docIds' must be less than or equal to 10
400Must provide exactly one of 'eventType' or 'eventTypes'
400Parameter 'eventType' must be one of: ClickEvent, AddToCartEvent, PurchaseEvent
400Each value in 'eventTypes' must be one of: ClickEvent, AddToCartEvent, PurchaseEvent
400Parameter 'eventTypes' must be a non-empty array
400Unrecognized param(s): '<name>' for any parameter not listed above, including sortBy
400Complementary recommendations failed: <reason> when the underlying search rejects the request (for example, an invalid filter)