Skip to main content
Beta. The Rust SDK is at 0.0.8. The wire contract against the Raindrop ingestion API is stable and verified end-to-end against the live backend on every push, but the crate API may still change in minor ways before 0.1.0. We recommend pinning the git tag in your Cargo.toml.

Installation

The Rust SDK is hosted on GitHub (not on crates.io). Add it to your Cargo.toml:
Smallest possible program — drops in as src/main.rs and runs:
Source code and releases live in raindrop-ai/raindrop-rust.
The Rust SDK requires Rust 1.88+ (MSRV). It is async-first and uses tokio. Most fallible methods return Result<_, Error>track_ai, track_event, identify, track_signal, the Interaction mutators (set_input, set_property, set_properties, add_attachments, patch, finish), and Client::flush / Client::close. Propagate errors with ? as you would for any fallible call. The two constructors — Client::begin(...).await and Client::resume_interaction(...) — are infallible: they always return an Interaction (a no-op handle when the client is disabled), so don’t put a ? on those.

Quick Start: Interaction API

The Interaction API uses a simple three-step pattern:
  1. begin() – Create an interaction and log the initial user input
  2. Update – Optionally call set_property, set_properties, set_input, or add_attachments
  3. finish() – Record the AI’s final output and close the interaction

Example: Chat Completion

Updating an Interaction

Update an interaction at any point using set_property, set_properties, set_input, or add_attachments:

Resuming an Interaction

If you no longer have the interaction object returned from begin(), resume it with resume_interaction():
resume_interaction() recovers an active in-memory interaction created by begin() in the same process. It is not a cross-process restore mechanism. If the event ID is not found in memory, a new interaction handle is created for that ID.

Single-Shot Tracking (track_ai)

For simple request-response interactions, you can use track_ai() directly:
We recommend using begin()finish() for new code to take advantage of partial-event buffering and tracing.
Use track_event() for non-AI events:

Tracking Signals (Feedback)

Signals capture quality ratings on AI events. Use track_signal() with the same event ID from begin() or track_ai():

Identifying Users


Attachments

Attachments let you include additional context — documents, images, code, or embedded content — with your events. They work with both begin() interactions and track_ai() calls.
The dashboard’s attachment viewer renders text, image, and iframe attachments. code attachments survive ingestion and are searchable, but are not currently displayed in the visual attachments tab.

Configuration

Call client.close().await? before your process exits to flush buffered events and spans. If write_key is empty and no local Workshop is configured, the client becomes a no-op (zero HTTP calls) instead of failing. Local Workshop mirroring is enabled when RAINDROP_LOCAL_DEBUGGER is set to a URL, when RAINDROP_WORKSHOP is a truthy value or URL, or when the SDK can connect to the default Workshop daemon at http://localhost:5899/v1/.

Projects

Pass .project_id(...) on the builder to scope every event from a client to a specific project. Under the hood this sets the X-Raindrop-Project-Id header on each request.
A project slug is up to 63 lowercase letters, digits, and hyphens, and it must start and end with a letter or digit (^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$). Omitting .project_id(...) (or passing "default") sends to the default Production project, which is the existing behavior, so single-project orgs need nothing here. See Projects for isolation, archival, and the full behavior table.

Tracing

Tracing captures detailed execution information from your AI pipelines — multi-model interactions, chained prompts, and tool calls. This helps you:
  • Visualize the full execution flow of your AI application
  • Debug and optimize prompt chains
  • Understand the intermediate steps that led to a response

Manual Spans

Use manual spans for workflow, task, retrieval, or any other work that is not specifically an LLM generation or tool call. Build span trees by passing a parent into SpanOptions::parent:
Spans started from an Interaction automatically inherit its user_id, convo_id, and event as traceloop.association.properties.* attributes, so the dashboard groups them under the same user, conversation, and event:
Plain client.start_span(...) calls only need name + event_id. The SDK automatically emits traceloop.association.properties.event_id so the span survives the backend’s ingestion filter. For non-event-bound spans, set operation_id (e.g. "ai.workflow") or pass properties so the span has at least one of ai.operationId, traceloop.span.kind, traceloop.workflow.name, traceloop.association.properties.*, or gen_ai.* — otherwise it will be dropped server-side.

LLM Spans

Use start_llm_span for model calls. LlmSpan emits the attributes that Raindrop’s backend and frontend understand for prompt messages, response text, model/provider, and token usage.
messages is the chat-shaped prompt representation. Use it when your provider call takes a role/content array instead of a single text prompt:
LlmMessage::system, LlmMessage::user, and LlmMessage::assistant are convenience constructors; use LlmMessage::new(role, content) for provider-specific roles. If both input and messages are set in LlmOptions, messages wins. The backend uses the last user message as the span’s input_payload, while the frontend renderer can show the full message array. If you only know the messages after creating the span, use set_messages. It replaces any previous input or prompt-message attributes:
You can also seed the LLM span from LlmOptions:
LlmSpan exposes set_model, set_provider, set_input, set_messages, set_output, set_io, set_token_usage, set_error, end, and end_at.

Closure-style helpers

If you prefer scoped instrumentation, with_span runs a closure inside a span and automatically marks the span as failed on Err:

Tool Spans

Tool spans use the dedicated wire format (traceloop.span.kind=tool) so they surface in the dashboard’s event.toolCalls[] array.
For retroactive logging of an already-completed call:
For functional wrapping, the SDK exposes with_tool and with_tool_async free helpers that run a closure inside a tool span and JSON-serialize the result onto traceloop.entity.output:

Standalone Tracer

Use Client::tracer() for batch jobs or non-conversation work where you still want spans, LLM spans, and tool traces:

Span Attributes

The SDK provides typed helpers for OTLP-compatible attributes:

Known Limitations

  • No automatic LLM-client instrumentation. Unlike the Python and TypeScript SDKs, the Rust SDK does not auto-hook into LLM frameworks. Create spans manually via start_span, start_llm_span, start_tool_span, with_span, with_tool, or track_tool.
  • No PII redaction. The Python SDK exposes set_redact_pii and the TypeScript SDK has redactPii. The Rust SDK does not yet implement client-side redaction. Redact at the call site or upstream of track_ai / track_event if needed.
  • Oversized payload guard. Payloads larger than 1 MiB after JSON serialization are dropped client-side (matching the JS / Python SDKs) to avoid 413s on the gateway. The drop is logged via tracing::warn! so production callers can detect it.

That’s it! You’re ready to explore your events in the Raindrop dashboard. Ping us on Slack or email us if you get stuck!