Flow: Recommendations
Product recommendation endpoints served by the search proxy. Includes similar products, search suggestions, and personalized recommendations.
Request Path
graph TD
A["Customer App"]
subgraph cf["Cloudflare Worker (search_proxy: {env}-ecom-api)"]
B["Auth & Settings middleware (same as search)"]
subgraph rec["Recommendation handler"]
C["Parallel context searches via MARQO_WORKER"]
D["Marqo search suggestions API"]
E["PIXEL_WORKER RPC for personalization data"]
end
F["Response with deduplicated results"]
G["Metrics enqueue (SQS)"]
end
H["Customer App"]
A --> B
B -->|Similar / For-You| C
B -->|Suggestions| D
B -->|For-You| E
C --> F
D --> F
E --> F
F --> H
F -.->|background| G
Endpoints
| Endpoint | Purpose | Key Input |
|---|---|---|
POST /api/v1/indexes/:index/recommendations/similar |
Products like these | documentIds[] (1-10) |
POST /api/v1/indexes/:index/recommendations/complementary |
Products that pair well | documentIds[] (not yet implemented) |
POST /api/v1/indexes/:index/recommendations/queries |
Search suggestions / autocomplete | q (query prefix) |
POST /api/v1/indexes/:index/recommendations/for-you |
Personalized recommendations | userId (required) |
Similar Products
Where: components/search_proxy/src/recommendations.ts
How It Works
- Splits
documentIdsinto up to 6 arrays (Cloudflare concurrent connection limit) - Sends parallel context searches to Marqo using HYBRID search with tensor ranking
- Each search uses document context (the seed products) with
excludeInputDocuments: true - Results interleaved and deduplicated by
_idandcollapseFields
Marqo request key params:
{
"searchMethod": "HYBRID",
"hybridParameters": { "retrievalMethod": "tensor", "rankingMethod": "tensor" },
"context": { "documents": { "ids": { "doc_id": 1 } } }
}
Logs:
{"message": "marqo_context_search_request", "url": "..."}
{"message": "marqo_search_response", "hitsCount": 10, "processingTimeMs": 30}
Search Suggestions
Where: components/search_proxy/src/recommendations.ts
Calls Marqo's search suggestions API with:
q— query prefixfuzzyEditDistance— typo tolerance (default 0)minFuzzyMatchLength— minimum chars for fuzzy (default 3)- Config from
search_suggestions_configin settings
Returns: { suggestions: [{ suggestion, score }] }
Personalized (For-You)
Where: components/search_proxy/src/recommendations.ts
How It Works
- Requires
pixel_idin settings (400 error if not configured) - Pixel Worker RPC:
env.PIXEL_WORKER.getPersonalizationData(pixelId, userId, sessionId)— fetches tracked events (clicks, add-to-cart, purchases) - Optional filter by
interactionTypes(ClickEvent, AddToCartEvent, PurchaseEvent) - Takes first 60 document IDs from tracked events
- Runs same parallel context search as similar products
Fallback: If no tracked events found → NoTrackedEventsError caught → falls back to wildcard search (q: "*") with any provided filters. Returns general products instead of failure.
Inspect: Pixel Worker is a separate Cloudflare Worker bound via service binding. Check its logs:
npx wrangler tail pixel-ingestion-worker-{env_suffix}
What to Look For
| Symptom | Where to Check |
|---|---|
| 401 on recommendations | Same auth as search — see Search. |
| 404 "Not configured" | Settings not in KV. Check Settings Sync. |
| Similar returns no results | Seed documents exist in index? Check filter expression. |
| Complementary returns 400 | Expected — not yet implemented. |
| Suggestions returning nothing | Index has searchable text? Check search_suggestions_config. |
| For-you returning generic results | No tracked events for userId (falls back to wildcard q: "*" search). Check Pixel Worker logs. |
| For-you returning 400 | pixel_id not configured in index settings. Check Settings Sync. |
| Slow recommendations | Multiple parallel Marqo calls. Check per-call processingTimeMs. |
Related Docs
- Search Proxy — worker bindings including PIXEL_WORKER
- Search — auth, settings, and KV lookup (shared middleware)
- Cloudflare Workers — how to tail workers
- Settings Sync — how settings reach KV