github-stats — Custom SVG GitHub Widgets on Cloudflare Workers

· 3 min read

I built a self-hosted Cloudflare Worker that generates dynamic SVG widgets from the GitHub API — with a full theming system, dark/light mode, KV caching, and transparent backgrounds for embedding anywhere.

I built a self-hosted Cloudflare Worker that generates dynamic SVG widgets from the GitHub API — with a full theming system, dark/light mode, KV caching, and transparent backgrounds for embedding anywhere.

The problem

Every developer’s GitHub profile tells a story — commits, streaks, top languages, contribution heatmaps. But existing widget services come with limitations: fixed themes that clash with your design, no control over caching, rate-limit issues, and no way to match your portfolio’s color palette.

I wanted widgets that:

  • match the dark blue palette of spoko.space exactly
  • switch between dark and light theme automatically via prefers-color-scheme
  • work without a background so they embed seamlessly into any page
  • are cached at the edge so they’re fast and don’t hammer the GitHub API

So I built one.

The result

GitHub Profile StatsMost Used LanguagesContribution Calendar

These are live widgets — rendered in real time from my GitHub data, cached at Cloudflare’s edge, and switching theme automatically based on your system preference.

Architecture

The service runs as a Cloudflare Pages project — a serverless function deployed at the edge, close to the visitor. The stack is intentionally minimal:

  • TypeScript — type-safe rendering pipeline with no rendering framework
  • Cloudflare KV — edge key-value store caches API responses for 24 hours, so the GitHub API is hit at most once per day per data type
  • GitHub GraphQL API — a single query fetches contributions, streak data, and repository stats
  • Pure SVG generation — no canvas, no headless browser, no image libraries; just string templates producing valid SVG

SVG was a deliberate choice: it’s pixel-perfect on any display (retina included), compresses to a few kilobytes, and lets you change colors purely through URL parameters — no server-side image processing needed.

The project handles nine endpoints (/langs, /stats, /streak, /contrib, /repos, /trophies, /stack, /profile, /icon) and returns image/svg+xml responses with proper Cache-Control headers.

Theming system

Every endpoint accepts URL query params to override colors:

/langs?theme=light
/langs?bg=0d1117&primary=58a6ff&text=c9d1d9&radius=6
/profile?bg=transparent&border=transparent

Ten built-in themes ship out of the box: dark, light, tokyonight, dracula, github-dark, nord, radical, synthwave, catppuccin, gruvbox, aura, discord. The transparent background support — added specifically for portfolio embeds — lets widgets blend into any page regardless of its background color.

For GitHub README embeds, the <picture> element handles dark/light switching automatically:

<picture>
  <source media="(prefers-color-scheme: light)"
    srcset="https://github.spoko.space/langs?theme=light">
  <img src="https://github.spoko.space/langs" alt="Languages">
</picture>

Tech stack icons via simple-icons

The /stack widget pulls icon paths and brand colors directly from the simple-icons npm package — no manual SVG copying, no stale colors. With Cloudflare’s esbuild bundler and tree-shaking, only the imported icons end up in the bundle.

Tech Stack

Fork & deploy

The project is open source under MIT. Deploying your own instance takes about five minutes:

git clone https://github.com/spokospace/github-stats
cd github-stats
npm install
npx wrangler secret put GITHUB_TOKEN
npx wrangler secret put CACHE_BUST_TOKEN
npx wrangler pages deploy .

Update the OWNERS array in src/index.ts with your GitHub username(s) and you’re done. Full docs at github.spoko.space.

Back to blog

Related posts

Read more