Getting started
Install
Requirements: Node.js 22.13 or newer (for node:sqlite) and pnpm to build.
git clone https://github.com/smartargs/earnback.git
cd earnback
pnpm install
pnpm build
npm link # puts `earnback` on your PATH
earnback demo # a made-up studio, to look around first
Your first project
cd ~/games/my-game
earnback init # writes earnback.config.json and ignores .earnback/ in git
- Edit
earnback.config.json: your app’s ids underapps, then enable the sources you use underconnectors. Each source has a setup guide. - Put the API keys where
earnback inittold you (your user config folder, never the project folder). - Run
earnback connect googleonce if you use AdMob, or Google Ads / GA4 with your own login. earnback doctorchecks the config, the secrets and every connection.earnbacksyncs and opens the report.
Run earnback whenever you want fresh numbers. The first sync reads everything since start; later syncs re-read only the last few weeks, because platforms revise recent days.
Configuration
earnback.config.json lives in your project folder and holds no secrets, so you can commit it.
{
"project": "my-game",
"start": "2026-09-01", // first day to sync
"timeZone": "Europe/Vienna", // your reporting day
"currency": "EUR",
"apps": [
// every id the platforms use for this app: package name, App Store id, GA4 property, AdMob app ids
{ "id": "my-game", "name": "My Game", "keys": ["com.example.mygame", "123456789", "ca-app-pub-…~…"] }
],
"secrets": {}, // optional: secret name → file path, when a key lives elsewhere
"channels": [
// optional: extra rules mapping GA4 first-user source/medium to a channel, checked before the defaults
{ "source": "partner-network", "channel": "partner" }
],
"funnel": [
{ "event": "first_open", "label": "Opened" },
{ "event": "tutorial_complete", "label": "Finished tutorial" }
],
"connectors": {
"google-ads": { "enabled": true, "customerId": "123-456-7890" },
"meta": { "enabled": true, "adAccounts": ["act_1234567890"] },
"ga4": { "enabled": true, "properties": ["123456789"] },
"admob": { "enabled": true, "publisherId": "pub-1234567890123456" }
},
"plans": []
}
Errors name the field that is wrong (connectors.meta.adAccounts needs at least one entry), and earnback doctor tells you what is missing and where it goes.
Secrets
Each secret has a name (google-service-account.json, meta-token, …). Earnback looks for it in this order:
- the environment variable
EARNBACK_<NAME>holding the content itself (e.g.EARNBACK_META_TOKEN), for CI; - a path you map in the config’s
secrets("meta-token": "/path/to/meta-token.txt"); - a file of that name in the project’s secrets folder:
%APPDATA%\earnback\<project>\on Windows,~/.config/earnback/<project>/elsewhere (EARNBACK_HOMEmoves it).
Files Earnback writes (login tokens) get mode 600. earnback doctor warns when a secret sits inside a git repository that doesn’t ignore it.
Tests with budgets and pass marks
A plan describes a test you are running: which campaigns, what you expect to spend, the hard limit, the marks that decide whether it passed, and the review dates. The Overview shows it on top, the digest reports it every morning, and earnback check exits with code 1 when a budget limit or a stop mark is crossed (for cron or CI).
"plans": [
{
"id": "us-video-test",
"name": "US video test",
"note": "Which of the three videos brings players who finish the tutorial?",
"from": "2026-11-06",
"to": "2026-11-19",
"campaigns": [
{ "source": "meta", "campaignId": "1202…", "expected": 150, "hardLimit": 150, "approved": 200 }
],
"marks": [
{ "label": "Cost per player who opened", "metric": "costPerPlayer", "channels": ["meta"], "max": 0.5, "stopAbove": 1, "minPlayers": 20 },
{ "label": "Finished the tutorial", "metric": "stepRate", "step": "tutorial_complete", "channels": ["meta"], "min": 0.6, "minPlayers": 20 },
{ "label": "Back the next day", "metric": "retention", "day": 1, "channels": ["meta"], "min": 0.25, "minPlayers": 20 },
{ "label": "Watched 3 seconds", "metric": "hookRate", "channels": ["meta"], "min": 0.25, "minImpressions": 1000 }
],
"reviews": [{ "date": "2026-11-09", "note": "First look: which video gets taps?" }]
}
]
Marks: costPerPlayer, stepRate, retention, earnedBack, hookRate, holdRate, tapRate. Each waits for minPlayers or minImpressions before it judges (“too early” until then). Definitions are in Metrics.
Several projects
Every folder with an earnback.config.json is a project. earnback init registers it in your workspace (workspace.json in the Earnback config folder); earnback projects add registers an existing one.
earnback projects # list (* marks the default)
earnback projects add ~/games/other
earnback projects default my-game
earnback -p other # sync and open another project from anywhere
earnback --all # sync every project and open the portfolio page
Inside a project folder, commands run on that project; elsewhere they run on the default project. With --all, sync, open, digest and check run on every registered project, and open builds a portfolio report with a project switcher.
Commands
| Command | Does |
|---|---|
earnback |
sync, then open the report |
earnback sync [--full] [--source id] |
fetch new data; --full re-reads everything from start |
earnback open [--no-sync] [--no-open] |
build the report (and open it) |
earnback digest [--send] [--force] |
build today’s digest; deliver it; deliver again today |
earnback check |
evaluate plans; exit 1 on a budget or stop alert |
earnback init [name] |
create the config here and register the project |
earnback projects [add|remove|default] |
manage registered projects |
earnback connect <google|tiktok|telegram|webhook> |
guided login or setup, then a test call |
earnback doctor |
check the config, secrets and every connection |
earnback schedule [--time HH:MM] |
print how to send the digest every day |
earnback demo |
open a report with made-up data |
Global options: -p, --project <name>, --all, -h, -v.
Where things live
| What | Where |
|---|---|
| Config (commit it) | <project>/earnback.config.json |
| Data and report (git-ignored) | <project>/.earnback/data.sqlite, <project>/.earnback/report.html |
| Secrets | %APPDATA%\earnback\<project>\ or ~/.config/earnback/<project>/ |
| Registered projects, digest settings | <earnback home>/workspace.json |
| Digest secrets (bot token, webhook URL) | <earnback home>/_workspace/ |
| Portfolio report | <earnback home>/portfolio.html |