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

gitpulse-tracker

v1.3.0

Published

Lightweight webhook handler for GitPulse — track real developer contribution quality across any Git project

Readme

gitpulse-tracker

Lightweight webhook bridge for GitPulse — tracks real developer contribution quality across any Git project.

npm version License: MIT Node.js >= 18


Setup in 3 steps — no code to write

Step 1 — Install

npm install gitpulse-tracker

Step 2 — Run the init command

npx gitpulse-tracker init

This auto-detects your framework (Laravel, Next.js App Router, Pages Router, Express, Fastify) and creates the webhook route file for you automatically. You write zero code.

Step 3 — Fill in your .env file

GITPULSE_API_KEY=your_api_key_here
GITPULSE_PROJECT_ID=your_project_id_here
GITPULSE_WEBHOOK_SECRET=choose_any_random_secret
GITPULSE_SERVER_URL=https://app.gitpulse.com

Get the API key and project ID from your GitPulse dashboard → Settings → API. The webhook secret is any string you choose — you'll paste the same value into GitHub/GitLab below.

Never commit your .env file. Add it to .gitignore.

Step 4 — Point GitHub / GitLab at your app

The init command prints your exact webhook URL. Use it here:

GitHub: repo → Settings → Webhooks → Add webhook

  • Payload URL: https://yourapp.com/api/gitpulse
  • Content type: application/json
  • Secret: same value as GITPULSE_WEBHOOK_SECRET
  • Events: Send me everything (or at minimum: Push, Pull requests, Pull request reviews)

GitLab: project → Settings → Webhooks → Add new webhook

  • URL: https://yourapp.com/api/gitpulse
  • Secret token: same value as GITPULSE_WEBHOOK_SECRET
  • Trigger: Push events, Merge request events, Comments

That's it. GitPulse starts tracking contributions on the next push.


What init creates

| Framework detected | Files created | Webhook path | | -------------------- | -------------------------------------------------------------------------------------------------------- | ----------------------- | | Laravel | config/gitpulse.php + app/Http/Controllers/GitPulseWebhookController.php + route in routes/api.php | /api/gitpulse/webhook | | Next.js App Router | app/api/gitpulse/route.js | /api/gitpulse | | Next.js Pages Router | pages/api/gitpulse-webhook.js | /api/gitpulse-webhook | | Express | gitpulse-webhook.js (router) | /webhooks/gitpulse | | Fastify | gitpulse-webhook.js (plugin) | /webhooks/gitpulse |

Detection is automatic — it looks for artisan (Laravel), next in package.json (Next.js), etc. Just run the command from your project root.

For Express and Fastify, init also prints the one-line import to add to your app.js.

If you have a .env.example file, the GitPulse env vars are automatically appended to it.


How it works under the hood

Every time a developer pushes or opens a PR, GitHub/GitLab fires a webhook to your app. The route created by init:

  1. Verifies the webhook signature (HMAC-SHA256) — only legitimate payloads pass
  2. Parses the raw payload into a normalized event
  3. Forwards it to your GitPulse server where it gets scored and stored

No database. No config files. Zero runtime dependencies.


Configuration options (advanced)

All options come from environment variables. If you need to override in code:

import { createGitPulseHandler } from "gitpulse-tracker";

export const POST = createGitPulseHandler({
  apiKey: process.env.GITPULSE_API_KEY, // required
  projectId: process.env.GITPULSE_PROJECT_ID, // required
  serverUrl: process.env.GITPULSE_SERVER_URL, // required — no trailing slash
  webhookSecret: process.env.GITPULSE_WEBHOOK_SECRET, // strongly recommended
  provider: "github", // optional — auto-detected from request headers
  timeout: 10000, // optional — outbound request timeout in ms (default: 10000)
});

Low-level API

For fully custom setups, the underlying primitives are exported.

Send events manually

import { GitPulseClient } from "gitpulse-tracker";

const client = new GitPulseClient({
  apiKey: process.env.GITPULSE_API_KEY,
  projectId: process.env.GITPULSE_PROJECT_ID,
  serverUrl: process.env.GITPULSE_SERVER_URL,
});

await client.sendEvent(events, rawPayload);

Parse payloads

import { parseGitHubEvent, parseGitLabEvent } from "gitpulse-tracker";

// Returns array of events, or null if the event type is not tracked
const events = parseGitHubEvent(req.headers["x-github-event"], payload);
const events = parseGitLabEvent(req.headers["x-gitlab-event"], payload);

Verify signatures

import { verifyGitHubSignature, verifyGitLabToken } from "gitpulse-tracker";

// Both throw { statusCode: 401 } if verification fails
verifyGitHubSignature(
  rawBodyString,
  webhookSecret,
  req.headers["x-hub-signature-256"],
);
verifyGitLabToken(webhookSecret, req.headers["x-gitlab-token"]);

Supported events

| Provider | Event | Tracked as | | -------- | ---------------------------------------------- | -------------- | | GitHub | push | push | | GitHub | pull_request opened / reopened / synchronize | pull_request | | GitHub | pull_request closed + merged | merge | | GitHub | pull_request_review submitted | review | | GitHub | issue_comment on a PR | comment | | GitLab | Push Hook | push | | GitLab | Tag Push Hook | push | | GitLab | Merge Request Hook open / reopen / update | pull_request | | GitLab | Merge Request Hook merge | merge | | GitLab | Note Hook on a merge request | review | | GitLab | Note Hook on an issue | comment |

All other event types are silently ignored — your endpoint returns { ok: true, skipped: true }.


Troubleshooting

init says "could not detect framework"

  • Run the command from the root of your project (where package.json or artisan lives).
  • For Laravel, make sure both artisan and app/Http exist in the root — standard for any Laravel project.

Laravel: webhook returns 419 (CSRF token mismatch)

  • The webhook URL must be excluded from CSRF protection. The init command prints the exact snippet to add. In Laravel 11+ add it to bootstrap/app.php:
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->validateCsrfTokens(except: ['api/gitpulse/webhook']);
    })
    In older Laravel, add 'api/gitpulse/webhook' to the $except array in app/Http/Middleware/VerifyCsrfToken.php.

Signature verification fails (401)

  • Next.js Pages Router: the generated file includes export const config = { api: { bodyParser: false } } — do not remove it.
  • Express: make sure express.json() is not applied before the webhook route (the generated file includes a comment about this).
  • Check that GITPULSE_WEBHOOK_SECRET in .env matches the secret entered in GitHub/GitLab exactly.

Events are skipped

  • GitHub: enable "Pull requests" and "Pull request reviews" in your webhook settings — push-only misses PRs.
  • GitLab: enable "Merge request events" and "Comments" in addition to push events.

GitPulseError: HTTP 429

  • Your project hit its monthly event limit. Upgrade your plan in the GitPulse dashboard.

Security

  • Signatures are verified with HMAC-SHA256 using crypto.timingSafeEqual to prevent timing attacks.
  • GITPULSE_WEBHOOK_SECRET is never forwarded to the GitPulse server or written to logs.
  • Always use HTTPS for both your app webhook URL and GITPULSE_SERVER_URL.

License

MIT