@sinequa/atomic

Audit

Usage telemetry — what it records, what it feeds back into relevance, and the two ways to send it.

Audit events are how a Sinequa deployment learns what people search for and what they click. They feed the analytics dashboards, and — more importantly — the relevance models: a click recorded as a click is what makes RFM improve ranking over time.

Concept — RFM

RFM is Sinequa's Relevance Feedback Model: relevance learned from what users do — which results they click, which they like, which they mark as important. It is computed on the server from the audit events your interface sends, which is why recording a click accurately matters more than recording it at all.

Two ways to send them, and the first is almost always the right one.

Use it for
Riding a searchAn event that belongs to a query — the search itself, a facet click
Audit.notify()An event with no request of its own — a document opened, a result copied

Events that ride a request

Most calls take an audit argument. Sending the event with the request it describes is cheaper and more accurate than a separate call, because the server sees both together:

Record the search, and a facet click
src/audited-search.ts
import { AuditEventType, createAtomicClient, filter } from "@sinequa/atomic";
import type { AuditEvents, Query } from "@sinequa/atomic";

const client = createAtomicClient({
  app: "<your-app>",
  backendUrl: "https://<your-sinequa-server>",
});

await client.initializeConfig();
await client.auth.login();

/** The search itself, audited as a text search. */
export function search(text: string) {
  const audit: AuditEvents = {
    type: AuditEventType.Search_Text,
    detail: { text },
  };

  // The event travels with the query it describes — one request, not two.
  return client.api.query.search({ name: "<your-query>", text, pageSize: 10 }, audit);
}

/** A facet click is a refinement, not a new search: say so. */
export function refine(query: Query, column: string, value: string) {
  const audit: AuditEvents = {
    type: AuditEventType.Search_Refine,
    detail: { column, value },
  };

  return client.api.query.search(
    { ...query, filters: filter.eq(column, value) },
    audit,
  );
}

Standalone events

Audit.notify() is for what has no request of its own — the user opened a document, copied a link, expanded a passage:

a click on a result
import { Audit, AuditEventType } from "@sinequa/atomic";

// Fire and forget: never await it in a click handler's critical path.
void Audit.notify({
  type: AuditEventType.Click_ResultLink,
  detail: { recordId: record.id, rank: record.rank },
});

It is deliberately fire-and-forget

Audit.notify carries noRecovery, so a 401 on it is not treated as a session to repair. Telemetry arriving after a sign-out used to trigger session recovery and put a login form in front of a user who had just signed out — which is the one thing an audit call must never cause.

What the event carries

An AuditEvent is a type and an optional detail. AuditEventType is a large enum aligned with the server's own list — Search_Text, Search_Refine, Click_ResultLink, RFM_Like — and the type also accepts a custom string, so a deployment can record its own events.

The library adds two things to whatever you send:

  • A session id — a GUID regenerated after ten minutes of inactivity, which is what groups events into a "session" in the analytics.
  • The current URL, unless you pass false as the second argument.

Pitfalls

What's next

On this page