npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

trackrev

v0.3.0

Published

The TrackRev SDK and CLI — tracking links, channel analytics, referrals and affiliate payouts, from Node or the terminal.

Readme

trackrev

TrackRev for Node and the terminal — create and manage tracking links, pull performance per channel and per link, walk the raw click stream, replay any visitor's journey from first click to paid conversion, and run a referral program end to end.

One package, two ways in: import { TrackRev } from "trackrev" in your app, or the trackrev command in your shell. Zero dependencies. Node 20 or newer.

Install

In your project, for the SDK:

npm install trackrev

Globally, for the CLI:

npm install -g trackrev

Or run the CLI once without installing:

npx trackrev channels

Authenticate

Create a secret key under Settings → Developers, then either save it:

trackrev login

It is stored at ~/.config/trackrev/config.json with mode 0600 and verified against the API before it is written, so a typo fails immediately rather than on your next command.

Or set it in the environment, which always wins and is what CI should use:

export TRACKREV_KEY=lk_live_...

TRACKREV_API_URL points the CLI at a different API base (self-hosted, staging). Use --profile NAME on login to keep several environments side by side.

Plans

Link and account commands work on every plan, including free, and respect the same limits the dashboard does (50 links on the free tier). Analytics commands — channels, links perf, clicks, journey — need a paid plan; on a free workspace they exit 3 with an upgrade message.

Node SDK

Everything below, as a client for your own code. Twenty resources, 71 methods, and a hand-written index.d.ts, so an editor completes trackrev.links. and catches a misspelled option before the code runs.

import { TrackRev } from "trackrev";

const trackrev = new TrackRev(process.env.TRACKREV_KEY);

const { channels } = await trackrev.channels.list({ days: 7 });

const launch = await trackrev.links.create("https://acme.com/launch", "Launch", {
  channels: ["youtube", "newsletter"],
  maxClicks: 1000,
});

Required arguments are positional; everything optional goes in a trailing object, named in camelCase and sent as the snake_case the API expects.

trackrev.attribution   .get .update
trackrev.channels      .list
trackrev.clicks        .list
trackrev.commissions   .list .create .setStatus
trackrev.credits       .list .markDelivered
trackrev.domains       .list .get .add .verify .remove
trackrev.export        .csv
trackrev.folders       .list .get .create .update .remove .assign
trackrev.keys          .list .create .revoke
trackrev.links         .list .records .get .create .update .remove .createMany .qr
trackrev.orders        .list
trackrev.partners      .list .setStatus .setGroup
trackrev.payouts       .list .settle
trackrev.programs      .list .get .update .groups
trackrev.referrals     .enroll .reportSignup .reportPurchase .stats
                       .setPayoutMethod .setRewardMode
trackrev.retargeting   .list .set .remove
trackrev.revenue       .connections .connection .providers .connect
                       .setWebhookSecret .disconnect .sync
trackrev.settings      .notifications .setNotification .branding .updateBranding
trackrev.visitors      .list .get .journey
trackrev.webhooks      .list .events .get .create .update .remove
trackrev.me()

A referral program, end to end

// Someone opts in. You get back their referral link.
const { referral_link } = await trackrev.referrals.enroll(user.id, user.email, "paid");

// Someone they invited signs up.
await trackrev.referrals.reportSignup(newUser.id, { refCode: "abc123" });

// That person pays. Idempotent on your own order id, so a replay never double-credits.
await trackrev.referrals.reportPurchase(newUser.id, order.id, 49.99, { currency: "usd" });

Errors

Anything that is not a success rejects with a TrackRevError carrying the HTTP status and the API's own code. A request that never got an answer — server unreachable, or timed out — rejects with a TrackRevConnectionError, which is a TrackRevError with status 0.

import { TrackRev, TrackRevError, TrackRevConnectionError } from "trackrev";

try {
  await trackrev.keys.create({ scope: "secret", label: "CI" });
} catch (e) {
  if (e instanceof TrackRevConnectionError) retryLater();
  else if (e instanceof TrackRevError) console.error(e.status, e.code, e.message);
  else throw e;
}

Retries

A request that is safe to repeat is retried three times on a 429, a 5xx or a connection failure, backing off 400ms, 800ms, 1600ms with a little randomness so throttled clients do not all return in the same instant. A Retry-After header wins over that schedule.

