SDK Reference
Custom events
Record user actions and feature usage with sendEvent.
A custom event records something a user did at a single point in time, such as exporting a document, sharing a link, or turning on a feature. Otis analyzes these events alongside your AI interactions, so you can see what users do after the AI responds.
Use sendEvent() for these point-in-time actions. For an operation that takes time or contains other steps, such as a retrieval call or a multi-step pipeline, use traced() instead.
Record an event
import { sendEvent } from "@runotis/sdk";
sendEvent("document.export", { format: "pdf", "doc.id": "doc-456" });
sendEvent("document.export", { format: "pdf" }, { userId: "user-123" });sendEvent() takes three arguments:
- Event name. Otis uses the name exactly as you pass it, so both calls above appear in Otis as events named
document.export. - Properties. Key/value pairs that describe the event, such as the export format or the document ID. Each key appears as an attribute of the event.
- Identity (optional). A
userIdfor this event only, as{ userId }. By default an event takes its identity from the surroundingwithContext()orwrap()scope, so most calls leave this argument out.
sendEvent() works in server and browser code. It delivers events in one of three ways, depending on how your app sends data to Otis:
- After
initOtis(). Events go to Otis with the identity from the surrounding scope. This is the usual setup. - Through your own OpenTelemetry setup. Without
initOtis(), events go to the tracer provider your app registers. They reach Otis only if that provider exports to Otis, for example withOtisSpanProcessororOtisExporter(see OpenTelemetry). On this path an event does not take identity fromwithContext(), so pass the user ID in the identity argument. - With neither. Events are held in memory and never sent.
Event names
Give each event a name that describes the action, such as document.export or invite.sent, and use the same name every time the action happens. Names that begin with otis_ are reserved for events the SDK records itself, and sendEvent() throws if you use one.
What to record
Record the actions that show whether the AI helped: exports, shares, searches, invites, and the first use of a feature. These actions tell Otis whether a user acted on what the AI produced.
Properties that contain user text
Otis treats event properties as structured values, such as formats, counts and IDs. It stores them as sent and doesn't scan them for personal data. If a property holds text a user typed, such as a comment or a note, mark its key so that Otis scans the value and redacts any personal data it finds.
To mark a key, start it with otis_redact_:
sendEvent("document.export", {
format: "pdf", // stored as sent
"doc.id": "doc-456", // stored as sent
otis_redact_note: "Drafted with alice@acme.com", // scanned and redacted
});Otis removes the marker before it stores the property, so the note above is stored as note. The marker is case-insensitive and works at any level of a dotted key, so otis_redact_note, otis_redact.note and details.otis_redact_note all match. Put the marker on the part of the key that holds the text: otis_redact_note matches, but note.otis_redact doesn't. The older sensitive_ prefix works the same way.
To keep a value exactly as sent, including one that Otis would otherwise redact, use the otis_dont_redact_ marker instead. Privacy describes both markers and the full matching rules.
Related
- Feedback signals record ratings and corrections on a specific AI response.
- Funnels and artifacts record the stages a document or other artifact moves through, and tie events to that artifact.