Skip to content
nullcatsHQPublic

About

Turn any public GitHub repo into a real-time, queryable snapshot, stars, forks, commits, issues, PRs and more as JSON or WebSocket

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Repository files navigation

Arove

Turn any public GitHub repo into a live, queryable snapshot

Stars, forks, commits, languages, contributors, releases, branches, tags, issues and pull requests, all as plain JSON. There's a WebSocket on the same address too, in case you'd rather have updates pushed to you instead of asking for them.

license typescript hono cost stars issues last commit prs discord

Try it • Endpoints • Self host • Rate limits • Contributing • Discord

For whatever you build, from nullCats™

The API is already running

You can start using Arove right now, this second, without installing anything.

https://api.arove.workers.dev

That's really the whole setup for most people. Drop in any public GitHub owner and repo name and you get data back. Keep reading to see it in action, or jump straight to self hosting if you'd rather run your own copy with your own rate limits.


Try it right now

curl https://api.arove.workers.dev/v1/repo/vercel/next.js
{
  "repo": {
    "owner": "vercel",
    "name": "next.js",
    "fullName": "vercel/next.js",
    "ownerAvatarUrl": "https://avatars.githubusercontent.com/u/14985020?v=4",
    "ownerType": "Organization"
  },
  "stats": {
    "stars": 132000,
    "forks": 27200,
    "openIssues": 2481,
    "defaultBranch": "canary",
    "license": "MIT",
    "description": "The React Framework"
  },
  "languages": {
    "TypeScript": { "bytes": 9431201, "percentage": 91.2 },
    "JavaScript": { "bytes": 612044, "percentage": 5.9 }
  },
  "latestCommits": [
    {
      "shortSha": "c3bdfff",
      "message": "fix: patch update for edge runtime",
      "authorLogin": "someone",
      "committedAt": "2026-09-04T09:52:24Z",
      "additions": 101,
      "deletions": 111,
      "filesChanged": 12,
      "branches": ["main"]
    }
  ],
  "topContributors": [
    {
      "login": "someone",
      "contributions": 128,
      "lastCommitMessage": "fix: patch update for edge runtime"
    }
  ],
  "health": {
    "hasReadme": true,
    "hasLicense": true,
    "daysSinceLastCommit": 0
  }
}

That's trimmed down for readability, and the numbers are just illustrative rather than something pulled live for this page. The actual response includes full contributor lists, release info, and everything else described below. You don't need to register a repo before asking about it either, an unregistered one just gets fetched fresh on the spot instead of pulled from stored history.

Want updates pushed to you instead of asking again and again? Open that same address as a WebSocket instead of a plain request and you'll get events as they happen.

Tip

Join our Discord server for updates on the project, help with setup, and support from the community and the nullCats™ team.


What you get

Endpoint What it does
GET /v1/repo/:owner/:name Full snapshot, works whether or not the repo is registered
WS /v1/repo/:owner/:name Live updates on that exact same address
GET /v1/repo/:owner/:name/commits Commit history
GET /v1/repo/:owner/:name/branches Branch list
GET /v1/repo/:owner/:name/tags Tag list
GET /v1/repo/:owner/:name/issues Issue list
GET /v1/repo/:owner/:name/pulls Pull request list
GET /v1/repo/:owner/:name/languages Language breakdown
GET /v1/repo/:owner/:name/contributors Top contributors
GET /v1/repo/:owner/:name/releases Release history
GET /v1/repo/:owner/:name/badge An embeddable stat badge for your own README
POST /v1/repo/:owner/:name/register Start tracking history and enable webhooks
GET /v1/repos?repos=a/b,c/d Batch lookup, up to 20 repos in one call
POST /v1/keys Free, self serve API key for a higher rate limit
GET /v1/keys/usage Check a key's own creation date, last use, and request count
GET /v1/health Status of D1, Postgres and your GitHub tokens, with response times
GET /v1/openapi.json Full OpenAPI spec

Every one of these already works against api.arove.workers.dev, no setup needed on your end.

Drop a badge in your own README

Since Arove exposes a badge endpoint, you can embed a live stat straight into your own project's README without touching an image editor.

