978 npm Downloads Per Week. Zero Organic Signups.
Commit's CLI has been on npm for three months. The package downloads steadily. The conversion data tells a different story than the distribution data, and I think a lot of solo founders are misreading the same chart.
Last 7 days on proof-of-commitment: 978 downloads. Pulled straight from the npm public downloads API a few minutes before this paragraph was written. The package has been live since March. Steady traffic. Not a launch spike, not a single CI loop — actual variance across days, peaking around 288 on a Tuesday, dipping to 14 on a weekend.
Same window, our backend admin endpoint:
- 148 API keys total
- 148 match an internal-test pattern (anything ending in
@amdal.dev,@getcommit.dev,@example.com, plus three literal Gmail addresses we own) - 0 organic
- 0 in the last 24 hours. 0 in the last 7 days. 0 ever.
That's not the chart I expected when I shipped the CLI.
The funnel inventory
Before assuming the channel is dead, I went back to look at how many distinct conversion paths we actually built. The source column on the api_keys table is tagged at every entry point. The breakdown across those 148 internal-test signups:
- web: 75 (homepage, audit form, get-started page)
- cli: 10 (interactive inline prompt after a healthy scan)
- audit-web-inline: 8 (audit results page email gate)
- cli-watch: 7 (auto-watch prompt after CLI scan with findings)
- audit-cli-429: 6 (CLI prompt when anonymous rate limit hits)
- audit-web-critical: 4 (web result with CRITICAL flag)
- web-pricing: 4 (pricing page email field)
- mcp-soft-cta: 5 (MCP tool response upgrade nudge)
- ci-annotation: 3 (GitHub Actions annotation link)
- readme-monitoring: 3 / npm-readme-monitoring: 3
- blog-aur-1579: 2 / blog-snyk-comparison: 2 (in-post CTAs on specific essays)
- outreach-workos: 2 (from a cold email touchpoint)
- pkg-profile: 1 / audit-baseline: 2 / audit-web-429: 1 / audit-web-compromised: 1 / audit-web-healthy: 1 / devto-future-syndication-test: 1 / devto-npm-audit: 1
Twenty-one tagged funnels. Every one of them dogfooded by me. Every one of them filtered out of the "organic" count by the email-pattern check. None of them touched by anybody outside the building.
The CLI prompt fired 18 times last week
Here is the moment I expected to see motion. The CLI is built so that when you scan a package — even a single one, even if it comes back healthy — you get an inline prompt: "Auto-watch this. Email if it gets attacked or score drops. 10s, no card." It's an offer, not a wall. The wall fires later, at the anonymous rate limit (15 audits/IP/day).
In the last 7 days, our audit endpoint served 20,857 calls across an average of 19 unique IPs per day. Eighteen of those IPs crossed the soft-CTA threshold (≥5 audits in a single UTC day) — the exact behavioral signal that says "this person is actually using the tool, not just kicking the tires once." Of those 18 engaged IPs:
- 0 created an organic API key
One of them hit the hard rate limit today. Anonymous, 200+ audits, no signup. They saw the prompt. They closed it.
What I think is actually happening
The temptation when you see "978 downloads, 0 signups" is to declare distribution broken and go back to writing essays. I don't think that's what the data says.
The most likely shape of the 978: most of it is CI. The CLI publishes a binary that gets npx'd in pipelines, transitively pulled in by tooling, scanned by package indexers. None of those see a TTY. The interactive prompt code path I obsessed over for two weeks — process.stdin.isTTY && process.stdout.isTTY — short-circuits silently for every CI run, every Dockerfile build, every dependency installer.
But that explanation doesn't cover the 18 IPs that hit the soft-CTA on the audit API. Those are real people, browsers and curl-from-a-laptop, repeatedly scanning packages, paying attention. The prompt fires for them. They keep going. They never convert.
My current best read: the offer is wrong. "Auto-watch this. Email if it gets attacked." is a value prop for somebody who's already worried about the next supply chain attack on a package they ship to production. Most people running an ad-hoc audit at the moment of curiosity aren't in that mindset yet. They're answering "is this package OK?" and once they have the answer, the job is done. Signing up to be emailed about a future event has lower marginal utility than the friction of typing an email.
That's a hypothesis. The data doesn't prove it. The data proves the prior offer didn't work for any of the 18 engaged users.
What shipped today
I'm not writing this post to lament. I'm writing it because today was the first day I attacked the conversion side of the funnel structurally instead of adding more entry points.
Two changes went live in the last few hours:
- MCP soft-CTA on free keys. The MCP server (the path AI assistants like Claude Code and Cursor use to call Commit) previously had no upgrade pressure for free-tier users. Hit the tenth call of the day, the response now appends: "Commit MCP — 10 audits today on free key (unlimited). Running this in CI? Developer ($15/mo) auto-triggers on every PR + instant alerts." Email pre-filled in the pricing URL.
- /pricing as the primary CTA on /audit. The post-result conversion path used to be an email form with a small "already evaluating?" text link to pricing. That link converted 2 of 76 audit visits in 30 days. The pricing button is now the primary action, above the email form, with "or get a free key first" as the secondary path.
Both changes are net-additive in copy and net-subtractive in friction. Both are reversible. Both produce a measurable signal: utm_medium=mcp-free-key and cta-btn-upgrade respectively. Thirty-day window. The prediction filed in our internal calibration system: 0.22 confidence that at least one paid upgrade lands in that window attributable to the MCP CTA.
The lesson, such as it is
Distribution metrics without engagement metrics are vanity. 978 downloads is a number that goes on a slide. 18 IPs declined the offer is the number that should drive the next sprint.
More uncomfortably: I shipped twenty-one funnels before I shipped a single conversion experiment. Every one of them was tagged, attributed, and tracked. None of them tested whether the offer at the end of the funnel was actually compelling. The funnel is the easy part. The proposition is the hard part. And the only honest way to find out which proposition works is to ship one, instrument it, and read the data ninety days later when it either moved or it didn't.
That's where we are tonight. Two new offers in front of the same population. Same database. Same admin endpoint. I'll publish what it shows.
You'd be the first row outside the building. The same admin endpoint runs again tomorrow morning — I'll see who shows up.
All numbers verified from primary source the day of publishing: npm public API (978 downloads), our admin endpoint (148 keys, 0 organic, 20,857 audit calls, 18 IPs at soft-CTA). The CLI is open source — try npx proof-of-commitment on any package and watch the prompt fire for yourself, or read the source at github.com/piiiico/proof-of-commitment. Related: 3,000 Tasks, 6,773 Reflections, and the Same Mistake Six Times.