---
title: Send Google ADK traces to Agent Analytics
description: "Export Google ADK OpenTelemetry spans to Agent Analytics. Python 2.13.0 emits GenAI spans. TypeScript 2.3.0, Go 1.6.1, Java 1.4.0, and Kotlin need the exporter steps in the guide."
product: general
lang: en
last_updated: 2026-10-28
token_estimate: 2335
---
# Send Google ADK traces to Agent Analytics

> For AI agents: a documentation index is available at [/docs/llms.txt](/docs/llms.txt). Append `.md` to any page URL for markdown, or send `Accept: text/markdown`.

The Python Google ADK emits OpenTelemetry GenAI spans. TypeScript `@google/adk` 2.3.0 and Java `com.google.adk:google-adk` 1.4.0 write the legacy `call_llm` attributes, and the guide's exporter copies them onto `gen_ai.*` before export. Go `google.golang.org/adk` v1.6.1 writes `generate_content` and `execute_tool` on spans and keeps message text on OpenTelemetry logs. Point the exporter at Amplitude. You don't need the Amplitude AI SDK in the agent process.

This page covers `google-adk` 2.13.0, `@google/adk` 2.3.0, `google.golang.org/adk` v1.6.1, and `com.google.adk:google-adk` 1.4.0 from Java and from Kotlin 2.1.21. Gemini Developer API calls can be spanned by a different instrumentor. That path is the OpenInference page. Amplitude stores the spans you export. Scrub personal data before it leaves your infrastructure. Refer to [Agent Analytics privacy modes](https://amplitude.com/docs/amplitude-ai/agent-analytics/privacy-modes).

## Set up with your AI coding agent (recommended)

Paste this prompt into your AI coding agent, such as Cursor, Claude Code, Windsurf, GitHub Copilot, or Codex.

```text
Connect this Python Google ADK agent to Amplitude Agent Analytics with native OpenTelemetry.

Fetch https://raw.githubusercontent.com/amplitude/Amplitude-AI-Node/main/docs/integrations/google-adk.md
and follow "Part 2: Coding agent procedure".
If @amplitude/ai is installed, the same file is under node_modules/@amplitude/ai/docs/integrations/.
Also follow https://raw.githubusercontent.com/amplitude/Amplitude-AI-Node/main/docs/integrations/privacy.md
and scrub content before export.
Follow links in the guide. If your source isn't listed, start at https://raw.githubusercontent.com/amplitude/Amplitude-AI-Node/main/docs/integrations/README.md
```

Review the changes, then verify with the steps in [Get started](#get-started).

## What this means for you

- **You run**: The ADK process, with its OpenTelemetry exporter pointed at Amplitude. A Collector is optional. Use one when you already collect gRPC spans or when you scrub attributes there.
- **You need**: `google-adk==2.13.0`, your Amplitude project API key, and a stable ADK session id and product-analytics user ID on every turn.
- **Protocol**: OTLP over HTTP. Amplitude accepts protobuf and JSON. Amplitude doesn't accept gRPC.
- **Privacy**: Amplitude doesn't scrub content after receipt. Mask or drop the content attributes before export.

## Export

Set these variables before the process imports ADK. In Python, encode the space in the header value as `%20`. Leave `Authorization=` as written.

```bash
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://api.amplitude.com/otlp/v1/traces
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer%20<project API key>"
OTEL_SERVICE_NAME=order-support
OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=SPAN_ONLY
ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS=true
```

EU data residency uses `https://api.eu.amplitude.com/otlp/v1/traces`.

Leave ADK's telemetry schema at the default. The legacy `call_llm` schema is not mapped. `SPAN_ONLY` puts prompts and completions on span attributes. Amplitude doesn't read span events. With `ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS=false` and `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=NO_CONTENT`, the session, user, agent, model, both token counts, and the tool name still arrive. The message text and the tool arguments don't.

## Identity

ADK writes `gen_ai.conversation.id` from the session id on the model and agent spans. The tool span doesn't get it. A span processor sets `user.id`, `gen_ai.agent.id`, and `gen_ai.conversation.id` on every span, including the tool span. Without that, Amplitude stores the tool call under the trace id. The agent `name` has to be a Python identifier. The product agent id is `gen_ai.agent.id`.

| Attribute | Value |
| --- | --- |
| `gen_ai.conversation.id` | The ADK session id. Use the same value on every turn. |
| `user.id` | The user ID product analytics already uses. Amplitude stores a missing user as `unknown`. |
| `gen_ai.agent.id` | A stable name for this agent. Amplitude doesn't read `gen_ai.agent.name`. |

## What carries over

| ADK span | Amplitude event |
| --- | --- |
| Model invocation (`generate_content`) | `[Agent] AI Response`, plus an `[Agent] User Message` for each new user message after the last assistant message |
| Tool (`execute_tool`) | `[Agent] Tool Call` |
| Agent and workflow spans | `[Agent] Span` |

A tool-loop continuation repeats the earlier user text inside `gen_ai.input.messages`. Amplitude doesn't emit that earlier user message again. Tool output is `[Agent] Tool Output`.

## TypeScript

`@google/adk` 2.3.0 names the model span `call_llm` and stores the prompt in `gcp.vertex.agent.llm_request`. Set `user.id`, `gen_ai.agent.id`, and `gen_ai.conversation.id` on every span, and copy the legacy blobs onto `gen_ai.operation.name`, `gen_ai.input.messages`, `gen_ai.output.messages`, and `gen_ai.tool.call.arguments` in the exporter. The steps are in the [Google ADK integration guide](https://github.com/amplitude/Amplitude-AI-Node/blob/main/docs/integrations/google-adk.md).

`ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS=false` keeps the session, the user, the agent, the model name, both token counts, and the tool name. The message text and the tool arguments don't arrive. The model span stays `call_llm`, so Amplitude records it as an `[Agent] Span`.

## Go

`google.golang.org/adk` v1.6.1 writes `generate_content` and `execute_tool` on spans, with the model name and both token counts. Message text is an OpenTelemetry log, and Amplitude doesn't read logs, so user-message text and reply text don't arrive. Set `user.id`, `gen_ai.agent.id`, and `gen_ai.conversation.id` on every span, and copy `gcp.vertex.agent.tool_call_args` onto `gen_ai.tool.call.arguments` in the exporter. The steps are in the [Google ADK integration guide](https://github.com/amplitude/Amplitude-AI-Node/blob/main/docs/integrations/google-adk.md).

## Java

`com.google.adk:google-adk` 1.4.0 names the model span `call_llm`. Register OpenTelemetry before ADK loads. Set `user.id`, `gen_ai.agent.id`, and `gen_ai.conversation.id` on every span, rewrite `call_llm` to `generate_content`, and copy `gcp.vertex.agent.llm_request`, `gcp.vertex.agent.llm_response`, and `gcp.vertex.agent.tool_call_args` onto the `gen_ai.*` keys. The steps are in the [Google ADK integration guide](https://github.com/amplitude/Amplitude-AI-Node/blob/main/docs/integrations/google-adk.md). With that exporter, user-message text, the tool call, and reply text arrive. `ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS=false` keeps the session, the user, the agent, the model name, both token counts, and the tool name. The message text and the tool arguments don't arrive. The exporter doesn't rewrite the empty request, so the model span stays `call_llm` and Amplitude records it as an `[Agent] Span`.

## Kotlin

Kotlin uses the same `com.google.adk:google-adk` 1.4.0 library and the same exporter. A Kotlin 2.1.21 caller produced the same spans as Java, including user-message text, the tool call, and reply text.

`ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS=false` keeps the session, the user, the agent, the model name, both token counts, and the tool name. The message text and the tool arguments don't arrive. The model span stays `call_llm`, so Amplitude records it as an `[Agent] Span`.

## Session close

`[Agent] Session End` is optional and recommended. A native ADK export doesn't send it. Amplitude closes the session after 30 minutes without a qualifying agent event by default, and 24 hours from the session start when no per-session override is set. The first close is the one that counts. Enrichment, including the Session Record and content-based signals, runs once after that close. The OpenTelemetry translator doesn't read an idle-timeout attribute from a span. Refer to [How sessions close](https://amplitude.com/docs/amplitude-ai/agent-analytics/sessions#how-sessions-close).

## Get started

Follow the [Google ADK integration guide](https://github.com/amplitude/Amplitude-AI-Node/blob/main/docs/integrations/google-adk.md). Send two turns with the same ADK session id, then confirm in Live Events:

1. Session ID is the ADK session id, not a trace ID.
2. User ID is the product-analytics user, not `unknown`.
3. Agent ID is `gen_ai.agent.id`.
4. On Python, TypeScript, Java, and Kotlin, the turn shows User Message text, the tool call, and AI Response text, with the model name and both token counts. On Go, the turn shows the tool call, the model name, and both token counts. User Message text and reply text don't arrive, because Go keeps that text on OpenTelemetry logs.
5. The second turn doesn't duplicate the first user message.

Guide last verified on October 28, 2026, against `google-adk` 2.13.0, `@google/adk` 2.3.0, `google.golang.org/adk` v1.6.1, and `com.google.adk:google-adk` 1.4.0 from Java and from Kotlin 2.1.21. Google ADK is a trademark of its owner. Amplitude isn't affiliated with or endorsed by that owner.