Safe to repeat means every GET, plus the three referral writes the API ignores a repeat of: enroll, reportSignup and reportPurchase. Every other write — creating a link, minting a key, settling a payout — is sent exactly once, because a retry there could do the work twice.

Options

new TrackRev(key, {
  apiUrl: "https://app.trackrev.io/api/v1", // point at staging or self-hosted
  timeoutMs: 15000,                         // per attempt; 0 means no limit
  maxRetries: 3,                            // 0 turns retries off
});

An endpoint the SDK has no method for yet is one call away:

await trackrev.request("GET", "/some/new/endpoint");

Commands

Generated from apps/cli/src/registry.js — edit there, then run pnpm --filter trackrev sync-docs.

Analytics

trackrev channels

performance per traffic source (paid plan)

trackrev channels --days 7 --ltv

| flag | meaning | | --- | --- | | --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

performance per short link (bare trackrev links still works) (paid plan)

trackrev links perf --limit 20

| flag | meaning | | --- | --- | | --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

the raw click stream — newest first, bots excluded (paid plan)

trackrev clicks --all --json

| flag | meaning | | --- | --- | | --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 visitors journey <visitor-id>

one visitor's timeline — every click, identify event and order, in order (paid plan)

trackrev journey <visitor-id>

The visitor caption goes to stderr, so the rows stay pipe-clean.

Links

trackrev links list

the links themselves — newest first, no window

trackrev links list --channel youtube

| flag | meaning | | --- | --- | | --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

create a campaign: one link per channel, or one Smart Link

trackrev links create --url https://acme.com/launch --name Launch --channel youtube --channel newsletter

| flag | meaning | | --- | --- | | --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 <id-or-slug>

one link by id, slug or short code

trackrev links get black-friday

trackrev links update <id>

change a link's slug, UTMs, expiry, password or targeting

trackrev links update <id> --expires 2026-12-31T23:59:59Z --max-clicks 1000

| flag | meaning | | --- | --- | | --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>

delete one link (its campaign and other channels stay) (asks to confirm; --yes in scripts)

trackrev links delete <id> --yes

trackrev links bulk

create up to 500 links from a CSV

trackrev links bulk --file links.csv

| flag | meaning | | --- | --- | | --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 <id-or-slug>

the link's QR code as SVG

trackrev links qr black-friday --out black-friday.svg

| flag | meaning | | --- | --- | | --out PATH | write here instead of stdout | | --size N | size in px (default 512, max 2048) |

Developers

trackrev keys list

the workspace's API keys (prefixes only)

trackrev keys list --revoked

| flag | meaning | | --- | --- | | --revoked | include revoked keys |

trackrev keys create

mint a key — the plaintext is shown once, never again

trackrev keys create --label 'CI deploy'

| flag | meaning | | --- | --- | | --scope SCOPE | secret (servers, CLI) or public (browser) | | --label TEXT | what this key is for |

The key goes to stdout and everything else to stderr, so trackrev keys create > key.txt captures only the key.

trackrev keys revoke <id>

revoke a key immediately (asks to confirm; --yes in scripts)

trackrev keys revoke <id> --yes

trackrev webhooks list

outbound endpoints, with their last delivery status

trackrev webhooks list

trackrev webhooks events

every event an endpoint can subscribe to

trackrev webhooks events

trackrev webhooks create

add an endpoint — the signing secret is shown once

trackrev webhooks create --url https://acme.com/hook --event sale.created

| flag | meaning | | --- | --- | | --url URL | https endpoint (required) | | --event NAME | an event; repeat for several |

https only. Run trackrev webhooks events for the valid names.

trackrev webhooks update <id>

change the URL or events, or pause and resume delivery

trackrev webhooks update <id> --pause

| flag | meaning | | --- | --- | | --url URL | new endpoint URL | | --event NAME | replace the event list; repeat | | --pause | stop delivering | | --resume | start delivering again |

trackrev webhooks delete <id>

remove an endpoint (asks to confirm; --yes in scripts)

trackrev webhooks delete <id> --yes

Setup

trackrev attribution get

the model and lookback window this workspace uses

