Tracking Agent docs

How to connect your analytics tool to the Tracking Agent

The Tracking Agent reads your analytics tool into a data snapshot: which events arrived, how often, and with which properties and values. Mixpanel, PostHog and Amplitude each have a recipe, BigQuery, Snowflake and ClickHouse have a SQL route, and other tools work through your AI's MCP connection on a laptop run. The snapshot stays on your runner and goes only to your model provider.

By Ansh AgrawalUpdated

Which ways can the Tracking Agent read analytics data?

RouteHow it worksAvailable
1. A recipedatalyze snapshot mixpanel|posthog|amplitude calls the tool's APIs with a read-only credentialMixpanel, PostHog and Amplitude
2. Your AI's MCP connectionYour AI writes the queries through the tool's MCP server, following the snapshot methodLaptop runs, any tool with an MCP server
3. The tool's API, without a recipeThe agent writes the API calls itselfNot yet
4. SQL on your warehousedatalyze snapshot warehouse queries BigQuery, Snowflake or ClickHouse with read-only credentials, which covers any pipeline that lands events thereBigQuery, Snowflake and ClickHouse

They're listed in order of preference. Whichever route builds it, the snapshot has the same shape, so the audit and the verifier work the same for every tool.

How do I connect Mixpanel to the Tracking Agent?

  1. In Mixpanel, create a service account with access to the project. Read access is enough.
  2. Give setup its username and secret, or save them yourself as the repo secrets MIXPANEL_SA_USERNAME and MIXPANEL_SA_SECRET.
  3. Give setup the project ID and data region (us, eu or in). They go into .datalyze/config.yaml under analytics.
  4. To test it, build a snapshot by hand with the command below.
bash
MIXPANEL_SA_USERNAME=... MIXPANEL_SA_SECRET=... \
  datalyze snapshot mixpanel --project-id 1234567 --region us --days 30 --out snapshot.json

The recipe streams a capped sample of raw events, retries rate-limited requests, and with --cache <dir> reuses answers for six hours. Mixpanel's APIs don't expose how stale profile values are or how many profiles are duplicates, so those two checks are skipped for Mixpanel.

How do I connect PostHog to the Tracking Agent?

  1. In PostHog, create a personal API key with the Query Read scope.
  2. Save it as the secret POSTHOG_API_KEY (or POSTHOG_PERSONAL_API_KEY).
  3. Give the project id with --project-id, or as analytics.project_id in .datalyze/config.yaml.
  4. If you're not on PostHog's US cloud, set the host with --host, analytics.host or POSTHOG_HOST. The default is https://us.posthog.com; the EU cloud and self-hosted PostHog work too.
bash
POSTHOG_API_KEY=... \
  datalyze snapshot posthog --project-id 12345 --host https://eu.posthog.com --out snapshot.json

The recipe runs HogQL queries through PostHog's Query API: daily counts; each event's volume by app version over the whole window; a raw sample of the last 2 days (20,000 events by default) for property fill rates, types and top values; platforms; double-firing and the identified share; person properties for users seen in the window; and duplicate profiles, meaning persons sharing an email, counted inside PostHog so no email comes back. It reads your custom events plus $pageview, $screen and $identify, and leaves out other $ events. It doesn't give per-property staleness, so that check is skipped for PostHog.

How do I connect Amplitude to the Tracking Agent?

  1. In Amplitude, copy the project's API key and secret key.
  2. Save them as the secrets AMPLITUDE_API_KEY and AMPLITUDE_SECRET_KEY.
  3. Set the region, us or eu, with --region or analytics.region.
bash
AMPLITUDE_API_KEY=... AMPLITUDE_SECRET_KEY=... \
  datalyze snapshot amplitude --region us --out snapshot.json

The event list and daily counts come from Amplitude's Dashboard REST API, paced to Amplitude's cost limit, so a big event list can take a few minutes. Event and user properties come from a raw sample from the Export API: whole hours ending two hours back, 24 hours by default, up to 100,000 events. The Amplitude recipe doesn't give staleness or duplicate profiles, and hidden events get no counts.

How do I connect a data warehouse to the Tracking Agent?

  1. Create a read-only login for the dataset or schema your events land in.
  2. Save it as JSON in the secret WAREHOUSE_CREDENTIALS, in the shape for your warehouse (below).
  3. In .datalyze/config.yaml, set analytics.tool: warehouse, analytics.warehouse and analytics.source: how your events are laid out, and where.
  4. To test it, build a snapshot by hand: datalyze snapshot warehouse --out snapshot.json.
WarehouseWAREHOUSE_CREDENTIALSConnects through
BigQueryA service account key file, or { "access_token": "..." }; analytics.project_id is the project jobs run inThe jobs.query API, with a cap of 20 GB billed a query
Snowflake{ "account", "user", "private_key" } for key-pair auth, or "token" for a programmatic access token; optional warehouse, role, databaseThe SQL API
ClickHouse{ "url", "user", "password" }The HTTP interface, read-only
analytics.source.layoutWhere the events are
segment, rudderstackThe loaders' schema: tracks, one table per event with its properties as columns, users and identifies
ga4The GA4 BigQuery export (events_*, intraday tables included). BigQuery only
events_tableOne table with a row per event and properties in a JSON column; name the columns under columns
mixpanel_export, amplitude_export, posthog_exportStarting points for the tools' own exports; check them against your export and override with columns
yaml
# .datalyze/config.yaml
analytics:
  tool: warehouse
  warehouse: bigquery          # bigquery | snowflake | clickhouse
  project_id: acme-analytics   # BigQuery: the project jobs run in
  source:
    layout: events_table
    schema: analytics          # dataset or schema
    table: events
    columns: { event: event_name, timestamp: ts, user_id: user_id, anonymous_id: device_id, properties: properties, app_version: app_version, platform: platform }
    users: { table: people, id: distinct_id, traits: properties }   # optional

The Segment, RudderStack and GA4 layouts fill every part of the snapshot: staleness comes from identifies or GA4's set times, and duplicate profiles (Segment and RudderStack) are counted inside the warehouse. An events table, and the export presets, give counts, app versions, properties, the identified share and user properties from users, but not staleness or duplicate profiles. Credentials put in a ClickHouse URL are moved into headers. Every query is in the snapshot with its SQL, a table name read from your data is used only if it's a plain identifier, and no value of a property that looks like personal data is kept. Without credentials in the runner, your AI can write the same queries through the warehouse's MCP connection on a laptop run.

What's in a Tracking Agent data snapshot?

  • Every event that arrived in the window (30 days by default), with its volume and daily counts.
  • For each event's properties: fill rate, the types seen, and the top values.
  • For user properties on active profiles: fill rate, types and top values.
  • Volume by platform (web, iOS, Android, Node), so an event arriving from another platform isn't called dead.
  • App versions, double-firing rate, and the names of properties whose values looked like an email or phone number.
  • The share of events from identified users.

Every figure carries the query that produced it, written out exactly, and the verifier re-runs a sample. A snapshot whose figures point at queries it doesn't list is rejected.

What does a data snapshot never contain?

Values of properties whose names look like personal data. Every route, the recipes and the warehouse alike, applies one rule. For a name with a personal or secret word in it (email, phone, mobile_number, whatsapp, upi_id, pan, aadhaar, ifsc, ip, token, password, address, location, a person's name as in full_name or customer_name but not screen_name, a code a person can use or share as in otp_code or referral_code but not country_code, free text as in search_query, order_note or user_bio), names matching pii_patterns in _conventions.yaml, and properties marked pii: true, only the fill rate and type are recorded. A name that only describes such a value keeps its values: one starting is_ or has_, or ending in a word like count, type, country, verified or bucket (token_count, phone_verified, ip_country). A description is free text unless it's catalogue copy (product_description). A tool's own properties ($ and mp_ names) keep no values either, and a URL that is kept loses its query and fragment: https://x.com/login?code=… is recorded as https://x.com/login, with or without the https://, and ;jsessionid= path parameters go too; a tel: or mailto: link keeps only its scheme. A value shaped like an email, a phone number, a UPI id (name@okhdfc) or a tel: link is never kept under any property name; the property is listed under pii_values instead. Vendor properties are left out too: names starting $ or mp_, plus time, distinct_id and token.

A snapshot never guesses either. If a figure isn't available, the field is left out and that check is skipped, because a made-up number would corrupt the audit. properties_complete is set only when a raw sample lists every property.

What if we don't connect an analytics tool?

Everything still runs. The PR check judges from the code, and datalyze scan compares the plan with the code. You lose the checks that need data: telling a dead event from one arriving from another platform, matching new values to the format of existing data, volume drops, and the audit itself.

Questions about connecting analytics

Does the Tracking Agent need write access to our analytics tool?

No. It only reads. A Mixpanel service account with read access to the project is enough, and for PostHog a personal API key with the Query Read scope.

Does the Tracking Agent work with PostHog and Amplitude?

Yes, for reading data: datalyze snapshot posthog and datalyze snapshot amplitude build the snapshot, and the install audit and the post-release watch use the recipe for analytics.tool. The typed tracker's adapter is still Mixpanel's only.

Can we use our data warehouse instead?

Yes. datalyze snapshot warehouse reads BigQuery, Snowflake or ClickHouse, laid out by Segment, RudderStack, the GA4 export or your own events table. For help modelling the events once they're there, see our BigQuery consulting.

What if our Mixpanel tracking is a mess?

Connect it anyway: the first audit shows how bad it is. If it shows a lot of broken or unplanned events, our Mixpanel implementation service rebuilds the tracking with you, and the playbook chapter on event verification covers checking it by hand.