Skip to main content
Beta. The Java SDK is at 0.0.3. The wire contract against the Raindrop ingestion API is stable and verified end-to-end against the live backend on every push, but the public API may still change in minor ways before 0.1.0. Pin an exact version in your build file.

Installation

The SDK requires Java 17+. The artifact coordinates are ai.raindrop:raindrop-java. Gradle:
Maven:
Smallest possible program:
Raindrop implements AutoCloseable, so try-with-resources flushes and stops the client for short-lived programs:

Single-Shot Tracking (trackAi)

For simple request-response interactions, call trackAi() directly. At least one of input or output is required, along with userId and event. It returns the event id (or null if the event was invalid or the client is disabled):
For new code we recommend the begin()finish() interaction API below: it buffers a pending event immediately and links any spans you create into the same trace.
Use track() for non-AI product events:

Interactions

begin() opens an interaction (a trace) and immediately ships a pending event so it appears in the Events tab right away. Update it as work progresses, then finish() records the final output:
setInput, setOutput, setModel, setProperty, and setError return the interaction, so they chain. Call finish() exactly once; it finalizes the event and closes the root span.

Tracing

Tracing captures detailed execution information — multi-step pipelines, tool calls, and subagents — so you can visualize the full execution flow, debug prompt chains, and understand the intermediate steps behind a response.

Tool and task spans

Spans created from an interaction inherit its userId, convoId, and event, so the dashboard groups them under the same user, conversation, and event. Use startTool for tool calls and startTask for other units of work:
setInput, setOutput, setError (which accepts a Throwable or a String), and setAttribute all return the span for chaining. Always end() a span — a try/finally guarantees it even when the work throws.

Nested spans & subagents

Spans are nestable: a span started from another span is parented to it, so subagent and tool trajectories form the correct tree in the trace view. Use startSpan(SpanOptions) for a generic span (for example a subagent with a custom operationId), and startTool / startTask for the common cases:
You can also start a free-standing tool span that is not tied to an interaction with raindrop.startToolSpan("name").

Signals

Signals capture quality ratings on AI events. Use trackSignal() with the same event id returned by begin() or trackAi():

Self-diagnostics

selfDiagnose() reports a signal that surfaces in the dashboard’s Self Diagnostics tab — useful when your agent detects that it is stuck or degraded:

Identifying Users


Attachments

Attachments include extra context — documents, images, code, or embedded content — with an event. Add them to a trackAi() or track() event via the builder:
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 raindrop.close() (or shutdown()) before your process exits to flush buffered events and spans under a bounded deadline. If writeKey is empty and no local Workshop is configured, the client is a no-op (zero HTTP calls) rather than an error. 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 reach the default Workshop daemon at http://localhost:5899/v1/.

Projects

Pass .projectId(...) 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])?$). An invalid slug is ignored with a warning and no header is sent, so a typo never breaks ingestion. Omitting .projectId(...) (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.

Reliability

Raindrop is designed never to slow down or crash your application. The SDK is a strict no-op when Raindrop is unreachable, slow, rate-limited, or misconfigured:
  • All network I/O runs on a background daemon thread. trackAi, track, trackSignal, identify, begin / finish, and span start/end only enqueue work and return immediately on the caller’s thread. flush() is non-blocking too.
  • Oversized payloads cost the cap, not the payload. Text fields and structured span/property values are bounded before serialization, so a multi-MB input is O(cap) on the caller.
  • Bounded waits everywhere. Connect/read timeouts, a capped retry count with clamped backoff, and a bounded flush-on-shutdown deadline — close() returns promptly even against a black-hole endpoint.
  • Exceptions never escape. Serialization or transport failures are swallowed and rate-limited-logged; your code path is unaffected.
The SDK is manual-only — it does not monkey-patch or auto-instrument your LLM client libraries — so it cannot interfere with your application’s runtime.

Local development with Workshop

Workshop is the local-first trace debugger. Point the SDK at it (or just run on localhost with RAINDROP_WORKSHOP=1) and events + spans stream into the UI with no write key: