A FastAPI-driven API and interactive dashboard for in-depth analysis of GitHub user statistics. This tool goes beyond simple data retrieval, offering a rich, interactive experience for exploring user data, including an innovative "GitHub Profile Stalker" for a comprehensive look at any user's profile.
Live at: github-stats.tashif.codes
- Interactive GitHub Profile Stalker: A user-friendly dashboard to search for any GitHub user and get a complete overview of their stats.
- Comprehensive Statistics: Fetch detailed data including programming language usage, contribution history, commit streaks, and total stars.
- Data Visualizations: Includes a beautiful line chart for contribution history and a breakdown of language usage.
- Profile Views Tracking: A simple endpoint to track and display profile views, similar to the popular GitHub Profile Views Counter.
- Detailed Repository Information: Get information on all of a user's public repositories, including READMEs, commit counts, and more.
- RESTful API: A well-documented API with interactive documentation (Swagger UI & ReDoc) for easy integration.
The heart of this project is the interactive dashboard, which you can access at the root URL (/). It includes the following features:
- GitHub Profile Stalker: Simply enter a GitHub username to get a full breakdown of their profile.
- Profile Overview: Key metrics like total commits, longest streak, current streak, and total stars at a glance.
- Top Languages: A chart showing the user's most used programming languages.
- Contribution Chart: A line chart showing contribution activity over the last year.
- Repository Details: See top repositories, recent commits, and a list of all repositories.
GET /{username}/stats
Fetches comprehensive statistics for a user, including language stats, contribution history, and profile views.
exclude(query, optional): Comma-separated list of languages to exclude (preferred).excluded(query, optional, legacy): Repeatable query param for backwards compatibility, e.g.?excluded=HTML&excluded=CSS.
Example Response:
{
"status": "success",
"message": "retrieved",
"topLanguages": [{"name": "Python", "percentage": 45.0}],
"totalCommits": 2068,
"longestStreak": 25,
"currentStreak": 10,
"profile_visitors": 1234,
"contributions": { ... }
}GET /{username}/languages
exclude(query, optional): Comma-separated list of languages to exclude (preferred).excluded(query, optional, legacy): Repeatable query param for backwards compatibility.attributed(query, optional, defaulttrue): Count only lines the user wrote. See Own-commit attribution.include_forks(query, optional, defaulttrue): Include forks, counting only the user's commits in them.
GET /{username}/contributions/breakdown
Per-repository view of what the user personally wrote: commits, additions,
deletions, files touched, language mix, and their share of each repo's total
additions. Also reports coverage and partial (see below).
exclude/excluded(query, optional): Languages to omit.include_forks(query, optional, defaulttrue).
GET /{username}/contributions
starting_year(query, optional): Starting year for the contribution history.
GET /{username}/repos
Returns repository-level data including:
- Decoded README content as Markdown (
readme). ConventionalREADME.mdfiles come from GitHub's raw CDN; the rate-limited Contents API is used only as a fallback for alternate README names and casing. - GitHub topics / tags (
topics) - Latest releases (
releases) - Release notes/body in Markdown (
releases[].body) - Release asset download links (
releases[].assets[].download_url)
Example:
[
{
"title": "RepoName",
"languages": ["Python", "JavaScript"],
"topics": ["fastapi", "api", "dashboard"],
"readme": "# RepoName\n\nProject documentation in markdown.",
"releases": [
{
"tag_name": "v1.2.0",
"body": "## Changelog\n\n- Added release support",
"url": "https://github.com/user/RepoName/releases/tag/v1.2.0",
"assets": [
{
"name": "RepoName-v1.2.0.zip",
"download_url": "https://github.com/user/RepoName/releases/download/v1.2.0/RepoName-v1.2.0.zip"
}
]
}
]
}
]GET /{username}/stars
GET /{username}/star-lists
Optional: ?include_repos=true to also include the repositories inside each curated list.
Example:
[
{
"name": "AI Projects",
"url": "https://github.com/stars/username/lists/ai-projects",
"repositories": ["pytorch/pytorch", "huggingface/transformers"]
}
]GET /{username}/commits
GET /{username}/profile-views
increment(query, optional):trueorfalsebase(query, optional): A number to set as the base count.
Language percentages and the per-repo user_* fields describe only the commits
the requested user authored. A fork counts the patches they wrote rather than
the upstream codebase, and in their own repos other contributors' commits are
ignored. Vendored paths (node_modules, dist, lockfiles, generated and
minified files) are skipped so they cannot dominate the split.
This is measured by walking commit diffs, which costs hundreds of GitHub API calls and takes minutes for a large account — far longer than a single request may run. So:
- Every walk is bounded by a wall-clock deadline and caches each repo it
measures, keyed by that repo's
pushed_at. Repos are only re-measured after they receive new commits. /{username}/languagesand/{username}/statsnever substitute whole-repository language bytes in attributed mode. A cold cache can return a partial or empty own-commit split;coverageandpartialon the breakdown endpoint show how much has been measured./{username}/reposreads the attribution cache but never walks diffs itself, because it is already the heaviest endpoint in the API.
A cache is strongly recommended. Without one nothing accumulates between requests, so every request can only report the own-commit data it measured within that request's deadline. Configure either:
REDIS_URL— aredis:///rediss://URL, used in preference when set; orUPSTASH_REDIS_REST_URL+UPSTASH_REDIS_REST_TOKEN— what Vercel's Upstash integration provisions. These are used over Upstash's REST API, which also suits serverless better than a pooled TCP connection.
/{username}/contributions/breakdown reports cache_enabled, plus a status
and message saying why a walk stopped (complete, deadline, rate_limited,
cache_disabled) — check those first when the attributed split does not appear.
To compute attribution up front rather than waiting for it to trickle in:
python scripts/warm_attribution.py tashifkhanIf the deployment's cache credentials are not readable locally, warm it through the API instead — each call measures more and caches it:
for i in $(seq 6); do curl -s https://your-api/tashifkhan/contributions/breakdown \
| python -c 'import json,sys; d=json.load(sys.stdin); print(d["coverage"], d["status"])'; doneTuning knobs (all optional, with defaults): ATTRIBUTION_INLINE_DEADLINE (3.5s
budget inside a request), ATTRIBUTION_BREAKDOWN_DEADLINE (8s),
ATTRIBUTION_MAX_COMMITS_PER_REPO (200), ATTRIBUTION_MAX_COMMIT_DETAILS (600),
ATTRIBUTION_RATE_LIMIT_FLOOR (500 calls kept in reserve for other endpoints),
ATTRIBUTION_CACHE_TTL_SECONDS (7 days).
To run this project locally, follow these steps:
-
Clone the repository:
git clone https://github.com/tashifkhan/GitHub-Stats-API.git cd GitHub-Stats-API -
Install dependencies:
pip install -r requirements.txt
-
Create a
.envfile and add your GitHub token:GITHUB_TOKEN=your_github_token_here -
Run the application:
python main.py
The application will be available at http://localhost:8989.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
See LICENSE for details.