Connect your agent
Google ADK, in every place you are likely to run it.
What you are configuring
Two standard OpenTelemetry environment variables. They are not TraptureIQ settings. They are the OTLP exporter's own configuration, which ADK already honours:
| Variable | Value |
|---|---|
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT | https://api.traptureiq.com/v1/traces |
OTEL_EXPORTER_OTLP_HEADERS | X-API-Key=tiq_your_key_here |
Plus , which google-adk does not bundle.
Running locally
You do not have to deploy anything to see what an agent costs. An agent on your laptop reports exactly like one on Cloud Run: same variables, same payloads, same dashboards. Cost per model, thinking-token share, per-sub-agent spend and the full latency waterfall are all available while you are still iterating, which is the point at which a prompt change or a model swap is still cheap to make.
Install the OTLP exporter
pip install opentelemetry-exporter-otlp-proto-http
Set the environment variables with export
In the terminal you will run the agent from. Replace tiq_your_key_here with your API key and my-agent with your agent's name.
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://api.traptureiq.com/v1/traces" export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT="https://api.traptureiq.com/v1/logs" export OTEL_EXPORTER_OTLP_HEADERS="X-API-Key=tiq_your_key_here" export OTEL_SERVICE_NAME="my-agent" export OTEL_RESOURCE_ATTRIBUTES="deployment.environment=local"
Run adk web in the same terminal
adk web .
Ask the agent something and allow 10–30 seconds. Spans leave on the OpenTelemetry batch processor's schedule, not the moment the agent replies. shortens that while you experiment; leave it out in production.
adk web reads these variables once, at startup, from the terminal. Your agent's .env is only loaded later, on the agent's first request, which is too late: nothing is exported and the dashboard stays empty. Exports last for that terminal session, so paste them again in a new terminal. (A .env is the right place for the deploy targets below.)
Tested on every ADK 2.x release and on 1.39.1 (). Older 1.x releases send cost data but not the agent structure, so agent attribution and topology stay empty. adk run never initialises OpenTelemetry in any version, so your agent answers normally and nothing is exported. Use adk web or adk api_server.
Because the runs are tagged deployment.environment=local, they stay separable from production everywhere. The Cost dashboard can show development spend on its own, or exclude it. Without that variable both sum into a single number, which is how an agent budget stops being explainable.
Deploying with adk deploy
ADK has three deploy targets, and each takes environment variables differently. This is where connecting usually goes wrong: the deploy succeeds, the agent runs, and nothing arrives because the variables never reached the runtime.
| Target | Supported | How to pass env vars |
|---|---|---|
cloud_run | Verified | --env KEY=VALUE on ADK ≥ 2.9; gcloud --set-env-vars after a -- separator on 2.8 and older. Not a .env file |
gke | Verified | No flag and no passthrough. Use kubectl set env on the Deployment afterwards |
agent_engine | Verified | A .env in the agent folder (requires ADK ≥ 2.11.0) |
Agent Engine
adk --version, upgrade with pip install -U google-adk, then deploy. adk deploy agent_engine builds a container that runs adk api_server, the same entrypoint Cloud Run uses, so the standard OTLP variables are honoured. On 2.1.x and older the deploy produced a different kind of app that ignored them entirely; if you cannot upgrade from one of those, Troubleshooting has a workaround. Versions 2.2 to 2.10 read the variables the same way 2.11 does, but they are not verified or supported on Agent Engine: upgrade before troubleshooting anything else.There is nothing Agent Engine specific to write. Put a .env and a requirements.txt next to agent.py and deploy. Both agent.py and __init__.py stay exactly as they are.
# my_agent/.env: picked up automatically at deploy time GOOGLE_GENAI_USE_VERTEXAI=1 OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://api.traptureiq.com/v1/traces OTEL_EXPORTER_OTLP_HEADERS=X-API-Key=tiq_your_key_here OTEL_SERVICE_NAME=my-agent
# my_agent/requirements.txt # ADK itself is installed by the deploy; this is the exporter it does not bundle. opentelemetry-exporter-otlp-proto-http
adk deploy agent_engine \ --project=$PROJECT_ID \ --region=$LOCATION_ID \ --display_name="my-agent" \ my_agent
my_agent/ ├── __init__.py # unchanged: "from . import agent" ├── agent.py # unchanged ├── .env # the two OTLP variables └── requirements.txt # opentelemetry-exporter-otlp-proto-http
--adk_app, --adk_app_object, --env_file, --requirements_file and --staging_bucket are all deprecated as of ADK 2.6 and no longer needed. The .env and requirements.txt inside the agent folder are read automatically.Cloud Run
How the variables get to Cloud Run depends on your ADK version (adk --version). From 2.9.0, adk deploy cloud_run has its own --env flag. On 2.8 and older there is none, so they go to gcloud run deploy after a -- separator.
adk deploy cloud_run \ --project=$PROJECT_ID \ --region=$LOCATION_ID \ --service_name="my-first-agent" \ --env "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://api.traptureiq.com/v1/traces" \ --env "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://api.traptureiq.com/v1/logs" \ --env "OTEL_EXPORTER_OTLP_HEADERS=X-API-Key=tiq_your_key_here" \ --env "OTEL_SERVICE_NAME=my-first-agent" \ --env "OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production" \ my_first_agent
adk deploy cloud_run \ --project=$PROJECT_ID \ --region=$LOCATION_ID \ --service_name="my-first-agent" \ my_first_agent \ -- \ --set-env-vars="^##^OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://api.traptureiq.com/v1/traces##OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://api.traptureiq.com/v1/logs##OTEL_EXPORTER_OTLP_HEADERS=X-API-Key=tiq_your_key_here##OTEL_SERVICE_NAME=my-first-agent" # ^##^ tells gcloud to split pairs on ## instead of commas, so a value # that contains a comma (a second header, say) arrives intact.
adk deploy cloud_run copies the agent folder into the image but does not turn its .env into environment variables (2.9+ reads it only for the project and region). The agent then loads it at runtime, after telemetry is already set up, so the deploy succeeds, the agent answers, and nothing arrives. Use the commands above.
The deploy sets GOOGLE_CLOUD_LOCATION to your --region. Models served only on the global endpoint (for example gemini-3.5-flash) then fail every call with a 404. Add --env GOOGLE_CLOUD_LOCATION=global (2.9+), or ##GOOGLE_CLOUD_LOCATION=global inside --set-env-vars (2.8 and older).
- On 2.9+, the old
-- --set-env-varsform fails: ADK already passes--update-env-vars, and gcloud accepts only one of the two. --envvalues are joined with commas, with no escape. A value containing a comma (two OTLP headers, several resource attributes) is split apart. Keep such values to one entry, or set them afterwards withgcloud run services update --update-env-vars.- With
--artifact_service_uri=gs://…, addgoogle-cloud-storageto the agent'srequirements.txt, or the container exits at startup.
GKE
adk deploy gke has neither an env flag nor a gcloud passthrough. The Deployment it generates has no env: block at all, so the variables go on afterwards with kubectl set env, which rolls the pods automatically:
adk deploy gke \ --project=$PROJECT_ID \ --region=$LOCATION_ID \ --cluster_name=$CLUSTER_NAME \ --service_name=my-first-agent \ --app_name=my_first_agent \ --with_ui \ my_first_agent kubectl set env deployment/my-first-agent \ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://api.traptureiq.com/v1/traces" \ OTEL_EXPORTER_OTLP_HEADERS="X-API-Key=tiq_your_key_here" \ OTEL_SERVICE_NAME=my-first-agent \ OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production
# The generated Service is ClusterIP on port 80 -> targetPort 8000. # ADK's own closing message suggests "8000:8000", which does not match # the Service it just created. Forward to port 80: kubectl port-forward svc/my-first-agent 8080:80 # Then drive it as usual, every call is traced. curl -X POST http://127.0.0.1:8080/apps/my_first_agent/users/u/sessions/s \ -H 'Content-Type: application/json' -d '{}'
Unlike gcloud run deploy --set-env-vars, kubectl set env splits arguments on whitespace, not commas. A header value containing a comma needs no special form. Quote it and it arrives intact.
The single --region value is used twice: it becomes GOOGLE_CLOUD_LOCATION inside the image and it is passed to gcloud container clusters get-credentials --region. Against a zonal cluster one of the two is always wrong. Pass a zone and the image gets an invalid Vertex AI location.
Agent Engine: a .env in the agent folder
For agent_engine only, adk deploy reads the .env next to agent.py and passes its values to the deployed runtime (ADK ≥ 2.11.0). Cloud Run does not; see above.
.env with your API key travels with the deployment. Fine for a personal test; for anything shared, keep the key in Secret Manager.Docker and other runtimes
docker run \ -e OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://api.traptureiq.com/v1/traces" \ -e OTEL_EXPORTER_OTLP_HEADERS="X-API-Key=tiq_your_key_here" \ my-agent
services: agent: build: . environment: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: "https://api.traptureiq.com/v1/traces" OTEL_EXPORTER_OTLP_HEADERS: "X-API-Key=tiq_your_key_here"
Capturing prompts and responses
Token counts and cost arrive without this. The prompt and response bodies, what fills the request/response panes in Observability, are a separate opt-in:
ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS=true
true. But adk deploy writes false into the deployed environment whenever the variable is absent, so an agent that showed prompt bodies on your machine will stop showing them once deployed, with nothing in the logs to say why. Set it explicitly in .env if you want it.Think about it before switching it on anywhere real: it means user prompts and model replies are stored in TraptureIQ, which may include personal data. Cost and traces work perfectly well without it.
Naming your agents
The agent name in the console comes from the span. There is nothing to register. Send a new name and it appears as a new agent. That also means a typo creates a second agent, so keep names stable once you have picked them. If OTEL_SERVICE_NAME is not set, the root agent's name is used instead.
Grouping calls into sessions
ADK sets a session id per conversation, which is what powers User journeys and Observability → Sessions. If you want spend attributed to an end user as well, set a user id on the ADK session. From ADK 2.1 that id travels only on log records, and only with log content capture on; see No per-user breakdown.
Send to a shared team tenant
By default an API key writes into its owner's tenant. To have an agent write into a shared team workspace instead, add the tenant id header:
OTEL_EXPORTER_OTLP_HEADERS="X-API-Key=tiq_your_key_here,X-Tenant-Id=<tenant-id>"
The tenant id is on Tenant picker → Manage tenants. Only tenants the key's owner belongs to are accepted.