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 usage — ai.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 output — raw 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 support — kickoff(), 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.

Tool catalog capture (ai.prompt.tools)

raindrop-crewai ≥ 0.0.10 records the crew’s tool catalog on every model span of an instrumented kickoff (kickoff, kickoff_async, kickoff_for_each, kickoff_for_each_async, through setup() or wrap()): the union of every agent’s and every task’s tools, each converted with CrewAI’s own convert_tools_to_openai_schema (the args_schema as a strict-mode JSON Schema), identical definitions recorded once. Model calls happen per agent with that agent’s tools while the wrapper hooks the crew, so this is a catalog that may overstate what one call received; the OTel crewai instrumentor emits no tool definitions of its own. An inferred catalog is marked with ai.prompt.tools.source = "crewai.agent.tools"; an explicit override carries no source. Pass tools= on RaindropCrewAI(...), setup_crewai(...) or create_raindrop_crewai(...) as the default for every instrumented kickoff, or wrap(crew, tools=[...]) / wrap_crew(crew, tools=[...]) for one crew; the override replaces the inferred catalog and tools=[] records an empty one. Follows TRACELOOP_TRACE_CONTENT. The catalog needs raindrop-ai ≥ 0.0.70, the source marker ≥ 0.0.71. The attribute lands on the LLM.call spans the CrewAI instrumentor produces; on crewai ≥ 1.x, LLM(model=...) returns native provider classes whose completions bypass LLM.call, so those providers get no model span and no ai.prompt.tools until the instrumentor covers them. See Tool catalog capture for the attribute format, the absent / [] semantics and the override shapes accepted.

Flushing and Shutdown

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

Application Git metadata (Python)

RaindropCrewAI(...), create_raindrop_crewai(...), and setup_crewai(...) accept the keyword-only app_git option. It defaults to True: explicit Raindrop Git environment or deployment context is applied immediately, and the base SDK may perform one bounded background local-Git lookup from the process working directory. Event capture, flush, and shutdown never wait for that lookup. Pass False to disable enrichment, or pass an AppGitOptions mapping with commit_sha, commit_dirty, branch, source_directory, detect_branch, and/or auto_detect. Automatic branch discovery remains opt-in through detect_branch=True (or RAINDROP_GIT_DETECT_BRANCH=true). For an ordinary in-process application, the process working directory is treated as the application-under-test checkout. A remote, coding, workflow, or observer process must not rely on its own checkout: pass app_git=False, provide explicit revision values, or set source_directory to the actual application checkout. Canonical per-operation properties remain authoritative. When supplying client=, configure app_git while constructing that Raindrop client; the supplied client is authoritative and the wrapper’s app_git argument does not reconfigure it. Release order is deliberate: first publish the base SDK feature, then publish the wrapper feature release with its minimum dependency coordinated to that base release. The existing raindrop-ai lower bound remains compatible, but application Git metadata is unavailable on an older core and must not be claimed complete until the base is upgraded. Until coordination assigns a released version, the wrapper checks for an explicit base app_git parameter and omits the option when unsupported. Explicit non-default configuration is debug-logged and omitted. Unsupported app_git is determined by signature inspection before construction, not by retrying initialization after a TypeError; Git configuration adds no initialization attempts and does not change any existing framework-specific initialization fallback.

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-crew — CrewOutput 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).