# Claude Code Usage Tracking With TelemHQ

Source HTML: https://telemhq.com/docs/claude-code

Claude Code is a local coding tool, not the Claude API. Track it by adding Claude Code hooks that send TelemHQ metadata after turns, failures, or tool activity.

Use this guide when you want to understand local coding-agent activity across projects or teams. Use the Claude API guide instead when your own app calls Anthropic Messages or Message Batches directly: https://telemhq.com/docs/claude

Create an ad hoc tracker with no schedule for normal Claude Code usage. Add a schedule only if the hook runs from a predictable automation, such as a nightly Claude Code job.

## 1. Save Your Ping URL

Copy the ping URL from a TelemHQ tracker and make it available to the Claude Code process.

```bash
mkdir -p ~/.claude/hooks
chmod 700 ~/.claude/hooks
export TELEMHQ_PING_URL="https://telemhq.com/ping/YOUR_TRACKING_TOKEN"
```

If Claude Code starts outside this shell, put the environment variable in the shell profile or process manager that launches Claude Code.

## 2. Add The Hook Script

Save this as `~/.claude/hooks/telemhq_ping.py`. It sends metadata only: event name, project, session id, tool name, and hashed paths. It does not send prompts, commands, file contents, or Claude output.

```python
#!/usr/bin/env python3
import hashlib
import json
import os
import sys
import urllib.request
from pathlib import Path

FAILED_EVENTS = {"PostToolUseFailure", "StopFailure"}


def short_hash(value):
    if not value:
        return None
    return hashlib.sha256(value.encode("utf-8")).hexdigest()[:12]


def compact_payload(payload):
    return {key: value for key, value in payload.items() if value is not None}


def main():
    ping_url = os.environ["TELEMHQ_PING_URL"]
    event = json.load(sys.stdin)

    cwd = event.get("cwd") or os.getcwd()
    hook_event = event.get("hook_event_name", "ClaudeCode")
    last_message = event.get("last_assistant_message")

    payload = compact_payload({
        "provider": "anthropic",
        "tool": "claude-code",
        "status": "failed" if hook_event in FAILED_EVENTS or event.get("error") else "success",
        "event": hook_event,
        "project": Path(cwd).name or "unknown",
        "session_id": event.get("session_id"),
        "tool_name": event.get("tool_name"),
        "tool_use_id": event.get("tool_use_id"),
        "permission_mode": event.get("permission_mode"),
        "cwd_hash": short_hash(cwd),
        "transcript_path_hash": short_hash(event.get("transcript_path")),
        "error": event.get("error"),
        "last_assistant_message_chars": len(last_message) if isinstance(last_message, str) else None,
    })

    request = urllib.request.Request(
        ping_url,
        data=json.dumps(payload).encode("utf-8"),
        headers={"Content-Type": "application/json"},
        method="POST",
    )

    with urllib.request.urlopen(request, timeout=10) as response:
        if response.status >= 300:
            raise RuntimeError(f"TelemHQ returned HTTP {response.status}")


if __name__ == "__main__":
    try:
        main()
    except Exception as exc:
        if os.getenv("TELEMHQ_HOOK_DEBUG") == "1":
            print(f"TelemHQ hook skipped: {exc}", file=sys.stderr)
        sys.exit(0)
```

```bash
chmod 700 ~/.claude/hooks/telemhq_ping.py
```

## 3. Configure Claude Code

Add this to `~/.claude/settings.json` for all projects, or to `.claude/settings.json` in one repo. `Stop` records one ping after each completed turn. `StopFailure` records API or turn failures.

```json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.claude/hooks/telemhq_ping.py"
          }
        ]
      }
    ],
    "StopFailure": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.claude/hooks/telemhq_ping.py"
          }
        ]
      }
    ]
  }
}
```

## Optional Tool Activity

Add this if you also want a ping after successful file edits and shell commands. This creates more pings, but gives project managers a clearer view of which kinds of Claude Code work are happening.

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash|Edit|MultiEdit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.claude/hooks/telemhq_ping.py"
          }
        ]
      }
    ],
    "PostToolUseFailure": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.claude/hooks/telemhq_ping.py"
          }
        ]
      }
    ]
  }
}
```

## Example Payload

```json
{
  "provider": "anthropic",
  "tool": "claude-code",
  "status": "success",
  "event": "Stop",
  "project": "api",
  "session_id": "abc123",
  "cwd_hash": "d7a8fbb307d7",
  "transcript_path_hash": "04f36e9f3e22",
  "last_assistant_message_chars": 842
}
```

Claude Code hook events do not always expose exact token and cost totals. For exact Claude API usage, use the Claude API guide or add token fields from your own wrapper when available.

## Related Guides

- Claude API pipeline tracking: https://telemhq.com/docs/claude
- Codex usage tracking: https://telemhq.com/docs/codex
- Sending pings: https://telemhq.com/docs/integration
- Claude Code hooks reference: https://code.claude.com/docs/en/hooks
