How I made my own GitHub Profile View Counter
A brief blog on how I created a GitHub Profile View Counter and deployed it on Vercel.
On this page
Introduction
I used to rely on Anton Komarev's GitHub Profile Views Counter Service. It worked well, but after some time I wanted to own the small pieces of infrastructure that appeared on my profile.
The original service was PHP-based and used a database such as MySQL. I did not want to add that stack to my own server for one badge, so my first instinct was to rebuild the service in Node.js.
After a couple of days, I realized I was solving a bigger problem than I actually had. I did not need a full application. I needed one endpoint that returned an SVG and updated a counter.
That was a perfect fit for a serverless function.
What I Needed
The counter had to do three things:
- Return an SVG badge that GitHub can render inside a README.
- Increment the count when GitHub's image proxy requests it.
- Avoid increasing the count for every random browser refresh or bot request.
The final URL needed to behave like a normal image:

Behind that simple image link, the function reads the current value, updates it when appropriate, and returns a fresh SVG.
The Implementation
I kept the setup small:
- I reused the badge style from Shields.io.
- I stored the count in Upstash.
- I served the badge through a Vercel Edge Function.
- I added request handling around GitHub's image proxy behavior.
- I deployed it as part of a small README utility project.
The main idea is simple: the endpoint is both the image renderer and the counter update point.
Problems I Had to Solve
Cold Starts
A profile badge should feel instant. A slow image looks broken, especially inside a README.
Regular serverless functions can have cold starts after a period of inactivity, so I moved the endpoint to a Vercel Edge Function. That kept responses faster and closer to the request source.
Image Caching
GitHub uses an image proxy and caches remote images aggressively. That is good for performance, but awkward for a live counter.
To keep the badge fresh, I returned it with:
Cache-Control: no-store
That tells intermediaries not to reuse an old badge response.
Abuse and Noise
Counters are easy to inflate if every request increments the value. I added basic filtering and rate limiting so the count reflects profile views more closely instead of refresh spam.
I also used Vercel's firewall controls to reduce abusive traffic while allowing GitHub's image proxy behavior.
Result
The final version is a tiny self-hosted view counter:
Sivothayan's GitHub Profile View Counter
Sample View
It does one job, it stays cheap to run, and I understand every moving part.
Open Source
The project is open source here:
Sivothayan's GitHub README Utils