Self-hosted badge server for GitHub Container Registry. Scrapes GHCR package pages and serves shields.io endpoint badges with pull counts, versions, image sizes, and platform info.
- Pull count, version, image size, and architecture badges for any public GHCR package
- Shields.io endpoint badge compatible JSON responses
- Background scraping on a configurable interval (default 6h)
- Supports packages where the repo name differs from the package name
- Zero external dependencies, Go stdlib only
- Distroless container image
- Graceful shutdown (SIGINT/SIGTERM)
- 1-hour client-side cache headers
docker run -d \
--name pkgbadge \
--restart unless-stopped \
-p 8080:8080 \
-e PKGBADGE_PACKAGES="owner/repo,owner/repo/package" \
ghcr.io/will-luck/pkgbadge:latestservices:
pkgbadge:
image: ghcr.io/will-luck/pkgbadge:latest
ports:
- "8080:8080"
environment:
PKGBADGE_PACKAGES: "owner/repo,owner/repo/package"
restart: unless-stoppedThen add badges to your README:

| Badge | Endpoint | Example |
|---|---|---|
| Pull count | /owner/package/pulls.json |
1.5k |
| Version | /owner/package/version.json |
2.11.1 |
| Image size | /owner/package/size.json |
12.4 MB |
| Platforms | /owner/package/arch.json |
amd64 | arm64 |
| Variable | Default | Description |
|---|---|---|
PKGBADGE_PACKAGES |
(required) | Comma-separated packages to scrape |
PKGBADGE_INTERVAL |
6h |
Scrape interval (Go duration format) |
PKGBADGE_PORT |
8080 |
HTTP listen port |
Package format is owner/package when the repo and package names match, or owner/repo/package when they differ (e.g. Will-Luck/Docker-Sentinel/docker-sentinel).
See the wiki for detailed configuration and usage guides.
See the Wiki for:
- Installation options (Docker, Compose, from source)
- Badge types and shields.io usage
- API reference
- Troubleshooting
MIT