Recombee Docs
Visit recombee.comStart Free
User Documentation
Admin UI
ReQL
API Clients & Integrations
Scenario Recipes
Misc

Integration Guide for AI Assistants

This document is meant for AI-based tools and contains operational knowledge for wiring an application up to Recombee, written to sit between the official docs and the reality of an integration. It is deliberately repository-agnostic. Where it describes behavior, that behavior is server-side API behavior and holds regardless of language or SDK.

Note on intended audience

This document is written for machine readers — AI coding assistants, agents, chatbots, and similar automated tools tasked with carrying out a Recombee integration. It assumes its reader is executing the work rather than casually browsing, and it is structured and phrased accordingly: explicit behavior over narrative, pitfalls flagged directly.

Recombee is a hosted recommendation and search engine. You feed it three things and it gives you back two things:

In:

  • Item Catalog — your items (articles, products, videos, …) and their properties.
  • User Catalog (optional) — your users and their properties.
  • Interactions — events describing what users do with those items (detail views, purchases, ratings, bookmarks, …).

Out:

  • Recommendations — ranked items for a user, for an item, or for the next page of a feed, produced by models Recombee trains on your data.
  • Search — full-text search over the catalog, ranked with the same personalization.

The mental model is simple: interactions + catalog in, recommendations + search out. Everything else in this document is about doing that cleanly.


Prefer an official SDK over hand-rolling HTTP. Recombee publishes client libraries for most common languages. They handle request signing, request/response shapes and batching, and are kept up to date with the API. If your stack has an SDK, use it.

  • Server-side SDKs: Java, Ruby, Node.js, PHP, Python, .NET, Go.
  • Client-side SDKs: JavaScript, Kotlin (Android), Swift (iOS).

The difference between the two families matters — see Authentication.

API reference: docs.recombee.com/api.md. The API client list is at docs.recombee.com/api_clients.md.

Start from a Scenario Recipe. docs.recombee.com/llms.txt is an LLM-oriented index of the whole documentation set, and it contains a Scenario Recipes section that is the single most useful starting point when implementing a concrete surface. Recipes are organized by vertical and then by use case, at docs.recombee.com/recipes/{vertical}/{use-case}/{recipe}.

Each recipe gives the recommended scenario settings for that use case — which logic to pick and its parameters, plus the filters, boosters and constraints worth configuring — and then basic integration guidance for requesting the recommendations. Since scenario configuration is a manual Admin UI step you have to specify precisely (Getting recommendations), read the matching recipe before designing a surface and follow its settings rather than inventing your own. Fetch llms.txt first to find the recipe that fits; append .md to a recipe URL for its plain-markdown form. For implementing use cases not covered by a recipe, use the rest of this document as a reference and consult the API docs.

Let the SDK be your reference. The SDKs ship with extensive inline documentation — every request class and parameter is commented, and those comments track the API reference. In most cases the fastest, most reliable way to pick the right endpoint and its parameters is to install the SDK and read its built-in comments and type definitions directly, rather than working from memory or from this file. The installed source is version-matched to what you'll actually call, so it won't drift the way a hand-written guide can.

This document may be out of date

Available SDKs, endpoint names, and defaults change. Before relying on a specific SDK, endpoint, or parameter, confirm it against the live docs pages above — or the SDK's own comments. Treat this file as orientation, not as the source of truth.


There are two tokens per database, and they map onto the two SDK families:

Private tokenPublic token
Used by

Server-side SDKs

Client-side SDKs

Runs in

Your backend / serverless functions

Browser / mobile app, talking to Recombee directly

API surface

Everything (catalog, properties, batch, interactions, recommendations, search, admin)

Interactions, recommendations, and search only (see note on merging)

Exposure

Must never reach the client. Anyone holding it can read/modify the whole database.

Designed to ship in client bundles; scoped by Recombee to safe operations.

