Skip to main content

Install

Supported: crewai 1.13 to 2.0. 1.13 is the release that added started_event_id and normalized token usage, both of which the adapter relies on to pair events and report tokens.

Instrument

instrument() registers a listener on CrewAI’s module-level event bus and subscribes one handler per event class. Nothing about your crew, agents, tasks, or tools changes.

What gets recorded

A task emits nothing on purpose. A CrewAI task is a subset of the agent execution that runs it, so emitting both would double every row and render them as siblings. The task id and name ride along on the agent’s own events instead. Memory and knowledge operations are recorded as tools, named for the surface they hit, so they appear next to your real tools where you can compare their latency. On a hierarchical crew, the nesting is what makes the trace readable:
CrewAI parents a delegated execution on the delegate_work_to_coworker tool event, not on the manager directly, so the adapter follows that link. Without it every agent comes out a sibling of every other and the delegation structure is lost.

Example

The handoff is visible in the trace: the analyst span closes, the writer span opens, and both sit inside one crew span.

Name your spans

agent_id comes from Agent(role=...), which is what makes it a readable dashboard facet.
agent_id is a low-cardinality column. A role containing a run id or timestamp degrades it for every query anyone runs. If a role looks like an id, the adapter refuses it and puts the real value in a payload field instead.

Control the session

Resolved in this order, first match winning:
  1. instrument("crewai", session_id=...)
  2. The enclosing failproofai_sdk.session() scope
  3. A generated uuid4().hex, once per crew or flow
Wrap the kickoff to control it per run:

Options

session_id is the only option this adapter reads. Prompts and completions are always recorded, truncated to the payload budget.

Human in the loop

CrewAI has two human-in-the-loop surfaces, and both are recorded as the same four events. @human_feedback on a flow method goes through CrewAI’s event bus: the runtime emits an event before it blocks on a person and another after the answer. Task(human_input=True) does not. It calls input() inside CrewAI’s own input provider and emits no event of any kind, so the adapter wraps that provider directly — without it the entire human wait was invisible and billed as active agent time. Either way you get:
agent_pause to agent_resume is the only pair that feeds paused time. Without it, a ten-minute human wait is billed as ten minutes of active agent time.
CrewAI sets no correlation id on either human-feedback event, so the adapter pairs them on the flow and method name, falling back to the most recently opened pause. That is sound because a console prompt blocks. If you build a concurrent feedback provider, set request_id on both events.
Because the Task(human_input=True) path is a wrapper around CrewAI’s input provider rather than an event subscription, it is restored on uninstrument() and re-raises whatever input() raises, KeyboardInterrupt included, unchanged.

Common problems

A role contains a UUID, timestamp, or per-run suffix. Use a stable human role and put the run-specific id in the task description instead.
The event bus is asynchronous, and kickoff() returns before the last handlers run. Drain it first:
This is a property of CrewAI, not of the SDK.
agent_end force-closes open pauses but not tools or models, so a run that dies inside a tool call leaves that span open. Normal teardown closes whatever is still open and marks it incomplete. Only a SIGKILL leaves it hanging, because nothing can run.
Check in this order: instrument() ran before kickoff(); there is a with failproofai_sdk.session(): around it; crewai is 1.13 or newer; FAILPROOFAI_SDK_STRICT=1 set, so a degraded hook raises instead of being swallowed.

Next

How it works

Pairs, ids, session lifecycle, and delivery.

Read a trace

Follow causality through the session you just captured.

Other frameworks

LangGraph, LlamaIndex, Pydantic AI, and custom agents.