trackrev attribution get --models

| flag | meaning | | --- | --- | | --models | list the three models and what each credits |

trackrev attribution set

change the model or the window

trackrev attribution set --model linear --window 60

| flag | meaning | | --- | --- | | --model NAME | last_touch, first_touch or linear | | --window N | lookback in days (1-365) |

Both settings apply retroactively — every past order is re-credited against them.

trackrev folders list

campaign folders, with how many campaigns each holds

trackrev folders list

trackrev folders create

create a folder to group campaigns under

trackrev folders create --name 'Q4 launch' --start 2026-10-01

| flag | meaning | | --- | --- | | --name TEXT | folder name (required) | | --description TEXT | what it covers | | --start YYYY-MM-DD | start date | | --end YYYY-MM-DD | end date |

trackrev folders update <id>

rename a folder or change its dates

trackrev folders update <id> --name 'Q1 launch'

| flag | meaning | | --- | --- | | --name TEXT | new name | | --description TEXT | new description | | --start YYYY-MM-DD | start date | | --end YYYY-MM-DD | end date |

trackrev folders delete <id>

delete a folder — its campaigns become ungrouped, not deleted (asks to confirm; --yes in scripts)

trackrev folders delete <id> --yes

trackrev folders assign <destination-id>

file a campaign under a folder, or un-file it

trackrev folders assign <destination-id> --folder <folder-id>

| flag | meaning | | --- | --- | | --folder ID | folder to file under; omit to un-file |

The id is a CAMPAIGN (the destination behind a set of links), not a single link.

Revenue

trackrev revenue list

connected payment providers and their last sync

trackrev revenue list

trackrev revenue providers

what can be connected, and the credentials each needs

trackrev revenue providers

Stripe is absent by design — its restricted key lives on the workspace, not here.

trackrev revenue connect

connect a provider — credentials are verified before saving

trackrev revenue connect --provider polar --field api_key=polar_oat_…

| flag | meaning | | --- | --- | | --provider NAME | polar, lemonsqueezy, paddle, creem or dodo | | --field K=V | credential as key=value; repeat per field | | --sandbox | use the provider's sandbox host, where it has one |

trackrev revenue sync

pull charges now and attribute them (paid plan)

trackrev revenue sync

| flag | meaning | | --- | --- | | --connection ID | one connection only; omit for all + Stripe |

Reports imported and attributed per provider. A provider that fails does not stop the others.

trackrev revenue disconnect <id>

disconnect a provider; imported orders are kept (asks to confirm; --yes in scripts)

trackrev revenue disconnect <id> --yes

Audience

trackrev visitors list

visitors, most recently seen first (paid plan)

trackrev visitors list --email @acme.com

| flag | meaning | | --- | --- | | --limit N | page size (default 100, max 500) | | --all | follow the cursor to the end | | --email TEXT | email contains this text |

trackrev visitors get <id>

one visitor (paid plan)

trackrev visitors get <id>

trackrev orders list

synced purchases, newest first

trackrev orders list --status refunded

| flag | meaning | | --- | --- | | --limit N | page size (default 100, max 500) | | --all | follow the cursor to the end | | --status NAME | paid or refunded | | --email TEXT | email contains this text |

amount is blank on the free plan, where revenue figures are hidden.

trackrev export

any dataset as CSV (paid plan)

trackrev export --kind orders --days 90 --out orders.csv

| flag | meaning | | --- | --- | | --kind NAME | channels, links, orders or visitors | | --out PATH | write here instead of stdout | | --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) |

Domains

trackrev domains list

branded short-link domains and their DNS status

trackrev domains list

trackrev domains add <domain>

attach a domain — prints the DNS records to add

trackrev domains add go.acme.com

trackrev domains verify <domain-or-id>

re-check DNS now; exits non-zero until it is active

trackrev domains verify go.acme.com

Exits 1 while still pending, so a deploy script can poll until it passes.

trackrev domains remove <domain-or-id>

detach a domain; links keep working on the default host (asks to confirm; --yes in scripts)

trackrev domains remove go.acme.com --yes

trackrev retargeting list

the ad pixels fired on opted-in link clicks

trackrev retargeting list --providers

| flag | meaning | | --- | --- | | --providers | show what can be configured instead |

