Backend integration options

If you request results from your own server, you can call Constructor through a client library or call the REST API directly. This guide explains what each option involves, and the requirements that apply to both.

🔍

Before you start. This applies to search, autocomplete, browse, and recommendations requested from your server. Both options must send everything in Required parameters. A JavaScript beacon is required on all pages, regardless of how you request results.

A backend integration is described in Integration approaches: your web servers receive the user's query, call Constructor's REST API, and use the JSON response to render the results. This guide covers the choice you make within that approach, and applies to both websites and mobile apps that get results from your own server.

The two options

Both options send the same values to the same endpoints. The difference is how much of the request you assemble yourself: a client library knows which parameters are mandatory, so there is less that can be omitted without an error.

RequirementClient libraryREST API directly
x-cnstrc-tokenSet once when you create the clientSend on every request
X-Forwarded-ForPassed as a user parameter per requestSend on every request
User-AgentPassed as a user parameter per requestSend on every request
i, sPassed as user parameters per requestRead from cookies and send
uiPassed as a user parameter per requestRead from your own session and send
cSet for you. Do not send it yourselfYou must send it
Request format changesUpgrade the libraryTrack and apply yourself

Requirements for both options

Every requirement is documented in Required parameters. Read it before you begin. Two points deserve emphasis here, because they cause problems that are not visible in a response.

❗️

Send x-cnstrc-token on every request. Requests that omit it are highly likely to be throttled, so a missing token affects availability, not only reporting. Treat this value as sensitive and never expose it client side.

Sending the same identifiers as your tracking

The anonymous user identifier i and session identifier s are set by the Constructor beacon and stored in the user's browser. In a backend integration, read them from the ConstructorioID_client_id and ConstructorioID_session_id cookies and send them with each request. See Identification parameters for how these values are assigned and stored.

The user identifier ui works differently. It is optional, it is your own account identifier for a signed-in user, and Constructor does not set a cookie for it. Read it from your application's own session and send it only for signed-in users. It ties one person's separate client and session identifiers together across devices.

Because your server requests results while the beacon sends behavioral events, both must use the same values for one user. Decide which side sets these identifiers, and have the other read them. Usually the beacon sets the cookies and your server reads them.

When the cookies do not exist yet

On a user's first visit, your server can run before the beacon has created the cookies. The two identifiers behave differently in this case, so handle them separately.

For the client ID, your server can generate a UUID, send it as i, and set the ConstructorioID_client_id cookie in its response. When the beacon loads, it reads that cookie and keeps the value, so the results request and the events that follow it describe one user.

For the session ID, send 1 and let the beacon own the value from then on. The beacon derives the session number from its own ConstructorioID_session cookie and writes ConstructorioID_session_id for you to read. It does not read ConstructorioID_session_id back, so a value your server writes there is overwritten rather than adopted.

📘

Generate an identifier only when the cookie is absent. A server that generates one on every request gives each request a new client ID, which records one user as many. Read the cookie first, and generate a value only when there is nothing to read.

🚧

Identifiers that do not match are the most common problem in a backend integration. If your server sends different values than the beacon, one user is recorded as two. Every request succeeds, and results are returned as normal, but personalization and attribution are affected.

Caching results

Results are personalized per user. If your server caches results, exclude personalized responses from shared caches, or include the client ID (i) in the cache key, and the user ID (ui) as well when you send one, so one user's results are not served to another.

Requests from a mobile app

An app has no browser User-Agent to forward, so construct one using the iOS and Android formats in Required parameters. A generic or malformed value affects device identification, which is usually why app traffic is reported as desktop.

An app also has no browser beacon, so the identifiers come from the iOS or Android SDK instead. See Identifiers in a mobile app.

Using a client library

Libraries are available for Node, Java, Python, and .NET. See Client libraries / SDKs for installation, and the GitHub wiki for each library for the backend parameters: Node, Java, Python, .NET.

📘

Library parameter names differ from the header names. Each library uses its own naming. For example, the token is securityToken in Node and security_token in Python, and the originating IP address is userParameters.userIp in Node and UserInfo.forwardedFor in .NET. The value you set is usually not named after the header it becomes, so search the wiki for your library by meaning rather than by header name.

Set the token when you create the client. Each library already points at Constructor's endpoint, so leave the service URL option unset unless your Constructor contact gives you a specific value. Pass the user parameters with each request, so that each request carries the values for the user it is made for. These parameters are the originating IP address, the user agent, the client ID, the session ID, and the user ID.

Identifiers in a mobile app

The libraries above run on your server. An app needs one more piece, because there is no browser beacon to create i and s. Constructor's mobile SDKs fill that role: iOS / Swift and Android / Kotlin. Both are listed with the rest in Client libraries / SDKs.

Add the SDK to your app so that it sends behavioral events, then read the identifiers it holds and send them to your own server with each results request. In Swift the properties are clientID and sessionID, and in Kotlin the methods are getClientId() and getSessionId(). Store them under the same ConstructorioID_client_id and ConstructorioID_session_id names your server already reads, so an app and a website work the same way on your side.

🚧

An app that generates its own identifiers is the mobile version of the mismatch above. If your app invents i and s rather than taking them from the SDK, the events the SDK sends and the results your server requests describe two different users.

Calling the REST API directly

The endpoints are documented in the API Reference: Search, Autocomplete, Browse, and Recommendations. Required parameters describes the headers and query parameters for this case.

Because no library sets values for you, send the c parameter yourself, in the format cio-be-[web|mobile]-[company name]. A website sends cio-be-web-farmstand and an app sends cio-be-mobile-farmstand. Use the same company name that your Constructor dashboard shows, in lowercase. Without this parameter, requests cannot be identified in reporting.

If a client library is available for your language, consider Client library usage justification before choosing this option.

Verifying your integration

Most problems in a backend integration return a valid response, so confirm these points before you go live.

  • Identifiers match between results and events. For one user, confirm the client ID in a results request is the same as the client ID in the tracking events.
  • Different users have different client IDs. If all requests share one value, your server is generating a new identifier per request instead of reading the cookie first.
  • Identifiers persist. Confirm the client ID (i) survives a page reload and the start of a new session. For an app, confirm it survives a restart. The session identifier (s) is expected to change when a new session starts, so a new value there is correct.
  • Every request carries the mandatory values. Inspect live requests and confirm the IP address and user agent are the user's, not your server's.
  • No throttling. Check for 429 responses, which indicate a missing or incorrect token.
  • Traffic is reported on the right platform. Confirm app traffic is reported as app traffic in the dashboard.
  • Personalized responses are not shared. Confirm your cache does not return one user's results to another.

Recommended order of work

  1. Confirm your catalog is loaded into a test index, so there is data to return.
  2. Request the API token from your Constructor contact.
  3. Place the beacon, so that i and s exist in cookies for your server to read.
  4. Build the integration against a test index and inspect live requests.
  5. Run the checks above, then move to your production index.
📘

Place the beacon before you build the integration. Your server reads i and s from cookies the beacon sets. Without it, the only identifiers your server has are the ones it generates itself, and no events arrive to match them.


Did this page help you?