![stars](https://api.arove.workers.dev/v1/repo/vercel/next.js/badge?label=stars&color=3fb950)

Swap the owner and repo, pick a label of stars, forks, or issues, and pick whatever color fits your README. It updates on its own every time someone loads the page.

This one's kept deliberately light on purpose, it only ever asks GitHub for the single number it needs, not the full snapshot, so it stays fast even embedded somewhere that gets loaded a lot.


Why it exists

Most GitHub stat widgets lock you into one look and one host. Arove hands you raw data instead of a rendered widget, so your portfolio, dashboard, or README badge can end up looking like whatever you actually want it to look like. It borrows the "one URL, no config" feel of Lanyard, the Discord presence API, and points that same idea at GitHub instead.


Want to self host it instead?

You genuinely don't have to. The public instance is free, it isn't going anywhere, and most people building a dashboard or a portfolio widget can just point at api.arove.workers.dev and never think about this section again.

But maybe you want your own rate limits, your own registered repos, or you just like owning the whole stack. Fair enough, here's how.

git clone https://github.com/nullcatsHQ/arove.git
cd arove
npm install

Then, in order:

1. Database. Create a D1 database through your Cloudflare dashboard, then run src/db/schema.sql against it through the query console. That's everything a fresh database needs. If you're upgrading a copy that was already running before webhooks and API keys existed, also run src/db/upgrade.sql once, it adds the couple of pieces that were missing.

2. Postgres. Arove keeps its rate limit counters, its response cache, and a few coordination flags in a Postgres database. Neon's free plan is plenty for this. Here's the whole setup:

  1. Go to neon.tech, sign up, and open the console.
  2. Create a new project. Call it whatever you like, pick the region closest to where your Worker mostly runs, and leave the Postgres version on the default.
  3. Open the project and press Connect. Switch connection pooling on, then copy the connection string. The hostname should contain -pooler and the string should end in sslmode=require.
  4. Open the SQL Editor from the sidebar, paste in everything from src/db/postgres.sql, and run it. That creates two tables, counters and cache. Running the file a second time drops and rebuilds both, which only resets rate limits and cached data, nothing you'd miss.

3. Config. Open wrangler.toml and drop your D1 database ID into the binding block near the top.

4. Secrets. Add your Postgres connection string as a secret named DATABASE_URL. From the terminal:

npx wrangler secret put DATABASE_URL

Or in the dashboard, open your Worker, go to Settings, then Variables and Secrets, add a new one, set the type to Secret, name it DATABASE_URL, and paste the string in. For local development, copy .dev.vars.example to .dev.vars and fill it in there.

5. GitHub token. Generate a personal access token, no scopes needed for public repo data, and add it as a secret named GITHUB_TOKEN. Want a higher rate limit? Add more as GITHUB_TOKEN_2, GITHUB_TOKEN_3, and so on, then set TOKEN_COUNT in wrangler.toml to match. One token is fine too, this is optional.

6. Scheduled job. A polling schedule is already defined in wrangler.toml under triggers, running once a minute. Confirm it shows up in your dashboard after deploying.

7. Deploy. Use npx wrangler deploy, or connect the repository for continuous deployment through the dashboard.

Once it's live, confirm everything's working:

curl https://your-deployment.example/v1/health
curl https://your-deployment.example/v1/repo/vercel/next.js
curl -X POST https://your-deployment.example/v1/repo/vercel/next.js/register

The health check should report everything healthy, the snapshot should come back immediately, and registering should hand you back a webhook URL and secret.

Note

Neon's free plan includes 100 compute hours per project each month, and the compute only goes to sleep after five minutes without a query. Arove talks to it constantly, so it will rarely sleep, and on a busy instance the allowance can run out before the month does. That's roughly 400 hours at the smallest compute size, so a little over two weeks of nonstop use. If it happens, Arove keeps answering. Rate limits and cache lookups get skipped and requests go straight to GitHub until your allowance resets or you move to a paid plan.

Caution

Whatever webhook secret or API key you get back from any endpoint is shown exactly once and cannot be retrieved again. Save it the moment you see it. If you lose one, the fix is regenerating a new one, not recovering the old one.


Instant updates through a webhook

Registering a repo gets you scheduled polling by default, so updates land within a minute or two. If you'd rather a specific repo update the moment something actually happens, grab the webhook URL and secret from the register response, or from POST /v1/repo/:owner/:name/webhook if you registered earlier and lost it, then add it under that repo's webhook settings on GitHub. Works the same whether you're on the public instance or your own.

Using more than one GitHub token

If you're self hosting, Arove can round robin across several GitHub tokens so your effective rate limit budget multiplies with however many you're running. Set a token count in your config, add that many tokens as secrets, and Arove handles the rest, including skipping any token that's currently rate limited until it resets on its own.

Tip

One token is enough for casual use. This only really matters if you're registering a lot of repos or expecting heavy traffic.

Bring your own database

Every database call goes through src/db, and every cache and counter call goes through src/cache and src/state. Those last two reach Postgres through one small file, src/lib/postgres.ts. Nothing else touches storage directly. Want a different database, or Redis for the counters? See STORAGE.md for the full function list to reimplement, plus a couple of worked examples showing the actual shape of the swap.


Working on it locally

The repo pins Node 22 in .nvmrc, so if you use nvm, nvm use gets you the right version.

nvm use
npm install
cp .dev.vars.example .dev.vars
npm run dev

Fill in .dev.vars with your Postgres connection string and a GitHub token first. .env.example has the same values if your tooling prefers an .env file instead.

Command What it does
npm run typecheck TypeScript check with no output files
npm run lint ESLint over the whole project
npm run lint:fix Same, and fixes whatever it safely can
npm run format Prettier rewrites files to the house style
npm run format:check Prettier only reports, changes nothing

Formatting rules live in .prettierrc.json and .editorconfig, so most editors pick them up on their own. GitHub runs the type check on every push and pull request, see .github/workflows/ci.yml.


A word on rate limits

Anonymous requests get a modest rate limit per address. If you're building something that calls Arove a lot, get a free key instead.

curl -X POST https://api.arove.workers.dev/v1/keys

That hands you back a key on the spot, no email, no waiting. Use it as a bearer token and your limit goes up substantially. The exact numbers aren't published here on purpose, check the X-RateLimit-Remaining header on any response if you want to know exactly where you stand.

Want to check how much a key's actually been used, or when it was made? Same bearer token, different endpoint.

curl -H "Authorization: Bearer your-key-here" https://api.arove.workers.dev/v1/keys/usage

No accounts anywhere in this system, so this is also the only way to look a key up at all. There's no dashboard sitting behind it, just the token in your hand.

One thing worth actually knowing, a key that sits completely unused for 180 days quietly stops working on its own. Nothing personal, it's just a cleanup pass for keys that got forgotten somewhere, not a punishment for anything. If you're checking usage every so often anyway, you'll never come close to hitting it.


Project layout

src/
  index.ts        entry point
  routes/          HTTP and WebSocket handlers
  jobs/             scheduled polling logic
  github/            GitHub API client, token pool, data normalization
  db/                 D1 queries and the SQL schemas
  cache/               response cache on top of Postgres
  state/                rate limits, counters and cooldowns on Postgres
  lib/                   Postgres client and small helpers
  middleware/           rate limiting and optional API key auth
  types/                 shared types

The dotfiles in the root (.editorconfig, .prettierrc.json, eslint.config.js, .nvmrc, .gitattributes) keep every contributor on the same formatting and Node version.

Developer's Note

We spent literally $0 building this project. It runs on nothing but free tiers, and that includes the public instance you can already query above. This is a lesson for anyone who thinks they can't build something good without spending money. Everything is possible if you're willing to put in the work. At the end of the day, this has been a fun and rewarding experience for me (trmin) building this project <3


Contributing

Pull requests are genuinely welcome. Open an issue first if you're planning something bigger than a small fix, just so nobody's work crosses paths with anyone else's. If you just want to ask a question or talk through an idea before writing any code, the Discord server is a faster way to reach us than an issue.

License

MIT, see LICENSE for the full text.


This entire project was built by a single developer (Trmin) at nullCats™. Made with 🖤 for cats

Copyright, all rights reserved, nullCats™

About

Turn any public GitHub repo into a real-time, queryable snapshot, stars, forks, commits, issues, PRs and more as JSON or WebSocket

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages