The ah CLI

Everything in this dashboard, in your terminal — and in a shape agents read well: dense aligned tables, --json on every verb, and no clicking. Point Claude Code at it and ask questions about your traffic in plain English.

  1. 1

    Install

    Needs Node 20 or newer.

    npm i -g @brightmotion/agenthog
  2. 2

    Sign in

    Opens your browser, mints a read token, and stores it in ~/.config/agenthog/config.json. One time, per machine. In several organizations? Tick the ones you want and every project shows up in one place.

    ah login
    ah digest
  3. 3

    Let Claude Code use it

    Once ah login is done, Claude Code can run ah like any other command — no plugin, no MCP server. The one thing worth doing is telling it the tool exists. Paste this into your CLAUDE.md:

    ## Analytics (AgentHog)
    
    Web analytics for this project live in AgentHog. The `ah` CLI is installed and
    authenticated — read from it directly instead of guessing.
    
    - `ah digest` — start here: one-call overview with deltas vs the previous window
    - `ah traffic --since 30d` — sessions per day by classification, plus top sources
    - `ah funnel signup` — or `ah funnel <step1> <step2> ...` for an ad-hoc funnel
    - `ah sessions list --converted` — then `ah sessions show <id>` for one timeline
    - `ah events top` / `ah clicks /pricing` — what people actually do
    - `ah revenue` — net/gross/refunds, ARPU, ARPPU, AOV (`ah revenue suggest` sets it up)
    - `ah ltv` — cumulative revenue per person by acquisition cohort
    - `ah economy` — in-game currency flows per currency (`ah economy suggest` sets it up)
    - `ah track <event> --prop k=v` — record something no SDK saw: a deploy, a migration, a
      correction (needs a write token; `--at` backdates, `--file` imports history)
    
    Every verb takes `--json`. Bots are excluded by default (`--all` includes them).
    Run `ah --help` for the full verb list.

    Then just ask: “did last week’s pricing change move signups?” — it will reach for ah digest and ah funnel on its own.

  4. 4

    Unattended agents and CI

    ah login needs a browser. For anything headless, mint a token on the Tokens page and pass it by env — it takes precedence over the stored login and never prompts.

    AH_TOKEN=ah_tok_… ah digest --json

Worth knowing

  • ah whoami — which account, token, and scope you are using, and where it came from.
  • Read scope is the default. Write tokens (for goals set, changes add, track) need an org admin: ah login --write.
  • One project? No flags needed. Otherwise pass --project <name>.
  • ah logout revokes the token(s) server-side, not just locally.
  • Several organizations: ah projects lists them all with an org column, and a project key picks the right one automatically. Account-wide verbs (usage, test-ips add, projects create) take --account <org>. Joined a new org? ah login --force.
  • Self-hosted? ah login --host https://your-agenthog.example, or set AH_API_URL alongside AH_TOKEN.

Common verbs

ah --help lists everything. The ones worth knowing on day one:

ah digest --since 30d                 # the daily standup view
ah traffic --since 7d                 # sessions per day + top sources
ah campaigns --since 30d              # which ad is actually working
ah paths --to "form_submit: waitlist" # discover the real funnel
ah funnel signup --by device_type     # then see where it breaks down
ah sessions list --converted          # who converted
ah sessions show 831ac66d             # one person's full visit
ah clicks /                           # what people click, incl. dead clicks
ah flags create cta --variants control:50,b:50   # feature flags (write scope)
ah experiments start cta --metric signup         # A/B test on the flag
ah experiments results cta            # per-variant conversion + chance-to-beat
ah funnel signup --by flag:cta        # any metric splits by variant

Writing events

Everything above reads. ah track is the one verb that writes an event — for anything that happened outside an SDK: a deploy, a migration, a billing correction, hours logged, or a one-shot import of history from another tool. It is a thin wrapper over the same token-authed server ingest a webhook relay uses, with the conventions applied for you: the event lands on a server session (out of ah traffic, visible in ah events, ah sql, funnels, revenue and economy), --person stitches it to the same person the app’s identify() reports, and bare numbers in --prop are sent as numbers. Needs a write token.

ah track deploy_completed --prop service=app --prop version=1.9.2
ah track time_logged --at 2026-08-25 --person eric --prop project=move --prop hours=5
ah track --file hours.csv --event time_logged --ts-col Date --person-col Person \
         --prop-cols Project=project,Work=work,Hours=hours --dry-run
ah track --file hours.csv ...                # the real run (--skip-bad drops the rows the dry run listed)
ah track --file export.ndjson                # NDJSON rows carry their own fields

Two things the verb tells you every time because they are easy to get wrong. --at 2026-08-25 is UTC midnight, while --at "2026-08-25 21:30" (no offset) is your local wall clock — and reports bucket days in UTC, so a late evening in a negative-offset zone lands on the next day. The resolved instant is echoed on every write; pass an ISO time with an offset when the exact moment matters. And there is no idempotency key: running an import twice writes every row twice, so --dry-run first, and carry a stable id in props if you may need to dedupe later. Bad rows are reported by line number and the import refuses to run until they are fixed or --skip-bad is passed — an import is never silently partial.

Revenue

Revenue is config, not a second pipeline. You declare which events you are already sending carry money and where in their props the amount lives — and the mapping applies retroactively over all history, immediately. ah revenue suggest reads the props already in your data and prints the exact commands.

ah revenue suggest                    # propose mappings (--apply writes them)
ah revenue map checkout_completed --amount cents --currency USD
ah revenue config                     # what's mapped + a live sanity count per event
ah revenue                            # net, gross, refunds, orders, payers, ARPU, ARPPU, AOV
ah revenue --series week              # revenue over time
ah revenue --by utm_source            # which channel earns
ah revenue --by props.plan            # which plan earns
ah revenue --by flag:cta              # revenue per A/B variant
ah ltv --by utm_source                # which channel buys the better customers

Two things worth knowing up front. Amounts are summed per currency and never across, so a multi-currency project gets a block each rather than one wrong total. And a purchase relayed by a webhook lands on a server session with no channel of its own, so --by attributes it to the channel that acquired the payer. Full walkthrough: Revenue & LTV.

Not integrated yet?

The CLI reads data the tracker sends. If this project has no data yet, start with how to integrate — or have your agent do it with the integration skill.