trackrev retargeting set <provider>

set a provider's pixel id

trackrev retargeting set meta --id 1234567890123456

| flag | meaning | | --- | --- | | --id ID | the pixel/tag id (required) |

The id must match that provider's shape — only validated ids are ever put into a loader snippet.

trackrev retargeting remove <provider>

remove a provider's pixel (asks to confirm; --yes in scripts)

trackrev retargeting remove meta --yes

Affiliate

trackrev programs list

the workspace's affiliate programs and their terms

trackrev programs list --archived

| flag | meaning | | --- | --- | | --archived | include archived programs |

trackrev programs get <id>

one program in full

trackrev programs get <id>

trackrev programs update <id>

change commission terms, or pause and archive (paid plan)

trackrev programs update <id> --rate 0.25 --status paused

| flag | meaning | | --- | --- | | --name TEXT | program name | | --landing-url URL | where partner links point | | --type TYPE | percent or flat | | --rate N | 0-1 fraction for percent (0.25 = 25%), dollars for flat | | --recurring N | months a commission keeps paying | | --cookie N | attribution window in days | | --min-payout N | minimum balance before a payout | | --auto-approve on\|off | approve signups instantly | | --status NAME | active, paused or archived |

Changes apply to NEW conversions; commissions already earned are untouched.

trackrev partners list

affiliates with their clicks, sales and earnings (paid plan)

trackrev partners list --status pending

| flag | meaning | | --- | --- | | --program ID | one program only | | --status NAME | pending, approved, rejected, banned or archived |

trackrev partners approve <partner-id>

approve a pending affiliate (paid plan)

trackrev partners approve <partner-id> --program <program-id>

| flag | meaning | | --- | --- | | --program ID | the program id (required) |

Does NOT send the approval email the dashboard sends — a re-run would mail them again.

trackrev partners reject <partner-id>

reject an application (paid plan) (asks to confirm; --yes in scripts)

trackrev partners reject <partner-id> --program <program-id> --yes

| flag | meaning | | --- | --- | | --program ID | the program id (required) |

trackrev partners ban <partner-id>

ban an affiliate (paid plan) (asks to confirm; --yes in scripts)

trackrev partners ban <partner-id> --program <program-id> --yes

| flag | meaning | | --- | --- | | --program ID | the program id (required) |

trackrev partners group <partner-id>

move an affiliate into a group, or back to program terms (paid plan)

trackrev partners group <partner-id> --program <program-id> --group <group-id>

| flag | meaning | | --- | --- | | --program ID | the program id (required) | | --group ID | group to move them to; omit to clear |

trackrev groups list <program-id>

a program's tiers, showing the terms each one resolves to (paid plan)

trackrev groups list <program-id>

Money

trackrev commissions list

the commission ledger, newest first (paid plan)

trackrev commissions list --status pending

| flag | meaning | | --- | --- | | --limit N | rows to return (max 500) | | --status NAME | pending, eligible, paid, refunded, void or fraud | | --partner ID | one affiliate only |

level 1 is the affiliate who sold; 2+ is an upline earning from their network.

trackrev commissions add

record an off-platform deal by hand (paid plan)

trackrev commissions add --program <id> --partner <id> --amount 500 --earnings 100

| flag | meaning | | --- | --- | | --program ID | program id (required) | | --partner ID | affiliate id (required) | | --amount N | gross sale value (required) | | --earnings N | the affiliate's cut (required) | | --currency CODE | defaults to usd | | --notes TEXT | why this was entered by hand |

Earnings is not derived — a manual commission exists because the normal rate did not apply. It counts toward your monthly commission cap.

trackrev commissions void <id>

void a commission entered in error (paid plan) (asks to confirm; --yes in scripts)

trackrev commissions void <id> --yes

| flag | meaning | | --- | --- | | --status NAME | set another status instead of void |

Refused if it is already on a payout batch — cancel the payout first.

trackrev payouts list

payout batches, with open and all-time totals (paid plan)

trackrev payouts list --status pending

| flag | meaning | | --- | --- | | --status NAME | pending, processing, paid, failed or canceled | | --limit N | rows to return (max 500) |

Creating a batch stays in the dashboard: it applies per-group payout floors and platform fees, and a second implementation would eventually pay someone wrong.

