Skip to content

endgegnerbert-tech/pinglet

Repository files navigation

pinglet

Anonymous runtime analytics for npm packages.
Real usage β€” not download noise.

version tests deps license

Watch Video


🎯 The problem

npm download counts are useless for understanding if anyone actually uses your package.

They count CI installs. Mirror caches. Bots. npm install in pipelines that never execute your code. A package with 100k weekly downloads might have zero real users.

pinglet tells you the truth: who's running your package, how often, and which parts.

npm downloads pinglet
Someone actually ran my code? ❌ βœ…
How many active anonymous users? ❌ βœ…
Which commands/features? ❌ βœ…
Which versions still active? ❌ βœ…
CI or real person? ❌ βœ…
macOS, Linux, Windows? ❌ βœ…

⚑ Quick Start (3 steps)

1. Deploy your server

Railway (easiest): push this repo β†’ create project β†’ add volume β†’ done.
Full guide: docs/deploy-railway.md.

Docker: docker build -t pinglet . && docker run -p 3456:3456 -e PINGLET_ADMIN_PASSWORD=... pinglet

Self-host: npx -p @black-knight.dev/pinglet pinglet-server

2. Login once

# Install the CLI (globally or via npx)
npm install -g @black-knight.dev/pinglet
# or: npx -p @black-knight.dev/pinglet pinglet login ...

pinglet login --url https://your-server.example.com --user admin

Stores a 30-day token β€” not your password.

3. Add 5 lines to your package

npm install @black-knight.dev/pinglet
import { Pinglet } from '@black-knight.dev/pinglet';

const analytics = new Pinglet({
  packageName: 'my-package',
  packageVersion: '1.0.0',
  endpoint: 'https://your-server.example.com/ping',
});

await analytics.track('run');
await analytics.track('command:build');

That's it. Your package now sends anonymous runtime pings.


πŸ“Š What you see

pinglet                        # quick overview
pinglet my-package             # detailed stats
{
  "pkg": "my-package",
  "totalPings": 1420,
  "uniqueUsers": 312,
  "events":      { "run": 980, "command:build": 310 },
  "versions":    { "1.4.0": 900, "1.3.0": 520 },
  "platforms":   { "darwin": 800, "linux": 500, "win32": 120 },
  "ci":          { "true": 40, "false": 1380 },
  "days":        { "2026-06-03": 1420 }
}

CLI cheat sheet

# Install: npm install -g @black-knight.dev/pinglet
# Or via npx: npx -p @black-knight.dev/pinglet pinglet <command>

pinglet                         # status overview
pinglet <pkg>                   # stats for package
pinglet ls                      # list all tracked packages
pinglet show <pkg>              # same as pinglet <pkg>
pinglet snippet <pkg>           # print copy-paste SDK code
pinglet health                  # server health check
pinglet login --url <url>       # login once
pinglet logout                  # remove local login

πŸ›‘οΈ Privacy

Collected Not collected
Random hashed client id Hardware id, hostname, username
Event name File paths, source code, logs
Package name + version Environment variables, secrets
Node.js version User-generated content
Platform (darwin/linux/win32) IP address
CI flag Client timezone

Full privacy model: docs/security.md.

Telemetry model

pinglet uses the industry-standard opt-out model (like Next.js, VS Code, Homebrew):

  • Tracking is ON by default at level 1 (basic: all event names, no properties)
  • No prompts during npm install β€” no postinstall script
  • Documented in every README β€” open source transparency
  • Inspect before sending: PINGLET_DEBUG=1 shows the JSON payload without transmitting
  • Opt out anytime: PINGLET_OPT_OUT=1, DO_NOT_TRACK=1, --no-telemetry

For more detail: docs/telemetry.md.


🌐 Server endpoints

Method Path Auth Description
POST /ping public Receive a runtime event
POST /auth/login Basic Auth Create 30-day admin token
GET /auth/check Bearer token Verify saved login
GET /packages admin List tracked packages
GET /stats?pkg=<name> admin Aggregated analytics
GET /health public Health check

πŸ“¦ Deployment

Platform Guide
Railway docs/deploy-railway.md β€” step by step
Docker docker build -t pinglet . β€” single command
Fly.io fly launch --dockerfile Dockerfile
Self-host npx -p @black-knight.dev/pinglet pinglet-server
Overview docs/deployment.md β€” all options

All deployments need one env var: PINGLET_ADMIN_PASSWORD.


πŸ”Œ API

new Pinglet(options)

Option Required Description
packageName βœ… Your package name
packageVersion βœ… Current version
endpoint βœ… URL receiving POST /ping
salt β€” Stable salt for anonymous client id
silent β€” Suppress console output
timeoutMs β€” Network timeout (default 1500ms)
ingestToken β€” Write token for private endpoints
meta β€” Non-PII properties on every event

Methods

await analytics.init()         // prepare client
await analytics.track('event') // send event β€” never throws
analytics.optOut()             // persist disable
analytics.optIn()              // re-enable
analytics.isOptedOut           // current state

πŸ“„ Documentation

Doc Topic
deployment.md Deploy (Railway, Docker, Fly)
deploy-railway.md Railway guide
security.md Privacy, GDPR, hardening
maintainer-guide.md Add pinglet to your package
agent-quickstart.md For AI agents
market-research.md Why pinglet
examples/basic-cli.mjs Working example

βœ… Best practices

  • Add a visible Telemetry section to your README
  • Events go low-cardinality: command:build, not raw input
  • Never track: paths, source code, logs, stack traces, secrets
  • Support DO_NOT_TRACK=1 + PINGLET_OPT_OUT + --no-telemetry
  • Offer PINGLET_DEBUG=1 so users can inspect the payload before trusting
  • Telemetry failures are always silent and non-blocking

πŸ“ License

MIT

About

Anonymous runtime usage analytics for Npm packages

Topics

Resources

License

Security policy

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors