{"id":"2fb0d425-055c-4141-9301-6500d7f4c805","slug":"game-analytics-kit","kind":"skill","name":"game-analytics-kit","summary":"Game analytics skills for Claude Code and Codex: AppMetrica events → local SQLite → versioned HTML reports in one fixed structure. Python stdlib only.","owner":"Trafalgardi","repoUrl":"https://github.com/Trafalgardi/game-analytics-kit","license":"MIT","licenseTier":"permissive","trust":"community","stars":0,"match":null,"fewStars":true,"format":"skill","createdAt":"2026-09-23T09:58:11.000Z","addedAt":"2026-10-21T11:40:02.622Z","logoUrl":"https://avatars.githubusercontent.com/u/34792447?u=bdd0d702d51cecc75a8c0b8baf9f9d5e14e45787&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["data-analytics","databases","developer-tools"],"tags":["analytics","appmetrica","claude-code","codex","game-analytics","gamedev","mobile-games","python"],"runtime":"binary","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-22T17:34:17.609Z","sample":false,"url":"https://conduits.dev/tools/game-analytics-kit","language":"Python","transports":["stdio"],"install":{},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"**English** · [Русский](README.ru.md)\n\n# game-analytics-kit\n\n[![tests](https://github.com/Trafalgardi/game-analytics-kit/actions/workflows/ci.yml/badge.svg)](https://github.com/Trafalgardi/game-analytics-kit/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)\n![Dependencies: none](https://img.shields.io/badge/dependencies-none-brightgreen.svg)\n![Claude Code and Codex](https://img.shields.io/badge/agents-Claude%20Code%20%C2%B7%20Codex-6f42c1.svg)\n\n**[Live example report](https://trafalgardi.github.io/game-analytics-kit/examples/sample/v002/report.html)** · [Site](https://trafalgardi.github.io/game-analytics-kit/) · [Quick start](#quick-start)\n\nA kit that turns a coding agent — **Claude Code** or **OpenAI Codex** — into a game analyst.\nInstalled into a game project, it lets the agent pull the game's raw analytics into a local\ndatabase, learn what this particular game's events mean, answer product questions and\npublish versioned reports: one HTML file per version that opens from disk and can be\nforwarded to anyone.\n\nThe kit is the same for every project. Everything game-specific — event meaning, filters,\ncohorts, queries, notes about the data — the agent writes inside the project, guided by the\nkit's skills.\n\n![The first screen of a full review: title, blocks, key metrics by build version](docs/images/report-summary.png)\n\n- [What you get](#what-you-get)\n- [Quick start](#quick-start)\n- [Working with Claude Code and Codex](#working-with-claude-code-and-codex)\n- [What to ask](#what-to-ask)\n- [Reports](#reports)\n- [Big games](#big-games)\n- [Updating and removing](#updating-and-removing)\n- [The token and security](#the-token-and-security)\n- [Troubleshooting](#troubleshooting)\n- [Developing the kit](#developing-the-kit)\n\n## What you get\n\n**Seven skills** — instructions the agent loads when a request matches them. Installed for\nboth agents (`.claude/skills/` and `.agents/skills/`).\n\n| Skill | What it does |\n| --- | --- |\n| `analytics-kit` | Entry point: what is installed, every command, which skill to use next, how to update |\n| `analytics-connect-appmetrica` | Finds the SDK key in the game code, walks you through a read-only token, resolves the app, runs the first data pull |\n| `analytics-data-model` | Learns the game's events and builds the project model: typed events, devices, developer-device filter, sessions, per-player metrics |\n| `analytics-project-audit` | Compares what the code sends with what arrives: coverage, broken events, a tracking plan, data to request |\n| `analytics-import-external` | Google Ads, AdMob, GA4 / Firebase, Play Console, App Store Connect: what to export, how to import and reconcile |\n| `analytics-research` | The analyst: a question or a full review → data → hypotheses → independent check of the key numbers → report |\n| `analytics-report` | Writes, builds, versions and publishes the report in one fixed structure |\n\n**An engine** (`kit/gak`, Python standard library only — nothing to `pip install`): AppMetrica\nLogs API sync by date ranges into SQLite, device sampling for big games, an event catalog, a\nmodel scaffold, queries, CSV import from ad and store consoles, the standard tables of every\nreport (key metrics by build version, drop-off, core actions by their number in the session,\nleaving after events), SVG charts and the report builder.\n\nSources today: **AppMetrica** events, sessions, installs, ad revenue, purchases, crashes and\nerrors; ad-network and store numbers come as CSV exports or screenshots. The engine has a\nsource interface for adding Firebase, GameAnalytics, devtodev and others.\n\n## Quick start\n\nYou need:\n\n- a game that already sends events to **AppMetrica** (the SDK is in the game and the app exists\n  in the AppMetrica console) — it is the source the kit reads today;\n- **Python 3.11+** — on Windows the `py` launcher from python.org; on macOS/Linux use\n  `python3` wherever this page says `py`;\n- **git**, and **Claude Code** or **Codex** installed and signed in.\n\nBelow, `<kit>` is the folder where you clone this repository and `<project>` is the root of the\ngame's git repository. For Unity that is the folder with `Assets/` and `ProjectSettings/`, or the\nrepository root above it if the Unity project sits in a subfolder. The kit puts its `analytics/`\nfolder there, next to `Assets/`, never inside it (`--analytics-dir` picks another place).\n\n**1. Clone the kit once**\n\n```bash\ngit clone https://github.com/Trafalgardi/game-analytics-kit.git <kit>\n```\n\n**2. Install it into the game project**\n\n```bash\npy <kit>/install.py <project>\n```\n\nThis adds the skills, `analytics/ga.py` (the command launcher) and `analytics/analytics.toml`\n(project settings). `--dry-run` shows the plan without changing anything.\n\n**3. Get an AppMetrica token** — a read-only OAuth token of the Yandex account that sees the app:\n\n1. Open <https://oauth.yandex.ru/client/new>, create an app: platform **Web services**, Redirect\n   URI `https://oauth.yandex.ru/verification_code`, permission **AppMetrica → `appmetrica:read`**.\n2. Copy its **ClientID**, open `https://oauth.yandex.ru/authorize?response_type=token&client_id=<ClientID>`,\n   confirm, and copy `access_token` from the address bar.\n3. Save it in a file, not in the chat. One file serves every project of that account:\n\n   ```bash\n   mkdir -p ~/.config/game-analytics-kit        # Windows (cmd): mkdir %USERPROFILE%\\.config\\game-analytics-kit\n   ```\n\n   and create `.env` in that folder with one line:\n\n   ```\n   APPMETRICA_TOKEN=<your token>\n   ```\n\n   Only for this project instead: the same line in `<project>/analytics/.env` (git-ignored).\n\n**4. Check that the kit sees the token**\n\n```bash\ncd <project>\npy analytics/ga.py status\n```\n\nExpect `token APPMETRICA_TOKEN: found in ...`. `py analytics/ga.py selftest` checks the engine\noffline. Run every `analytics/ga.py` command from the project root.\n\n**5. Start the agent in the project and ask in plain words, one request at a time**\n\n```bash\ncd <project>\nclaude          # or: codex\n```\n\n1. `Connect AppMetrica and pull the last two weeks.` — the agent finds the SDK key in the code,\n   fills `analytics/analytics.toml`, measures the data volume and starts the pull in the\n   background (10–60 minutes for two weeks, depending on the game). It waits for the pull\n   itself and says when it is done; `py analytics/ga.py status` shows the loaded days too.\n2. `Build the data model.` — the agent learns the game's events and writes the project model.\n3. `Audit our analytics.` — optional but recommended the first time: what the game tracks,\n   what is broken, what to fix before trusting the numbers.\n4. `Make a full review of the game for the last two weeks.` — the full report.\n\nThe agent names each report (its *slug*) after the request: the report is\n`analytics/reports/<slug>/v001/report.html`, and `analytics/reports/index.html` lists them all.\nRequests work in any language; reports are written in `report_language` from\n`analytics/analytics.toml` — Russian by default, `report_language = \"en\"` for English.\nThe agent asks before running commands unless you allow them; allow `py analytics/ga.py ...`\nfor the session to avoid a prompt per command.\n\n## Working with Claude Code and Codex\n\nBoth agents discover the skills by themselves; you do not name them.\n\n| | Claude Code | Codex |\n| --- | --- | --- |\n| Skills folder | `<project>/.claude/skills/analytics-*` | `<project>/.agents/skills/analytics-*` |\n| Interactive | `cd <project>` → `claude` → type the request | `cd <project>` → `codex` → type the request |\n| One-shot (headless) | `cd <project>` → `claude -p \"Make a full review of the last two weeks\"` | `codex exec -C <project> \"Make a full review of the last two weeks\"` |\n| Publishing | the local `report.html`, plus a Claude Artifact link where the environment supports it | the local `report.html` |\n\n- Install for one agent only with `--agents claude` or `--agents codex`.\n- Headless runs need permission to run commands (`claude -p --dangerously-skip-permissions`,\n  `codex exec --dangerously-bypass-approvals-and-sandbox`) — use them in a project you trust.\n- Long data pulls run as detached background jobs, so they survive the end of an agent's\n  session; the agent follows them with `py analytics/ga.py sync --wait`.\n\n## What to ask\n\n| Ask | Skill | Result |\n| --- | --- | --- |\n| \"Connect AppMetrica\", \"pull fresh data\", \"sync failed\" | connect-appmetrica | data in `analytics/data/analytics.db`, settings in `analytics.toml` |\n| \"Build the data model\", \"we added events in 1.2\" | data-model | `analytics/model/*.sql`, facts in `analytics/notes/project.md` |\n| \"Audit our analytics\", \"what do we track?\" | project-audit | report `tracking-audit` + tracking plan |\n| \"Make a full review of the last two weeks\" | research | report of the kind *full review* |\n| \"Where do we lose new players?\", \"did 1.2 help?\", \"does paid UA pay back?\" | research | report of the kind *question* |\n| \"Here is an AdMob export / a Google Ads screenshot\" | import-external | `ext_*` tables, numbers reconciled with events |\n| \"Update the report\", \"fix the numbers in section 3\" | report | a new version of the report |\n\nWhat the agent learns about the project stays in the project: `analytics/notes/project.md`\n(durable facts: event meaning, filters, time zone) and `analytics/notes/findings.md` (dated\nconclusions). Every next session starts by reading them.\n\n## Reports\n\nEvery report has the same structure, so you — and the next agent — find things in the same\nplace:\n\n| # | Block | Content |\n| --- | --- | --- |\n| 1 | Summary | key-metrics table with **build versions as columns** (D1/D3/D7, playtime, sessions, session length, interstitials and rewarded per player, ARPU, revenue, players) and short answers to what you asked |\n| 2 | Product | retention, the **drop-off table** (loading and tutorial steps, then every 30 s of the first 10 minutes), core loop, leaving after negative events, economy |\n| 3 | Revenue | ads by format, placement and network; purchases |\n| 4 | Technical | technical problems and analytics defects (duplicates, empty fields, sources that disagree) |\n| 5 | Countries | the country split in one place |\n| 6 | Hypotheses | H1, H2… — claim, the numbers it rests on (linked), how to test it, confidence |\n| 7 | Recommendations | each linked to a hypothesis, with the expected effect and how to measure it |\n| — | Data needed, method | what to export from which console; sources, filters, definitions |\n\nA **full review** has all blocks; a **question** report keeps 1, 6, 7 and only the blocks it\nneeds. The title is your request (\"MyGame 0.2.0, 08–21.09: full review\"); the thesis is the\nline under it. Facts are separated from interpretation, and every number in the answers,\nhypotheses and recommendations appears in a table or chart of the report. The builder refuses\na report whose structure or links are broken.\n\n![Hypotheses with confidence and recommendations linked to them](docs/images/report-hypotheses.png)\n\n- A version is final once built. A correction or new data is a new version (`v002`) that\n  starts with \"what changed\".\n- `report.html` is one self-contained file (only fonts load from the web); light and dark\n  themes; readable on a phone.\n- Live examples on made-up numbers: [on the site](https://trafalgardi.github.io/game-analytics-kit/examples/index.html) and in\n  [docs/examples/sample-report/en/analytics/reports/](docs/examples/sample-report/en/analytics/reports/)\n  (the same in Russian: [ru/](docs/examples/sample-report/ru/analytics/reports/))\n  (`sample` — a full review in three versions, `sample-question` — a question report). Open\n  `index.html` from a clone to browse them.\n\n## Big games\n\nEvent volume differs between games by two orders of magnitude. Before the first large pull the\nagent downloads one day into a scratch database and picks a mode by volume:\n\n- `sample = 0.1` in `analytics.toml` keeps 10% of devices — the same devices in every table,\n  so rates, medians and funnels are not biased. Absolute numbers (players, impressions, revenue)\n  are shown both as the sample and as an estimate (×10), marked \"≈ estimate\".\n- `flatten_params = false` skips the parameters table, the biggest part of the database\n  (~6 KB per event).\n\nThe engine also refuses to load a chunk that would not fit on the disk and says which lever to\nuse. A real case: ~600k events a day — with a 5% sample and no flattening, two weeks load in\nabout 15 minutes into a ~200 MB database.\n\n## Updating and removing\n\n```bash\ngit -C <kit> pull                            # get the kit's current version\npy <kit>/install.py <project>              # update the project (same command as install)\npy <kit>/install.py <project> --dry-run    # what would change\npy <kit>/install.py <project> --uninstall  # remove the kit and its skills; data, notes and reports stay\n```\n\nAn update replaces only what the kit owns — the skill\nfolders it installed (they carry a `.gak-managed` marker), `analytics/kit/` and\n`analytics/ga.py`. Your `analytics.toml`, `.env`, data, model, queries, notes and reports are\nnever touched; your own skills in `.claude/skills/` are left alone. After an update:\n`py analytics/ga.py status`, `py analytics/ga.py selftest`, `py analytics/ga.py model apply`.\nThe installed version is recorded in `analytics/kit.install.json`; the changes are in\n[CHANGELOG.md](CHANGELOG.md).\n\nWhat to commit in the game repository: `analytics/analytics.toml`, `model/`, `queries/`,\n`notes/`, `reports/`, `ga.py`, `kit/`, `kit.install.json` and the skill folders, so that everyone on the team gets\nthe same kit with the project. `analytics/.gitignore` already excludes the database, console\nexports, report scratch folders and `.env`.\n\n## The token and security\n\n- The AppMetrica token is read-only (`appmetrica:read`). It is looked up in this order: the\n  `APPMETRICA_TOKEN` environment variable, `<project>/analytics/.env`,\n  `~/.config/game-analytics-kit/.env`.\n- The kit never prints, logs or stores the token: not in the database, reports, notes,\n  `analytics.toml` or git. `status` only says where it was found.\n- Do not paste the token into the chat. If you do, the agent will not repeat it and will ask\n  you to save it to a file; revoke it at <https://oauth.yandex.ru> if it leaked anywhere.\n- The SDK key from the game code (a UUID) is not a secret; it goes into `analytics.toml`.\n- Advertising ids, IP addresses and operators are not downloaded unless you ask for them\n  explicitly (`sync --with-device-ids`).\n- The database stays on your machine. Reports contain aggregates, not device-level data.\n\n## Troubleshooting\n\n| Symptom | What to do |\n| --- | --- |\n| `py` is not found | Install Python 3.11+ from python.org (it adds the `py` launcher on Windows); on macOS/Linux use `python3` |\n| `status` says the token is not found | Check the file name and the line `APPMETRICA_TOKEN=...` in one of the three places above |\n| `401` during sync | The token is missing, expired or from an account that does not see the app — issue a new one |\n| `429` or a sync that sits at \"preparing\" | AppMetrica prepares exports one at a time and allows three in a queue; the kit waits. Do not start a second sync; if one range is stuck for long, the agent re-requests it with another chunk size |\n| `database is locked` | Two syncs into one database. Wait for the running one (`py analytics/ga.py sync --wait`) or pull the urgent table into a scratch file with `sync --db data/scratch.db` |\n| The disk fills up | Set `sample = 0.1` and `flatten_params = false` in `analytics.toml` or pull a shorter period. The sample rate is fixed per database by its first sync: to change it, start a new database (delete `analytics/data/analytics.db` or point `[database].path` elsewhere) |\n| The agent ended while data was still loading | The pull keeps running in the background; ask the agent to continue — it waits with `sync --wait` |\n| `report build` fails | It lists every problem (missing chart, empty field, broken structure or link); ask the agent to fix them and build again |\n| A built report has a mistake | Built versions are final: ask for a new version, it will say what changed |\n| Codex: \"model requires a newer version of Codex\" | Update the Codex CLI or pass a model it knows: `codex exec -m <model> ...` |\n| The kit behaves differently from this page | `py analytics/ga.py status` shows the installed version; update with `install.py` |\n\n## Developing the kit\n\nRead [CONTRIBUTING.md](CONTRIBUTING.md) first. The contract is [docs/DESIGN.md](docs/DESIGN.md)\n(change it first, then the code, then the skills); the field experience the skills are written\nfrom is [docs/KNOWLEDGE.md](docs/KNOWLEDGE.md); end-to-end tests with real agents are in\n[docs/TESTING.md](docs/TESTING.md) and [docs/TEST_LOG.md](docs/TEST_LOG.md). Rules for agents\nthat work on the kit itself: [AGENTS.md](AGENTS.md).\n\n```bash\npy kit/selftest.py                               # engine, offline, synthetic data\npy tests/test_install.py                         # installer\npy docs/examples/sample-report/make_sample.py    # report builder and the examples\npy install.py <scratch project folder> --dry-run # the install plan\n```\n\n`py install.py <project> --link` links the skills and the engine to your clone instead of\ncopying them, so a change in the kit is visible in the project at once.\n\n## License\n\n[MIT](LICENSE).\n"}