trackrev payouts mark-paid <id>

settle a payout sent off-platform (paid plan) (asks to confirm; --yes in scripts)

trackrev payouts mark-paid <id> --reference PAYPAL-BATCH-123 --yes

| flag | meaning | | --- | --- | | --reference TEXT | the rail's own id (PayPal batch, Wise transfer) |

Does NOT email the affiliate — the dashboard sends that, and a re-run would send it twice.

Settings

trackrev settings notifications

every transactional email, and whether it is on

trackrev settings notifications

default=yes means no override is stored and the catalogue default applies.

trackrev settings notify <key>

turn one transactional email on or off

trackrev settings notify affiliate.approved --off

| flag | meaning | | --- | --- | | --on | enable it | | --off | disable it |

trackrev settings branding

the white-label settings affiliates see

trackrev settings branding

trackrev settings set-branding

set the partner-facing logo and accent colour

trackrev settings set-branding --color '#e63e2e'

| flag | meaning | | --- | --- | | --logo URL | https logo URL | | --color HEX | hex accent, e.g. #e63e2e | | --clear-logo | back to the TrackRev logo | | --clear-color | back to the TrackRev colour |

The affiliate subdomain is read-only here — claiming one is a namespace reservation and belongs in one place.

Account

trackrev me

which workspace, plan, limits and key you're using

trackrev me

trackrev login

save a secret key so you don't need TRACKREV_KEY

trackrev login --profile staging --api-url https://staging.example.com/api/v1

| flag | meaning | | --- | --- | | --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 logout

forget a saved key

trackrev logout

Global flags

| flag | meaning | | --- | --- | | --json | print the API's JSON instead of a table | | --profile NAME | use a saved login other than the current one | | --yes | skip the confirmation on destructive commands | | --version | print the version | | --help | show help (also: trackrev --help) |

Output

The same data comes out three ways, so a command works both as something you read and as something you pipe:

trackrev channels                    # aligned table (a terminal)
trackrev channels > channels.tsv     # tab-separated, raw values (a pipe or file)
trackrev channels --json | jq .      # the API's own JSON body

Piped output is deliberately unformatted — 2410.5, not 2,410.50, and true rather than yes — so cut and awk see real values:

trackrev channels | cut -f1,5
trackrev links list | column -t
trackrev clicks --all --json | jq '.clicks[] | select(.country == "BD")'

Warnings, errors, confirmations and the journey caption always go to stderr, never into your pipe.

Recipes

# One link per channel for a launch, then print just the shareable URLs
trackrev links create --url https://acme.com/launch --name Launch \
  --channel youtube --channel newsletter --channel twitter | cut -f3

# A link that dies after 1,000 clicks and sends latecomers to the waitlist
trackrev links create --url https://acme.com/beta --name Beta --channel newsletter \
  --max-clicks 1000 --expired-url https://acme.com/waitlist

# Import a quarter's worth of links from a spreadsheet export
trackrev links bulk --file q4-links.csv

# Your five best links by revenue this month
trackrev links perf --limit 100 | tail -n +2 | sort -t$'\t' -k6,6nr | head -5

# Follow the newest click through to that visitor's whole journey
trackrev clicks --limit 1 | tail -1 | cut -f6 | xargs trackrev journey

# Nightly export
trackrev clicks --all --json > "clicks-$(date +%F).json"

Exit codes

| code | meaning | | --- | --- | | 0 | success | | 1 | no API key, auth failure, network error, not found, API error | | 2 | usage error — unknown flag or command, bad value, missing argument, refused confirmation | | 3 | plan required — the workspace needs a paid plan for this command |

Exit 3 is separate so CI can tell "you are on the wrong plan" apart from "the call broke".

Development

node --test test/*.test.js   # the full suite, against a mock API — no network, no credentials
pnpm sync-docs       # regenerate the command tables in this file and the docs site

The test glob is pinned: a bare node --test also runs every other file under test/, and mock-api.mjs is a server that never exits.

Commands are declared once in src/registry.js. The help text, the argument parser, the tables above, the /cli marketing page and the Settings → Developers panel are all derived from it — add a command there and a handler in src/commands/, then run pnpm sync-docs.