Skip to main content
This API will be removed at the end of this year. It is the current-generation storefront search API, and it is the supported and recommended way to build a custom search UI today — the Depict search modal runs on exactly these endpoints. A successor API is coming, and every team building on this one should plan for a migration before year end. Migration documentation will follow; ask your Depict contact to be notified when it is published.
Depict derives search analytics — click-through rate, zero-result queries, revenue per query, ranking feedback — entirely from client-side events. A search request on its own produces no engagement data. A custom UI must send these events itself.

POST /events

The body is a JSON array of events. Send it as Content-Type: text/plain: that keeps the request a CORS simple request, so the browser skips the preflight round trip, and it works with keepalive when the page is unloading.
The response is 202 with the number of events accepted:
Rules:
  • All events in one request must share the same merchant_id; a mixed batch is rejected with 400.
  • At most 100 events and 256 kB per request; larger requests are rejected with 413.
  • Malformed events fail the whole batch with 422.
  • Delivery is fire-and-forget. Ignore the response body in production code.
If Depict has issued your store a publishable tracking token, pass it as a query parameter: POST /events?depict_token=YOUR_TOKEN. The token is safe to ship in client-side code — it only authorises writing events for your store.

Fields on every event

string
required
Which event this is. See the table below.
string
required
Your merchant id.
string
required
The same per-tab id you send on search requests.
string
The same per-browser id you send on search requests. Without it, every visit from a returning shopper counts as a new user.
string
Storefront language, matching the search request.
string
Country code, matching the search request.
string
A UUID you generate per event. Used to de-duplicate, since keepalive requests can be delivered more than once. Strongly recommended.
string
ISO 8601 timestamp of when the event happened in the browser. The server also stamps its own arrival time; sending both makes batching and unload delay measurable.

Event types

Every search-related event carries search_id: the id of the search whose results the shopper acted on, or null if the interaction did not come from a search. Getting this right is what makes per-query analytics work. position is the zero-based index of the product in the result list. It is what makes click-through rate comparable across result sets — send it. For add_to_cart, product_id must be the main product id, the same id space as product_click and product_impression, or per-product funnels will not join. Keep the variant in variant_id and the variant SKU in sku. For purchase, transaction_product_ids are the variant SKUs, and prices are per line item after discounts. quantities, prices and transaction_product_ids are parallel arrays.

Attribution

add_to_cart and purchase usually happen long after the search, often on a different page, so the search context has to be carried across. The Depict modal does it like this, and a custom UI should follow the same rules:
  1. When the shopper clicks a result — not when the search runs — store the search_id, the query, and a timestamp in sessionStorage. A click is engagement; an abandoned search should not claim credit for a later purchase.
  2. On add_to_cart and purchase, read that record back and send its search_id and query on the event.
  3. Expire it after 30 minutes. A click half an hour before checkout is unlikely to have caused the conversion, and unbounded attribution inflates per-query conversion rates.
  4. Clear it after a purchase. A later cart event should not be re-attributed to a search that already converted.
If no record applies, send "search_id": null and "query": null rather than omitting the fields. That records the conversion as non-search traffic instead of silently dropping it.

Batching and volume

Impressions are the highest-volume event by far. Buffer them briefly and send them as one array — the Depict modal collects impressions for 50 ms and flushes whatever accumulated:
Send other event types immediately — they are rare, and a click that is batched can be lost when the page navigates away.

Worked example

Verifying

Confirm each event type reaches Depict once before you launch:
  • POST /events returns 202 with accepted equal to the number of events you sent. accepted: 0 for a non-empty batch means every event was dropped.
  • Analytics in the Depict portal appear with a processing delay — check for presence first, exact counts later.
  • Confirm search_id is populated on click, impression, add-to-cart and purchase events. Attribution silently disappears when it is null everywhere, and nothing about the response tells you it happened.