Skip to main content

Installation

Quick Start

What Gets Traced

The CrewAI integration automatically captures:
  • Crew kickoff invocations — input variables, crew name, process type (sequential/hierarchical)
  • Agent metadata — agent roles and count
  • Task metadata — task descriptions and count
  • Task outputs — per-task name, agent, and summary (truncated)
  • Token usageai.usage.prompt_tokens, ai.usage.completion_tokens, ai.usage.cached_tokens, ai.usage.total_tokens
  • Model name — extracted from the first agent’s llm.model; per-LLM model also appears on the corresponding trace span
  • Crew outputraw text output of the crew execution
  • Errors — captured as error.type / error.message properties on the event; the original exception is always re-raised
  • Async supportkickoff(), kickoff_async(), kickoff_for_each(), kickoff_for_each_async() are all instrumented
  • Nested OTel trace spans — crew workflow → agent → task → LLM, via the opentelemetry-instrumentation-crewai instrumentor (see Tracing; per-tool spans are not produced — see Known Limitations)

Configuration

Auto-instrumentation shortcut

Manual wrapping (no monkey-patch)

Debug Mode

Enable verbose logging when troubleshooting:
This sets the raindrop_crewai logger to DEBUG, surfacing telemetry-side failures that are otherwise swallowed (so the user’s pipeline never crashes due to instrumentation).

Projects

Route events to a specific project by passing its slug as project_id:
project_id sets the X-Raindrop-Project-Id header on every event. Omit it (or pass "default") to use your org’s default Production project, which is the existing behavior. The same option is accepted by the setup_crewai(...) and create_raindrop_crewai(...) factories. Invalid slugs are ignored with a warning and no header is sent.

Multiple projects in one process

Available in raindrop-ai>=0.0.56. When one service runs several crews that should report to different projects, create one RaindropCrewAI wrapper per project. Each wrapper owns its own raindrop.Raindrop client, so the two route independently — there is no shared module-level state:
Each wrapper owns its configuration and delivery pipeline, so crews handled by different wrappers route independently. To share a single client across wrappers (or with the module-level API), construct a raindrop.Raindrop yourself and pass it via client=:
Use wrap() — not setup() — for multiple projects. setup_crewai() / RaindropCrewAI.setup() patches the Crew class process-globally, so only the first setup()’s project can own class-wide auto-instrumentation; a second setup() with a different project keeps routing to the first and emits a warning. wrap(crew) instruments a specific crew with that wrapper’s own client, taking precedence over any class-level setup() patch for that crew — so per-crew routing stays correct even if setup() ran earlier in the process.

Multi-Agent Crews

CrewAI is designed for multi-agent collaboration. Agent roles, task descriptions, and the overall crew structure are all captured as event properties:

Tool Calls

CrewAI agents can use tools; the integration captures them indirectly:
  • The tool’s output flows through the agent’s response text and lands on the event’s aiData.output.
  • The agent and task spans inside the workflow trace include the time spent in tool calls.
CrewAI’s OTel instrumentor does not emit per-tool spans, so event.toolCalls on the dashboard will be empty (see Known Limitations).

Batch Processing

Use kickoff_for_each() to process multiple inputs in one call. The integration tracks the entire batch as a single event with aggregated token counts:

Async Usage

Tracing

When tracing_enabled=True (the default), the integration activates the opentelemetry-instrumentation-crewai instrumentor via traceloop-sdk, producing nested OTel spans for every crew execution:
  • Crew workflow — root span covering the entire kickoff() call (crewai.workflow)
  • Agent execution — child span per agent ({role}.agent)
  • Task execution — child span per task ({name}.task)
  • LLM calls — leaf spans for each underlying LLM call, with model name and token usage
Spans are exported to the Raindrop /v1/traces endpoint and link back to the flat event via the trace_id property the SDK sets in raindrop.begin(). They appear in the dashboard’s Traces tab after async ingestion (typically 30–120s). To ship flat events only without OTel spans:

Identify Users

Associate events with a user identity after initialization:

Track Signals

Attach feedback, edits, or other custom signals to a previously-shipped event by its event_id. The Python SDK does not currently expose a lastEventId accessor like the TypeScript client does, so to attach a signal you need either (a) the event_id returned to your application out-of-band (e.g. logged by debug=True), or (b) the public ID surfaced on the dashboard’s event detail page.

Flushing and Shutdown

Always call shutdown() (which flushes pending data) before your process exits to ensure all telemetry is shipped:

Known Limitations

  • No per-tool spans / empty event.toolCalls — the underlying opentelemetry-instrumentation-crewai instrumentor only wraps Crew.kickoff (workflow), Agent.execute_task (.agent), Task.execute_sync (.task), and LLM.call (LLM generation). It does NOT produce a span per tool invocation, so event.toolCalls on the dashboard will be empty for CrewAI runs. Tool usage surfaces only in the agent’s final output text and indirectly in the agent/task span durations.
  • Streaming — CrewAI’s CrewStreamingOutput is returned to the caller as-is; the flat Raindrop event is shipped after the stream completes.
  • finish_reason is per-LLM, not per-crewCrewOutput does not expose a finish_reason. Per-LLM finish reasons appear on the LLM trace spans inside the workflow trace, not on the flat event.
  • Python SDK feature surface — the Python SDK is module-level and does not expose EventShipper / TraceShipper classes. The identify() and track_signal() methods are pass-through wrappers around the raindrop.analytics.* module functions.
  • wrapt<2 required for tracing — the OTel CrewAI instrumentor uses wrapt.wrap_function_wrapper(..., module=...) which was removed in wrapt 2.0. The package’s dev dependencies pin wrapt<2; production environments running wrapt 2.x will see no trace spans (the flat event still ships).