Open-source project
ryo-ma/github-profile-trophy avatar
ryo-ma/github-profile-trophy

github-profile-trophy: the README image generator its owner may switch off

🏆 Add dynamically generated GitHub Stat Trophies on your readme

6,671 stars2,224 forksTypeScriptMIT

At a glance

What is it?
A Deno service that renders rank trophies from GitHub activity into SVG images you embed in a README, now running behind a volunteer load balancing list and a funding warning.
Who is it for?
The interesting part of this repository is not the rendering, it is the state of the hosted deployment. A service that other people's profile READMEs depend on has warned its users that it may be discontinued, and responded by listing sixteen volunteer endpoints rather than a mirror policy.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 90 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • ryo-ma/github-profile-trophy6,671 ★ · +7
Star history
Repository2026-10-072026-10-23
ryo-ma/github-profile-trophy6.7k6.7k

7 Stars in the last 16 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The whole integration is one markdown image tag

Adding trophies to a profile README takes one line. You paste this into your profile's README and change the username:

code
[![trophy](https://github-profile-trophy.vercel.app/?username=ryo-ma)](https://github.com/ryo-ma/github-profile-trophy)

There is no SDK, no JavaScript to include and no authentication. The service fetches public GitHub activity for the username you pass, computes a rank per trophy category, and returns an SVG. GitHub then caches that image in your README, so the URL is fetched on a schedule rather than on every page view, which is why a single request per profile is not the traffic problem it might appear to be.

The query string is the entire configuration surface, and the README documents two optional parameters. A theme parameter selects a colour scheme, with onedark given as the example:

code
[![trophy](https://github-profile-trophy.vercel.app/?username=ryo-ma&theme=onedark)](https://github.com/ryo-ma/github-profile-trophy)

A column parameter controls how many trophies sit on a row, and a rank parameter selects which categories appear. The project's own demo image passes eight columns and asks for the ranks SSS, SS, S, AAA, AA, A, B and C. That URL is the fastest documentation in the repository, because it shows every knob at once.

Ranks, and one category deliberately not shown

Every trophy category maps to a rank, and the ranks run SSS, SS, S, AAA, AA, A, B, C, UNKNOWN and SECRET. The README groups them by how they read rather than by how they are computed.

The top three are for hard to reach ranks. AAA through A is described as what you reach if you do your best, and the README suggests aiming there first. B and C mean you are making good progress. UNKNOWN is what you get before you have taken any action at all, and it is the one rank with a visual convention attached: it is denoted by a question mark rather than a letter.

SECRET is the interesting one. Its acquisition condition is stated as secret, and the trophy is not displayed until certain conditions are met. The README shows a placeholder image of what it looks like and then invites contributions, saying that if you come up with interesting conditions, the owner will consider adding a trophy. That is a gamification mechanic with a hidden rule set, and it is also the only part of the project where the logic is deliberately not published.

One consequence worth knowing before you deploy this yourself: the SECRET category is part of the rank vocabulary in the source, so a self-hosted fork inherits the behaviour whether or not you understand it.

A TypeScript project that actually runs on Deno

The repository is labelled TypeScript and the topics list deno as well, and the second label is the accurate one. There is no package.json and no node_modules. The entry point is main.ts, imports are gathered in deps.ts, the task runner configuration is deno.json, and the Dockerfile starts from the official Deno image:

dockerfile
FROM denoland/deno:latest

# Create working directory
WORKDIR /app

# Compile the main app
RUN deno cache main.ts

The rest of the container copies the source and runs deno run with full permissions, which is the usual Deno deployment shape: one runtime, one entry file, permissions granted at launch rather than through a manifest.

The source layout explains what the service does. render_svg.ts is the rendering entry point, src holds the trophy definitions and theme definitions, api holds the request handling for the serverless deployment, test holds the tests, and vercel.json plus a .vercelignore are what make the same code deployable as a Vercel function. The Dockerfile and docker-compose file exist so the same app can be run locally or on your own machine instead.

So there are two deployment stories on purpose. Vercel is what the hosted service uses and what the owner asks forkers to use. Docker is what you use when you want the container on hardware you control.

Redis in the local compose file, and why a cache exists at all

The compose file defines two services, a Redis container and the application itself.

yaml
services:
  redis:
    container_name: trophy-redis
    image: redis:latest
    ports:
      - "6379:6379"

Redis is there because the expensive part of serving a trophy image is not the SVG, it is talking to GitHub. Every uncached request for an unknown or stale username needs a fetch of that user's activity, and GitHub rate limits unauthenticated requests aggressively. A cache turns a repeat request into a lookup, and it also means the GitHub-side quota is spent once per user per refresh interval rather than once per README render.

Two details in that compose file are worth reading before you adapt it. The Redis port is published to the host, which is convenient for local debugging and unnecessary for a deployment you care about. The application command is deno run with the watch flag and DENO_ENV set to development, and the source directory is bind mounted, so the container restarts the process on every file save. Both are developer conveniences and both should come out before this runs anywhere shared.

The owner has published a shutdown warning and a load balancing list

This is the section that makes the project worth reading carefully. Near the top of the README, under a notice from the project owner, the situation is stated plainly: because user and traffic numbers have grown, the cost of maintaining the service is high and financially difficult to sustain, and as costs rise there is a possibility the service may have to be discontinued.

The README then asks for support in three ways. Financial support through GitHub Sponsors. Reducing server load by forking the repository and deploying to Vercel yourself. And sharing the URL of your own Vercel deployment so traffic can be spread across deployments, either by email or by pull request.

That third request is why the README carries a list of sixteen endpoints contributed by volunteers, under a heading about load balancing endpoints, with a request to use them in moderation. Several are personal Vercel deployments on hobby plans, which have usage ceilings. If your README points at one of them, you are depending on someone's account and on their willingness to keep paying.

The honest reading is that this is a service with an unowned failure mode. Nothing in the README commits to a date or a migration path, so the practical response is the one the owner already suggests: get your own deployment and stop depending on the list.

One release, a long gap, and a large fork count

The release history is a single entry. Version 1.0 was published on 2026-01-27 and its notes are a list of merged pull requests rather than a narrative: a theme update, an EditorConfig addition, a GruvBox and Default theme, a Dracula theme, a chalk based theme, a nord theme, an alduin theme, a dark-hub theme, a spelling fix, a typo fix, and a 404 that now includes the requested user id. The theme list in that changelog is the fastest evidence that most of the contribution volume here has gone into colour schemes.

The last push to the default branch, master, was on 2026-07-25. The repository is not archived.

The other number worth reading is forks, which stands at 2,179. For a project whose README explicitly asks people to fork it and deploy their own copy, a fork count in that range is not a sign of disagreement with the project. It is the load balancing strategy working as designed, and it is also a decent proxy for how much of the internet is currently rendering its README images from code someone else copied out of here.

What the repository does not tell you

Several things a self-hoster would want are not in the README. There is no statement of which GitHub token the service uses, whether it is authenticated, or what happens when the rate limit is reached. There is no documented cache duration, so you cannot tell from the documentation how fresh a rank is. There is no note on failure behaviour, which is the specific thing that matters most: an image URL that returns nothing renders as a broken image in someone's README, permanently and publicly.

The repository does have a CONTRIBUTING file, and the secret-rank section is an explicit invitation to propose new trophy conditions, which tells you where the maintainer wants help. The action.yml at the root suggests there is a GitHub Actions entry point as well as the Vercel path, though the README does not describe what that action does.

For a decision, the relevant questions are narrow. If you want the image, embed it and accept that it may break. If you want the image to keep working, fork it, run the Dockerfile or deploy to Vercel, and point your README at your own URL. The difference between those two is one line of markdown, which is the only real argument this project has.

Editorial conclusion

The interesting part of this repository is not the rendering, it is the state of the hosted deployment. A service that other people's profile READMEs depend on has warned its users that it may be discontinued, and responded by listing sixteen volunteer endpoints rather than a mirror policy. That is an unusual and arguably more honest position than silently raising a timeout. Before you embed one of these images, decide whether you are willing to keep it working: the code is small, the container is a single Deno image with a Redis sidecar, and forking to Vercel is the step the owner asks for. If you do nothing, your README keeps an image pointing at someone else's Vercel project until it stops resolving.

Frequently asked questions

How to win GitHub trophies?

Each trophy category is computed from public GitHub activity and mapped to a rank between SSS and C, with UNKNOWN shown as a question mark before you have any activity. There is also a SECRET rank whose conditions are not published and whose trophy only appears once they are met.

Is the hosted GitHub Profile Trophy service going to stay online?

The owner states in the README that running costs have become difficult to sustain and that the service may have to be discontinued. The suggested responses are sponsoring, self-hosting on Vercel, and using the volunteer deployment endpoints the README lists.

How do I add a trophy to my GitHub profile README?

Paste the markdown image tag into your profile README and replace the username in the query string. The README also documents an optional theme parameter, such as theme=onedark, and a column parameter for how many trophies sit per row.

What runtime does github-profile-trophy use?

Deno. The repository has main.ts, deps.ts and deno.json rather than a package.json, and the Dockerfile starts from denoland/deno:latest with deno cache main.ts as its build step.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. ryo-ma/github-profile-trophy on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ryo-ma-github-profile-trophy.svg)](https://hysenlabs.com/projects/ryo-ma-github-profile-trophy)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/ryo-ma-github-profile-trophy.svg)](https://hysenlabs.com/projects/ryo-ma-github-profile-trophy)

Was this useful?