Your link analytics, in the terminal.
Create tracking links, then pull channels, links, the raw click stream and any visitor's full journey — the same numbers as the dashboard, without leaving your shell. An aligned table when you're reading, tab-separated values when you pipe, and the API's own JSON for jq.
npm install -g trackrevPuts the trackrev command on your PATH. Node 20 or newer.
- Zero dependencies
- Node 20+
- MIT licensed
Install and authenticate
One install, one environment variable.
Install it once with npm, create a secret key under Settings → Developers, and export it. From then on every command is just trackrev — no flags to remember, no config file, no login flow, no daemon. The CLI is a single file that talks to the Analytics API over HTTPS with the key you give it.
- npm install -g trackrev puts a trackrev command on your PATH
- Or skip the install: npx trackrev <command> runs it once, then forgets it
- TRACKREV_API_URL points it at staging or a self-hosted API
# 1. Install the CLI (needs Node 20+)npm install -g trackrev # 2. Create a secret key under Settings → Developers, then export itexport TRACKREV_KEY=lk_live_… # 3. Run it — from here on, every command starts with "trackrev"trackrev channels --days 7 --ltv # Don't want to install it? npx runs one command and keeps nothing:npx trackrev channelsOpen Settings → Developers to create a key · package on npm
Create links. Read everything.
Each command maps to a single API endpoint, so what you do in the terminal is exactly what the dashboard does — same limits, same windows, same attribution model.
trackrev channels --days 7 --ltvtrackrev channelsPaid plan
performance per traffic source
--days N- last N days (default 30, max 365)
--from ISO- explicit start, e.g. 2026-01-01; wins over --days
--to ISO- explicit end (defaults to now)
--ltv- add all-time lifetime value per channel
conversions is a decimal on purpose — attribution splits credit, so one sale touched by two channels counts 0.5 on each.
trackrev links perf --limit 20trackrev links perfPaid plan
performance per short link (bare `trackrev links` still works)
--limit N- rows to return (max 500)
--days N- last N days (default 30, max 365)
--from ISO- explicit start, e.g. 2026-01-01; wins over --days
--to ISO- explicit end (defaults to now)
--settings- attach each link's URL, expiry and password flag
trackrev clicks --all --jsontrackrev clicksPaid plan
the raw click stream — newest first, bots excluded
--limit N- page size (default 100, max 500)
--all- follow the cursor to the end of the stream
--link ID- one link only
--bots- include bot traffic
--all stops after 200 pages and says so on stderr, so a runaway cursor can never loop forever.
trackrev journey <visitor-id>trackrev visitors journeyPaid plan
one visitor's timeline — every click, identify event and order, in order
The visitor caption goes to stderr, so the rows stay pipe-clean.
trackrev links list --channel youtubetrackrev links list
the links themselves — newest first, no window
--limit N- page size (default 100, max 500)
--all- follow the cursor to the end
--channel KEY- one channel only
--q TEXT- slug contains this text
trackrev links create --url https://acme.com/launch --name Launch --channel youtube --channel newslettertrackrev links create
create a campaign: one link per channel, or one Smart Link
--url URL- destination (required)
--name TEXT- campaign name (required)
--channel KEY- a channel; repeat for several
--smart- one link that infers its channel per click
--tag TEXT- a tag; repeat for several
--folder ID- put the campaign in this folder
--external- destination is a site you can't put the pixel on
--slug SLUG- custom slug (2–64 chars; lowercase, digits, hyphens)
--campaign TEXT- utm_campaign (defaults to the name)
--expires ISO- expire at this time
--max-clicks N- expire after this many clicks
--expired-url URL- where to send visitors after expiry
--password TEXT- require this password before redirecting
--mobile-url URL- device targeting: send mobile here
--desktop-url URL- device targeting: send desktop here
--retarget on|off- fire the workspace's ad pixels on click
Prints one row per link created. Channels: facebook instagram youtube linkedin twitter tiktok newsletter website other.
trackrev links get black-fridaytrackrev links get
one link by id, slug or short code
trackrev links update <id> --expires 2026-12-31T23:59:59Z --max-clicks 1000trackrev links update
change a link's slug, UTMs, expiry, password or targeting
--term TEXT- utm_term
--content TEXT- utm_content
--clear-password- remove the password
--clear-expiry- remove date and click-cap expiry
--slug SLUG- custom slug (2–64 chars; lowercase, digits, hyphens)
--campaign TEXT- utm_campaign (defaults to the name)
--expires ISO- expire at this time
--max-clicks N- expire after this many clicks
--expired-url URL- where to send visitors after expiry
--password TEXT- require this password before redirecting
--mobile-url URL- device targeting: send mobile here
--desktop-url URL- device targeting: send desktop here
--retarget on|off- fire the workspace's ad pixels on click
trackrev links delete <id> --yestrackrev links delete
delete one link (its campaign and other channels stay)
trackrev links bulk --file links.csvtrackrev links bulk
create up to 500 links from a CSV
--file PATH- CSV with url, name, channel columns (- for stdin)
Optional columns: utm_campaign, utm_term, utm_content, tags, campaign_id. Rows that fail are listed with the reason; the rest are created.
trackrev links qr black-friday --out black-friday.svgtrackrev links qr
the link's QR code as SVG
--out PATH- write here instead of stdout
--size N- size in px (default 512, max 2048)
trackrev metrackrev me
which workspace, plan, limits and key you're using
trackrev login --profile staging --api-url https://staging.example.com/api/v1trackrev login
save a secret key so you don't need TRACKREV_KEY
--key lk_…- the key (prompted, hidden, when omitted)
--api-url URL- API base for this profile
Stored at ~/.config/trackrev/config.json with mode 0600. TRACKREV_KEY in the environment always wins, for CI.
trackrev logouttrackrev logout
forget a saved key
Every flag, in full, in the CLI reference
Designed for the shell
Reads like a table. Pipes like data.
The same command adapts to where its output is going. On a terminal you get an aligned, comma-formatted table. Into a pipe or a file you get tab-separated raw values — 2410.5, not 2,410.50 — so cut, awk, and sort see real numbers. Add --json and you get the API's own body, untouched, for jq.
- TTY detection — no --format flag to remember
- Piped output is raw on purpose: spreadsheets and scripts get numbers
- --json is the API response verbatim, so the docs are the schema
$ trackrev channelson a terminalchannel clicks revenueyoutube 1,204 2,410.50newsletter 310 1,890.00
$ trackrev channels > channels.tsvinto a pipe or filechannel → clicks → revenueyoutube → 1204 → 2410.5newsletter → 310 → 1890
$ trackrev channels --json | jq .with --json{ "channels": [{ "channel": "youtube", "clicks": 1204, "revenue": 2410.5 },{ "channel": "newsletter", "clicks": 310, "revenue": 1890 }] }
Compose it with the tools you already have.
Because stdout only ever carries data, every command slots into a shell pipeline. Filter the click stream with jq, rank links with sort, diff two windows, or feed a visitor id from clicks straight into journey with xargs. Cron it and you have a nightly export with no dashboard login.
- Cursor pagination handled for you — --all walks the whole stream
- Bots excluded by default; --bots when you want the noise
- ISO timestamps and UUIDs, ready for a warehouse load
# Top five links by revenue, this monthtrackrev links --limit 100 \ | tail -n +2 | sort -t$'\t' -k6,6nr | head -5 # Every click from one country, as JSONtrackrev clicks --all --json \ | jq '.clicks[] | select(.country == "BD")' # Newest visitor → their whole journeytrackrev clicks --limit 1 | tail -1 | cut -f6 \ | xargs trackrev journeystderr for humans, stdout for machines.
Warnings, errors, and the journey caption go to stderr — never into your pipe. Exit codes distinguish a usage mistake from a failed request, so a cron job can tell the difference between a typo and an expired key. And --all caps itself at 200 pages and says so, rather than looping on a bad cursor.
- 0 success · 1 runtime failure · 2 usage error
- 401, 402, and 404 each get a one-line message that says what to do
- No stack traces — an unknown flag is a one-line usage error
- 0Success
- 1No API key · auth failure · network or API error · not found
- 2Usage error — unknown flag or command, bad value, missing argument
- 3Plan required — this command needs a paid plan
Copy, paste, done.
One-liners for the questions teams actually ask. Each one is a complete command — swap the window or the filter and run it.
trackrev links create --url https://acme.com/launch --name Launch \
--channel youtube --channel newsletter | cut -f3trackrev links create --url https://acme.com/beta --name Beta --channel newsletter \
--max-clicks 1000 --expired-url https://acme.com/waitlisttrackrev links bulk --file q4-links.csvtrackrev channels --days 7 | cut -f1,5trackrev links perf --limit 100 | tail -n +2 | sort -t$'\t' -k6,6nr | head -5trackrev clicks --all --json | jq '.clicks[] | select(.country == "BD")'trackrev clicks --limit 1 | tail -1 | cut -f6 | xargs trackrev journeytrackrev clicks --all --json > "clicks-$(date +%F).json"TRACKREV_API_URL=https://staging.example.com/api/v1 trackrev links listFrequently asked
What developers ask before wiring the CLI into a script — cost, install, where the key goes, and what it can't do yet.
Pairs well with
Channel Analytics
Rank every channel by revenue — not clicks — and spot the real winners.
Learn moreVisitor Journey Timeline
Every step from first click to paid customer, stitched into one timeline.
Learn moreAnalytics Breakdown
OS, browser, device, and geo analytics on every click and conversion.
Learn morenpm install -g trackrev
Install it, create a secret key, export it — then trackrev channels is the whole workflow. The CLI is free and open source; the Analytics API it reads from is included on every paid plan.
MIT licensed · Zero dependencies · Node 20+