Clicks and views
Report what shoppers click and see after a search, so Insights shows the searches that find what nobody opens.
A search with results is not yet a good search. Insights counts what shoppers click and see per query, so a search that finds products nobody opens shows as one. The React components report by themselves. A shop that draws its own results reports through the client, with the hit the answer named:
import { } from "@orbsearch/client";
const = ({ : "http://127.0.0.1:7800" });
const = await .("", { : "category_page", : "wohnen/sofas" });
const = { : ., : "product:SOFA-ASKA-2", : 1 };
export function (: ) {
.("click", () => ..()); // sent at once
return ..(, ); // a view, once half of it was visible for a second
}
..({ : ., : "home/sofa-sale" }); // seen now, such as a banner
..(); // the waiting views, before the shop replaces the page itselfEach report is an event naming the query ID of its answer, here the sofa page's, and the hit by its entity or the banner by its rule. watch returns the call that stops watching.
What the components report
A tile, a banner, a suggestion and a link to a hit beside the products each report two things:
- A click on a link in them, a middle click included. It goes at once by
navigator.sendBeacon, so a navigation never waits for it. - A view once half of the item was visible for a second, once per answer and item. Views wait in memory and go together when the page is hidden, or once 100 have gathered.
A tile "Load more" brought names the answer of the first page, with its position counted across the pages, and a sponsored one names its campaign. The query ID never goes into a link, and nothing is written to the shopper's device.
Lists of your own in React
A React list of your own names its answer with <Answer>, and each item reports through useReport, whose ref and click handlers go on the item's element:
import { , } from "@orbsearch/react";
export function ({ }: { : string }) {
return (
< ={}>
< ="product:SOFA-ASKA-2" ={1} />
</>
);
}
function ({ , }: { : string; : number }) {
const = ({ , });
return (
< {...}>
< ="/p/aska-2-sitzer-sofa">Aska 2-Sitzer-Sofa aus Samt</>
</>
);
}Both need a StorefrontProvider above them, whose client sends the reports.
Send nothing
Make the client with report: false, and every report call does nothing, the components' included. The demo storefront does so for a browser that sends Global Privacy Control:
import { } from "@orbsearch/client";
const =
typeof !== "undefined" && "globalPrivacyControl" in && . === true;
export const = ({ : "http://127.0.0.1:7800", : ! });A shop that asks for consent makes its client with report: false until the shopper agrees. If they take it back, a client made again for the same pageView with report: false also drops the views still waiting. On a server, where no beacon can go, the calls do nothing either.
The Events API underneath
The client posts each batch to POST /v1/events on the Query API, with no key and no cookie. Here is a click on the first hit of a search for "graues Sofa" (grey sofa):
query_id=$(curl -s 'http://127.0.0.1:7800/v1/search?query=graues%20Sofa' | jq -r .query_id)
curl -s http://127.0.0.1:7800/v1/events -H 'Content-Type: text/plain' \
-d '{"events": [{"type": "click", "query_id": "'"$query_id"'", "entity": "product:SOFA-ASKA-2", "position": 1}]}'{"accepted":1,"late":0}The answer is 202: accepted, and late for events whose answer is older than 48 hours. The body is read as JSON whatever its content type, since a beacon posts text/plain. A batch holds 1 to 100 events in at most 64 kB, and one malformed event refuses it whole with 400.
Reference: POST /v1/events · events_per_call · event_hours
Next
- Insights: what the merchant reads from clicks and views.
- React components: the parts that report by themselves.
- The client: one client per page load, and its page view.