My GitHub profile stats card kept showing up as a broken image. If you use one of the popular public stats card services, you have probably seen it too: the little sad file icon where your beautiful stats used to be.
The reason is simple and structural. Those services run as one shared public instance, every profile README on the planet hits the same deployment, and the GitHub API rate limit (plus the hosting bill) belongs to one maintainer. When traffic spikes, the deployment gets paused and everyone's README breaks at once. It is nobody's fault; it is just a shared-resource problem.
So I built gitglance, a stats card service designed from day one to be self-hosted in one click. Your instance, your GitHub token, your 5,000 requests per hour. Nobody else's traffic can break your README.
What it does
gitglance renders SVG cards for your README straight from a URL:
- 8 card types: overview stats, top languages, a combined card, a donut chart, circular gauges, a bar chart, a repository pin and a commit activity chart
- 16 visual styles: vercel, terminal, glass, neon, aurora, mesh, waves, mono and more
- 21 color themes: tokyonight, dracula, catppuccin, nord, gruvbox, cyberpunk...
- A visual card builder: open your instance root, pick options in dropdowns, copy the markdown
You can try every combination on the live builder: gitglance-eight.vercel.app
Three things I learned building SVG cards
1. SVG transform-origin does not mean what you think. My language bars had a grow animation using transform: scaleX(0) to scaleX(1) with transform-origin: left center. Looked right in my head. In the rendered card, the bars slid across the whole image from the left edge instead of filling in place. In SVG, transform-origin resolves against the viewBox by default, not the element. The fix is one line: transform-box: fill-box. My first tester caught it within minutes of the card going live on a real profile.
2. Animations must degrade gracefully. GitHub renders READMEs through an image proxy, and you cannot assume CSS animations will run everywhere. The safe pattern: every keyframe defines only the "from" state, so the resting state of every element is the final, fully visible card. Where animations run you get bars growing and aurora backgrounds drifting; where they do not, you still get a complete card. Never animate from opacity: 0 on content you care about.
3. You do not need a headless browser. A lot of card generators render HTML with Puppeteer and screenshot it. gitglance builds the SVG as a string in plain Node (Express, no other runtime deps). It is fast, cheap to host on a serverless function, and the output stays crisp at any size because it is a real vector.
Why self-hosting matters here
The GitHub REST API gives you 60 requests per hour unauthenticated, per IP. On a shared serverless platform, your function's egress IP is shared with strangers, so an unauthenticated public instance is dead on arrival at any scale. With your own deployed instance plus a GITHUB_TOKEN environment variable (a classic token with just public_repo), you get 5,000 requests per hour all to yourself, and the six-hour CDN cache means a typical profile burns a handful of those per day.
Deploying is: import the repo on Vercel, add the token, done. The repo is MIT licensed and small enough to read in one sitting, which also makes it a decent codebase to study if you want to see how URL-parameterized SVG generation works.
If you try it and something looks off, open an issue. And if it saves your README from the sad broken-image icon, a star on the repo genuinely helps other people find it.
Top comments (0)