Best practices:

  • Keep the private token in server-side configuration/secrets only. Do not inline it into client code, commit it, or send it to the browser.
  • Use the public token (via a client-side SDK) for calls that legitimately originate on the client — recording interactions, requesting recommendations, running search. These go directly from client to Recombee; you do not need to build a signing proxy for them.
  • Merge Users is the exception: it is server-side only by default. The public token can only call it if the database has client-side merging enabled, so route it through a backend endpoint that uses the private token (or ask Recombee support to enable client-side merging for your database). Don't design the login flow around a browser-side merge until you've confirmed it's enabled.
  • Use the private token (via a server-side SDK) for everything the public token can't do — catalog and property management, batch uploads, admin operations.
  • Load the database name and tokens from environment/secrets. Never hard-code a fallback database name (e.g. env.RECOMBEE_DB || "some-db") — a wrong default silently points production at the wrong database. Fail loudly when configuration is missing.

Direct REST for unsupported languages. If no SDK exists for your stack, call the REST API directly. Authentication is HMAC-SHA1: sign the full request path — including the /{databaseId} prefix and the query string — with the private token, append hmac_timestamp, then append &hmac_sign=<hex>. Because this uses the private token, it must run server-side behind your own proxy; the proxy should pass Recombee's status code and response body through unchanged. Sign the final path (query params included), then append the signature. This is exactly the mechanical work an SDK exists to remove, so reach for REST only when you have no SDK option.


Every user and every item is referenced by a string ID. Keep IDs stable, URL-safe, and within Recombee's allowed character set (alphanumerics plus a small set of symbols — check the docs for the exact rules). The ID is your join key between systems.

Anonymous vs. authenticated users:

  • For a not-yet-logged-in visitor, generate a random, persistent ID (e.g. a UUID) and store it (cookie/local storage/device store). Use it for all of that visitor's interactions and recommendation requests.
  • When that visitor logs in, call the Merge Users endpoint to merge the anonymous ID into the authenticated user's ID. This folds the anonymous interaction history into the real profile so nothing learned before login is lost. This call needs the private token unless specified otherwise — see Authentication — so it belongs on your backend, not in the browser.

Identity consistency is a hard requirement. The userId and itemId you send in interaction events must be byte-for-byte identical to the IDs used in recommendation requests and catalog updates. If a recommendation returns item article-42 and the user clicks it, the resulting detail-view interaction must reference article-42 — not Article-42, not 42, not an internal database primary key. Any mismatch silently breaks attribution and model training: Recombee treats the two spellings as different entities, interactions never connect to the items they concern, and recommendation quality quietly degrades with no error to alert you. Decide on one canonical ID per user and per item, and use it everywhere.


Recombee needs to know about your items and their properties before it can recommend them or filter on them. There are two ways to get the catalog in:

A) Catalog feed (JSON, XML, RSS). Configure a feed URL in the Recombee Admin UI and Recombee pulls and refreshes the catalog on a schedule. This is the better choice when the app already publishes a product/article feed, or when you'd rather not write bespoke sync code. If a feed fits, prefer directing the user to set one up in the Admin UI instead of writing an uploader. However, if real-time updates are important, or if you want to control the sync process in your own codebase, use the API instead.

B) Direct API integration. Define item properties and push item values through the API. Property definitions are not created lazily — writing a value to an undefined property fails until the property exists. Make property definition an idempotent part of your sync (re-declare on every run; it's cheap). For the actual upload, use Batch requests — sending N items as N sequential calls is slow and will hit serverless execution limits. One batched request carries hundreds of operations.

Put everything you'll need into the catalog. Recombee can return item metadata as part of a recommendation response (request the item properties you want back). So anything that will be displayed in the UI, used for analytics, consumed by recommender logic, or referenced by business rules / filters should live in the catalog as an item property. If it isn't in the catalog, you can't render it from a recommendation response or filter/boost on it.

Users are catalogued the same way. The optional user catalog works exactly like the item catalog: define user properties, then set values on them (in bulk via Batch). Populating it is optional — users are also created implicitly when you record their first interaction (see cascadeCreate in Recording interactions) — but user properties are worth setting when you want to filter, boost, or segment on them.


Interactions are the signal Recombee learns from. Recombee models several interaction data types, including:

  • Detail view — user looked at an item.
  • Purchase — user bought an item.
  • Rating — user gave an explicit score.
  • Cart addition — user added an item to a cart.
  • Bookmark — user saved an item.
  • View portion — how much of an item was consumed (e.g. video/article progress).

These will not always map cleanly onto your application's existing event types. Pick the Recombee type whose intent best matches each of your events rather than forcing a one-to-one mapping, and don't invent semantics a type doesn't have.

Two rules that matter:

  • Always allow entity creation on interactions (the cascadeCreate option) so an event for a brand-new user or item doesn't fail because the entity isn't known yet.
  • For any interaction that resulted from a recommendation, always include the recommId from that recommendation's response. This is how Recombee attributes outcomes back to the model that produced them — it's what makes reporting and A/B evaluation meaningful. Thread the recommId from the recommendation response through to the interaction call. (And remember The identity model: the IDs on the interaction must match the ones from the recommendation.)

Writes are not immediately readable. An interaction takes roughly 5 seconds to become visible to the listing endpoints (ListUserDetailViews, ListUserRatings, …). Code that writes an interaction and reads it straight back will see nothing and conclude the write failed. Anywhere you need read-after-write, poll with a timeout (~30s) rather than asserting once, and distinguish "not visible yet" (lag) from "visible but wrong" (a real bug). The same applies to Merge Users: wait for the source user's history to actually land before merging, or there is nothing there to move.

recommId values are dash-insensitive. Recombee may hand back a UUID formatted differently from the one it issued, so never compare recommIds with string equality — normalize both sides first (e.g. id.replaceAll("-", "")).


Use the recommendation request that fits the surface. Requests vary along two axes: what you want back (items, users, or item segments) and what it's based on (a user, an item, an item segment, or a search query). The request names follow this pattern — e.g. Recommend Items to User for a personalized feed, Recommend Items to Item for related items on a detail page, or Search Items when the user types a query. Consult the SDK/docs for the full set, since the available combinations change.

Every request must name a scenario — and you must create it first. A scenario identifies the surface a recommendation is for ("homepage-rail", "product-detail-related"). This is not a stylistic nicety: scenarios are never auto-created, and a request naming one that doesn't exist is rejected outright:

{"message": "Scenario does not exist. Please create the Scenario in the Recombee Admin UI"}   ← HTTP 403

Scenarios are also where per-surface filters, boosters and recommendation logic are configured, and they're how Recombee reports each surface's performance separately — one shared scenario across every rail throws all of that away. The extra setup step is the intended Recombee workflow, so accept the cost rather than designing around it.

Because the integration is dead until the user creates them, your setup documentation must list every scenario ID together with its type (Ranked List, Composite, …) and its stage configuration. Treat that list as a hard deliverable of the integration, not an appendix. Don't invent that configuration from scratch — find the matching Scenario Recipe (API prerequisites) and take its recommended logic, parameters, filters, boosters and constraints as your starting point.

Item Segments. An item segment is a named group of items derived from the catalog — for example a genre, a brand, a topic, or any grouping you define with a ReQL expression over item properties. Alongside recommending individual items, Recombee can recommend segments: instead of "which items should this user see," you ask "which topics/brands is this user interested in." Use segments to build things like a personalized list of categories, a "browse by topic" rail ordered per user, or the row titles of a homepage whose contents are then filled with item recommendations. Segments do not have properties or interactions. Check the SDK/docs for the exact segment requests available and how to configure the segmentations themselves (in the Admin UI or via the API). Note that ListSegmentations returns an object — {"segmentations": [...]} — not a bare array.

Composite Recommendations — reach for these first. A composite request returns a source entity together with the result entities recommended for it — for example a source segment ("Science Fiction") plus the result items within it. The source can be based on a user, item, segment, or search query, and the results can be items, users, or segments. The sample response below shows the resulting source + recomms shape.

Whenever a surface is "source + results", use a composite request. That covers genre and category rails, a personalized 2D homepage (each row is one source with its results), and "Because you liked X". Do not hand-roll it as Recommend Item Segments to User followed by Recommend Items to Item Segment — composite is the current idiomatic API for exactly this shape.

To fill a page with N rows, send N composite requests in a single Batch with distinctRecomms: true. That flag is what makes N otherwise-identical requests return N different sources; without it you get N copies of the same top row.

Never set rotationRate (with or without rotationTime). Rotation works by penalising items purely for having been recommended recently, which demotes the genuinely best-matching items and can significantly harm recommendation quality. Don't reach for it to make a rail look "fresh" between page loads. If a surface really needs more variety, use diversity or configure it at the scenario level, and otherwise let the models rank freely.

Pagination / subsequent pages. After an initial recommendation, load further pages with Recommend Next Items (or Recommend Next Item Segments for segment-based rails) rather than re-requesting from scratch. This continues the same recommendation, keeps results consistent, and preserves attribution.

Multiple rails at once. When instead a page needs several independent recommendation requests together, batch them into a single request — it's fewer round trips, lower latency than firing the calls sequentially, and with distinctRecomms: true, the results are deduplicated, which is preferred. This applies to both composite and non-composite requests. For example, a homepage with three rails of "Science Fiction", "Romance", and "Mystery" should be a single batch of three Recommend Items to Item Segment calls, not three separate calls.

A sample recommendation response looks as follows:

{
  "recommId": "ee94fa8b-efe7-4b35-abc6-2bc3456d66ed",
  "source": {
    "id": "category-4",
    "values": {
      "name": "Science Fiction"
    }
  },
  "recomms": [
    {
      "id": "item-64",
      "values": {
        "title": "The Martian",
        "author": "Andy Weir"
      }
    },
    {
      "id": "item-42",
      "values": {
        "title": "Dune",
        "author": "Frank Herbert"
      }
    },
    {
      "id": "item-23",
      "values": {
        "title": "Neuromancer",
        "author": "William Gibson"
      }
    }
  ],
  "numberNextRecommsCalls": 0
}

This JSON is mapped onto the SDK's response objects, but the fields are the same. The recommId is the unique identifier for this recommendation response, and must be included in any interaction events that result from it. The source object is present only for composite recommendations; a plain request (e.g. Recommend Items to User) returns just recommId and recomms. The values object contains the requested item/user properties for each recommended item/user, but is only present if returnProperties was set in the request. For requesting only certain properties, use returnProperties with includedProperties. numberNextRecommsCalls reports how many times Recommend Next Items has been called for this recommId so far: a single recommendation can be extended by repeated Recommend Next Items calls, each returning further, previously-unrecommended items, and this field tracks how many such calls have happened.


  1. Hand-rolling REST + HMAC signing when an SDK exists. Signing, request shapes, and batching are exactly what the SDKs handle. Check the API clients page first.
  2. Crossing the token/side boundary. Private token in client code (a full-database leak) or expecting the public token to do server-only work. Keep private→server, public→client.
  3. Inconsistent IDs. Interaction IDs that don't match recommendation/catalog IDs — see The identity model. Silent, and corrosive to quality.
  4. Forgetting recommId. Interactions from recommendations without it can't be attributed; your reporting and experiments go dark.
  5. Writing to undefined properties. Define item/user properties (both namespaces) before writing values; make it part of an idempotent sync.
  6. Hard-coded database fallbacks. A default DB name masks misconfiguration and can point production at the wrong database. Fail loudly instead.
  7. Error handling that discards the upstream body. Wrapping failures in a generic {"error": "request failed"} throws away the one thing that explains the failure.
  8. Assuming a 404 means "wrong URL". In Recombee it almost always means "the referenced entity doesn't exist" — read the body (see Error & edge-case reference).
  9. Infinite client retries on 4xx. A 4xx is an answer, not an outage. Retry only network errors and 5xx, with a cap.
  10. Sequential uploads / per-rail calls. Use Batch for catalog sync and for multi-rail recommendation pages.
  11. Omitting scenario, or naming one nobody created. A 403 that stops the surface dead — see Getting recommendations. Ship the scenario list as part of the setup instructions.
  12. Hand-rolling composite as a segments-then-items two-step. Use Composite Recommendation; batch N of them with distinctRecomms: true for N distinct rows.
  13. Using rotationRate for "freshness". It trades real relevance for the appearance of variety. Leave rotation parameters out entirely.
  14. Asserting on an interaction immediately after writing it. ~5s of read-back lag makes this a false failure; poll instead (Recording interactions).
  15. Comparing recommIds with ---. Dashes are not significant — normalize first (Recording interactions).

  • Read the response body, always. Log the status code and a snippet of the response body at every Recombee call site. Recombee encodes the reason for a failure in the body; debugging on status + URL alone is debugging blind.
  • Test the call sites that actually fail — with their real payloads. A smoke test that only exercises recommendations will pass while catalog or user-property writes fail in production. Replay each distinct call-site payload, not just the convenient endpoints.
  • Verify identity end-to-end. Confirm that the ID on a recorded interaction is identical to the ID that came back in the recommendation the user acted on. This is the check that catches the silent identity-model failures.
  • Confirm recommId round-trips. Trace a recommendation's recommId all the way into the interaction it produces — comparing on the dash-stripped form.
  • Budget for write lag in every check. Interactions take ~5s to become readable, so any verification that reads back what it just wrote must poll to a ~30s timeout. A test that asserts immediately reports a bug that isn't there and sends you hunting it.
  • Check the Admin UI. After a catalog sync or a batch of interactions, confirm items and events actually appear in the database in the Recombee Admin UI.

The one rule: Recombee uses HTTP status codes semantically. Always read the response body before theorizing about a status. A 404 usually does not mean "wrong URL" — it means "the entity you referenced does not exist," and the body names which one:

{"message": "user property \"prefLens\" does not exist!"}   ← HTTP 404

Status → meaning cheat sheet:

StatusBody saysActual meaningFix
401

invalid token/db

wrong token, wrong DB name, or token↔db mismatch

check the token and DB name together — a valid token for the wrong DB is still 401

404

... property "X" does not exist

you wrote to an undefined property

define the property first (both item and user namespaces exist)

404

item/user "X" does not exist

referenced entity missing and creation wasn't allowed

enable cascadeCreate on the request

403

Scenario does not exist ...

the request named a scenario that hasn't been created

create it in the Admin UI — scenarios are never auto-created (Getting recommendations)

405

Method not allowed

newer clusters reject GET listing endpoints

use the POST equivalents; on an SDK this is handled for you

409

duplicate

the write already happened

treat as success — don't retry

400

Error in expression ... single quotes ... double quotes

ReQL filter quoting: 'x' = property access, "x" = string constant

fix the filter; filtering on an undefined property errors the same way

Batch results are per-entry. A Batch request can return 200 overall while individual sub-requests inside it fail. Inspect each entry's own status rather than assuming the batch succeeded or failed as a unit.

Retry policy. Any HTTP response settles the request. Retry only genuine network errors and 5xx, with a small cap. Never retry a 4xx in a loop — an offline queue re-sending a 404 forever produces console noise that masks the real signal.

Two separate property namespaces. Item properties and user properties are defined independently. It's easy to define all your item properties and forget the user ones; then every user-property write fails in production while item-only smoke tests pass.

© Copyright 2026, Recombee s.r.o
docs.recombee.com