SDK + EventListener
For self-hosted CrewAI, or when you want full Python-SDK control over
session naming, tags, and flush timing, use the ants-platform SDK with
the bundled EventListener.
Running CrewAI Enterprise? Use the Native OTel path instead — it's zero-code and produces the same trace shape.
Setup
Install the SDK
Requires Python >=3.10.
Set environment variables
Get keys from Project Settings → API Keys in the ANTS Platform dashboard.
Register the EventListener at module level in crew.py
Initialise in crew.py, not main.py. CrewAI's deployment runner imports @CrewBase directly and never executes main.py.
Flush before exit
In main.py (or wherever you call kickoff()):
Configuration
EventListener parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
public_key | str | — | Required when deploying to CrewAI's cloud platform to avoid multi-instance auth conflicts. Use ants_platform._public_key. |
agent_name | str | "crew" | Identifier used as the trace name (e.g. "support_crew"). |
agent_display_name | str | None | Human-readable name shown in the UI. |
tags | dict | None | Key-value pairs attached to every trace, e.g. {"env": "production"}. |
AntsPlatform client options
| Parameter | Type | Default | Description |
|---|---|---|---|
secret_key / public_key / host | str | env vars | API credentials. |
timeout | int | 5 | HTTP timeout (seconds). Bump to 30 for slower local setups. |
Deploying to CrewAI's cloud platform
CrewAI's deployment runner bypasses main.py and imports your
@CrewBase class directly. Two rules:
- Initialise in
crew.pyat module level, before the class. - Pass
public_keyexplicitly toEventListener. CrewAI's enterprise telemetry creates its own internal Langfuse client. Without an explicitpublic_key, the SDK detects multiple client instances and disables tracing for safety.
Set ANTS_PLATFORM_PUBLIC_KEY, ANTS_PLATFORM_SECRET_KEY,
ANTS_PLATFORM_HOST in your CrewAI deployment's Environment Variables.
Push your changes to your Git remote — crewai deploy push builds from
the remote, not your local files.
How it works
EventListener hooks into CrewAI's event bus on instantiation and
translates events into observations:
| CrewAI event | Observation |
|---|---|
CrewKickoffStartedEvent | Root span (trace created) |
AgentExecutionStartedEvent | Agent span (nested under crew) |
LLMCallStartedEvent / Completed | Generation span with token usage and cost |
ToolUsageStartedEvent / Finished | Tool span with arguments and output |
TaskStartedEvent / Completed | Task span |
*FailedEvent / *ErrorEvent | Error attribution (level=ERROR) |
Supported process types
| Type | Support |
|---|---|
Process.sequential | Fully supported. Recommended. |
Process.hierarchical | Not yet supported. |
Next
- Hit an issue? See Troubleshooting.
- Compare with the Native OTel approach for CrewAI Enterprise.