Skip to main content
TelemetryEvent is the SDK’s primitive for product telemetry — user actions, tool calls, agent decisions, anything you’d send to a product analytics tool. Events are pushed independently of trajectories, and can be correlated to them via trace_id (see Linking Events to Trajectories).

Quickstart

For telemetry-only usage, only project_id and trajectory_api_key are required in init() — no provider credentials needed.
import trajectory_sdk as tj

tj.init(project_id="acme", trajectory_api_key="tj_key_...")

result = tj.push_events([
    tj.TelemetryEvent(
        event_type="user.accept",
        session_id="session-123",
        properties={"surface": "chat", "model": "gpt-4o"},
    ),
])

print(result.pushed, result.skipped, result.errors)

Constructing Events

TelemetryEvent is a frozen dataclass. Only event_type and session_id are required; every other field has a sensible default.
event = tj.TelemetryEvent(
    event_type="tool.call",
    session_id="session-123",
    properties={"tool": "search", "query": "refunds policy"},
    user_id="user-abc",
    trace_id="req_01HXYZ",
    trajectory_id="traj_xyz",
    source="my_app",
    metadata={"app_version": "2.4.0"},
)
FieldTypeDefaultDescription
event_typestrrequiredDotted event name (e.g. user.accept, tool.call).
session_idstrrequiredSession grouping. Defaults to trace_id when produced via TraceContext.event(...).
propertiesdict{}Free-form event payload.
event_idstrnew UUID4 hexIdempotency key (see below).
timestampstrnow (UTC ISO)Event time. Pass an explicit value to backdate.
user_idstr | NoneNoneEnd-user identifier.
trajectory_idstr | NoneNoneBackend trajectory ID once known.
trace_idstr | NoneNoneCaller-owned correlation key. Always set when producing events via TraceContext.
sourcestr"sdk"Where the event originated.
metadatadict | NoneNoneAdditional context not part of properties.

Idempotency

event_id is the idempotency key. The default UUID4 means re-runs of the same code produce different IDs (and the backend will accept both as separate events). For at-least-once delivery pipelines — webhooks, retries, replay from a queue — set event_id deterministically from your own primary key so duplicate pushes are coalesced server-side:
import hashlib

def event_id_for(record_id: str) -> str:
    return hashlib.sha256(record_id.encode()).hexdigest()

event = tj.TelemetryEvent(
    event_type="user.accept",
    session_id="session-123",
    event_id=event_id_for(record["id"]),
)
Re-pushing the same event_id is a no-op on the backend.

Pushing Events

tj.push_events(events) validates, chunks, retries, and pushes a batch of events.
result = tj.push_events(
    events,
    organization_id="org_42",
    chunk_size=1000,
    max_retries=3,
)
ParameterTypeDefaultDescription
eventslist[TelemetryEvent]requiredEvents to push.
organization_idstr | NoneNoneLogged client-side for attribution. The backend derives the authoritative org from the API key.
chunk_sizeint1000Max events per HTTP request. The SDK splits longer lists automatically.
max_retriesint3Per-chunk retry budget on transient failures.
The call returns a PushResult:
FieldTypeDescription
pushedintEvents accepted by the backend.
skippedintEvents dropped client-side as invalid.
errorslist[str]One message per invalid event.
Invalid events are dropped with a logged warning rather than raising. This matches the pattern used by upload() for empty trajectories: bad inputs don’t poison a whole batch. Inspect result.errors to see what was rejected.

Producing Events via TraceContext

When you’re already inside a TraceContext (the recommended path for SDK-instrumented agent runs), use trace.event(...) so events automatically inherit the trace_id:
trace = tj.start_trace()

trace.event("tool.call", {"tool": "search"})
trace.event("tool.result", {"ok": True}, user_id="user-abc")

# trace.events is the accumulated buffer
tj.push_events(trace.events)
TraceContext.event(...) sets session_id = trace_id automatically. Override either via the keyword arguments if you need a different grouping. See Linking Events to Trajectories for the full workflow, including tj.upload_trace() which uploads a trajectory and pushes correlated events in one atomic call.

Linking Events to Trajectories

The trace_id correlation story end-to-end.

API Reference

Full signatures for push_events, TelemetryEvent, PushResult.