A serverless application for generating dynamic GitHub contribution widgets as SVG images. Built with Netlify Functions and designed to be embedded anywhere.
- GitHub Widgets
- 🎨 Beautiful SVG Widgets - Animated, responsive, customizable widgets for GitHub ReadMe
- 🌈 Customizable Themes - Choose from multiple color themes for widgets
- ⚡ Fast & Cached - In-memory LRU cache with configurable TTL (default: 1 hour)
- 🔒 Secure - Optional user locking via
LOCK_GITHUB_USERenvironment variable - 🚀 Serverless - Runs on Netlify Functions (AWS Lambda)
- 🔄 Extensible - Easy to add new widget types and API versions
- 🛠 SVG Error Handling - All errors returned as SVG images with appropriate HTTP status codes
All widgets support customizable color themes to match your style preferences. Choose from 6 pre-built themes or use the default.
Use the theme query parameter to select a theme for any widget:
| Theme | Description | Preview Colors |
|---|---|---|
| radical (default) | Vibrant pink and purple with dark background | Pink title, multi-color accents |
| ocean | Cool blue tones inspired by the deep sea | Cyan title, ocean blue palette |
| sunset | Warm pink and orange hues | Coral pink title, sunset gradients |
| forest | Natural green tones | Fresh green title, nature-inspired |
| midnight | Deep purple and violet shades | Purple title, night sky colors |
| monochrome | Classic black, white, and gray | Clean grayscale aesthetic |
Add the theme parameter to any widget URL:
/api/v1/timeseries-history.svg?userName=octocat&theme=oceanRadical Theme (Default):
Ocean Theme:
Sunset Theme:
Forest Theme:
Midnight Theme:
Monochrome Theme:
- Node.js 20.x or higher
- GitHub Personal Access Token (create one here)
- Netlify account (for deployment)
- Clone the repository:
git clone https://github.com/yourusername/github-widgets.git
cd github-widgets- Install dependencies:
npm install- Create a
.envfile from the example:
cp .env.example .env- Add your GitHub token to
.env:
GITHUB_TOKEN=ghp_your_token_hereRun the development server:
npm run devThe API will be available at http://localhost:8888/api/v1/
Test the endpoints:
# Timeseries history - with username and date range
curl "http://localhost:8888/api/v1/timeseries-history.svg?userName=cyrus2281&range=2025-01-01:2025-10-15"
# Timeseries history - with username only (defaults to last 365 days)
curl "http://localhost:8888/api/v1/timeseries-history.svg?userName=cyrus2281"
# Experience timeline - with CSV data
CSV_DATA="company,start,end,title,logo,color%0AGoogle,2025-10,,AI/ML%20Engineer,,#4285F4"
curl "http://localhost:8888/api/v1/experience-timeline.svg?experienceCSV=${CSV_DATA}"
# Most starred repositories
curl "http://localhost:8888/api/v1/most-starred.svg?userName=torvalds&top=5"- Production:
https://your-site.netlify.app/api/v1/ - Local:
http://localhost:8888/api/v1/
Generate a GitHub contribution timeseries chart as an SVG image.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
userName |
string | Conditional* | GitHub username to generate chart for |
range |
string | Optional | Date range in format YYYY-MM-DD:YYYY-MM-DD (max 365 days) |
theme |
string | Optional | Color theme: radical (default), ocean, sunset, forest, midnight, monochrome |
*Required unless LOCK_GITHUB_USER environment variable is set.
Examples:
# Basic usage
/api/v1/timeseries-history.svg?userName=octocat
# With date range
/api/v1/timeseries-history.svg?userName=octocat&range=2024-01-01:2024-12-31
# With custom theme
/api/v1/timeseries-history.svg?userName=octocat&theme=oceanResponse:
- Content-Type:
image/svg+xml - Cache-Control:
public, max-age=3600 - X-Cache:
HITorMISS(indicates cache status)
Generate a professional experience timeline as an SVG image.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
experienceCSV |
string | Yes | URI-encoded CSV data with experience entries |
includeStartDate |
boolean | Optional | Whether to display start date labels on timeline nodes. Defaults to true. |
includeEndDate |
boolean | Optional | Whether to display end date labels on timeline nodes. Defaults to true. |
width |
number | Optional | Width of the SVG in pixels. Defaults to 1200. |
heightPerLane |
number | Optional | Height per timeline lane in pixels. Defaults to 80. |
marginTop |
number | Optional | Top margin in pixels. Defaults to 100. |
marginRight |
number | Optional | Right margin in pixels. Defaults to 30. |
marginBottom |
number | Optional | Bottom margin in pixels. Defaults to 30. |
marginLeft |
number | Optional | Left margin in pixels. Defaults to 30. |
baseFontSize |
number | Optional | Base font size in pixels for relative scaling of all text. All font sizes scale proportionally from this value. Defaults to 14. |
embedLogos |
boolean | Optional | Whether to embed company logos in the timeline. Defaults to true. |
animationTotalDuration |
number | Optional | Total duration of the animation in seconds. Defaults to 5. |
theme |
string | Optional | Color theme: radical (default), ocean, sunset, forest, midnight, monochrome |
CSV Format:
The CSV must have the following header (in this exact order):
company,start,end,title,logo,color
Field Descriptions:
company(required): Company namestart(required): Start date in formatYYYY,YYYY-MM, orYYYY-MM-DDend(optional): End date in same format as start, or empty for "present"title(optional): Job title/positionlogo(optional): URL to company logo imagecolor(optional): Hex color code for the timeline bar (e.g.,#4285F4)
Example CSV:
company,start,end,title,logo,color
Google,2025-10,,AI/ML Engineer,https://example.com/google-logo.png,#4285F4
Spotify,2024-08,2025-06,Sr Software Developer,https://example.com/spotify-logo.png,#1DB954
Netflix,2024-04,2024-12,Software Engineer - Contract,,#E50914
Amazon,2022-01,2024-08,Software Developer,https://example.com/amazon-logo.png,#FF9900
Meta,2020-06,2021-10,Web Developer,https://example.com/meta-logo.png,#0668E1
Usage Examples:
# Basic example with minimal data
CSV="company,start,end,title,logo,color%0AGoogle,2025-10,,AI/ML%20Engineer,,#4285F4"
curl "http://localhost:8888/api/v1/experience-timeline.svg?experienceCSV=${CSV}"
# With multiple entries (URL encode the entire CSV)
# Use online URL encoder or encodeURIComponent() in JavaScript
# Customizing dimensions and animation
CSV="company,start,end,title,logo,color%0AGoogle,2025-10,,AI/ML%20Engineer,,#4285F4"
curl "http://localhost:8888/api/v1/experience-timeline.svg?experienceCSV=${CSV}&width=800&heightPerLane=60&animationTotalDuration=10"- Use width, margin, and font size parameters to fit your layout.
JavaScript Example:
const experienceData = `company,start,end,title,logo,color
Google,2025-10,,AI/ML Engineer,https://example.com/logo.png,#4285F4
Spotify,2024-08,2025-06,Sr Software Developer,,#1DB954`;
const encodedCSV = encodeURIComponent(experienceData);
const url = `https://your-site.netlify.app/api/v1/experience-timeline.svg?experienceCSV=${encodedCSV}`;Response:
- Content-Type:
image/svg+xml - Cache-Control:
public, max-age=3600 - X-Cache:
HITorMISS(indicates cache status)
Error Responses:
All errors are returned as SVG images with appropriate HTTP status codes:
400 Bad Request- Invalid CSV format, missing required fields, or invalid dates404 Not Found- Invalid endpoint500 Internal Server Error- Server error during SVG generation
Generate a widget displaying your most starred GitHub repositories with animated glowing borders.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
userName |
string | Conditional* | GitHub username to fetch repositories for |
top |
number | Optional | Number of repositories to display (1-10). Defaults to 3. |
title |
string | Optional | Custom title for the widget. Defaults to "Most Starred". |
animationDuration |
number | Optional | Duration of card entrance animations in seconds (0.5-10). Defaults to 3.5. |
theme |
string | Optional | Color theme: radical (default), ocean, sunset, forest, midnight, monochrome |
*Required unless LOCK_GITHUB_USER environment variable is set.
Examples:
# Basic usage - top 3 repositories (default)
/api/v1/most-starred.svg?userName=torvalds
# Custom number of repositories
/api/v1/most-starred.svg?userName=torvalds&top=5
# Custom title and theme
/api/v1/most-starred.svg?userName=torvalds&top=5&title=Top%20Projects&theme=ocean
# Custom animation duration (faster animations)
/api/v1/most-starred.svg?userName=torvalds&animationDuration=2
# All parameters
/api/v1/most-starred.svg?userName=torvalds&top=5&title=My%20Best%20Work&theme=midnight&animationDuration=4.5Response:
- Content-Type:
image/svg+xml - Cache-Control:
public, max-age=3600 - X-Cache:
HITorMISS(indicates cache status)
Error Responses:
400 Bad Request- Invalid username or top parameter out of range (1-10)404 Not Found- User not found or no repositories available500 Internal Server Error- Server error during SVG generation
Generate a comprehensive GitHub user statistics widget displaying various metrics with an animated GitHub logo.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
userName |
string | Conditional* | GitHub username to fetch statistics for |
showHandle |
boolean | Optional | Display user's GitHub handle (@username). Defaults to true. |
showStars |
boolean | Optional | Display total stars across all repositories. Defaults to true. |
showCommits |
boolean | Optional | Display total commits (all time). Defaults to true. |
showCommitsThisYear |
boolean | Optional | Display commits for the current year. Defaults to true. |
showPRs |
boolean | Optional | Display total pull requests. Defaults to true. |
showIssues |
boolean | Optional | Display total issues. Defaults to true. |
showRepos |
boolean | Optional | Display total repositories. Defaults to true. |
showContributedTo |
boolean | Optional | Display number of repositories contributed to. Defaults to true. |
showLogo |
boolean | Optional | Show/hide the GitHub logo. When hidden, widget width adjusts to 300px. Defaults to true. |
width |
number | Optional | Width of the SVG in pixels (300-1000). Defaults to 600. |
animationDuration |
number | Optional | Duration of animations in seconds (0.5-10). Defaults to 2. |
theme |
string | Optional | Color theme: radical (default), ocean, sunset, forest, midnight, monochrome |
*Required unless LOCK_GITHUB_USER environment variable is set.
Examples:
# Basic usage - all stats visible (default)
/api/v1/user-stats.svg?userName=octocat
# Show only specific stats
/api/v1/user-stats.svg?userName=octocat&showCommits=false&showIssues=false
# Custom width
/api/v1/user-stats.svg?userName=octocat&width=600
# With custom theme
/api/v1/user-stats.svg?userName=octocat&theme=ocean
# Minimal stats display
/api/v1/user-stats.svg?userName=octocat&showHandle=false&showCommitsThisYear=false&showPRs=false&showIssues=false
# Custom animation speed
/api/v1/user-stats.svg?userName=octocat&animationDuration=4
# Hide the GitHub logo (widget becomes narrower at 300px)
/api/v1/user-stats.svg?userName=octocat&showLogo=false
# All parameters combined
/api/v1/user-stats.svg?userName=octocat&width=700&theme=midnight&animationDuration=3&showCommitsThisYear=falseResponse:
- Content-Type:
image/svg+xml - Cache-Control:
public, max-age=3600 - X-Cache:
HITorMISS(indicates cache status)
Error Responses:
400 Bad Request- Invalid username, width out of range (300-1000), or animationDuration out of range (0.5-10)404 Not Found- User not found500 Internal Server Error- Server error during SVG generation
Generate a repository card widget displaying GitHub repository information similar to GitHub's pinned repositories.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
userName |
string | Conditional* | GitHub username (repository owner) |
repoName |
string | Yes | Repository name |
theme |
string | Optional | Color theme: radical (default), ocean, sunset, forest, midnight, monochrome |
showUserName |
boolean | Optional | Display the username/owner. Defaults to true. |
showLanguage |
boolean | Optional | Display the primary language. Defaults to true. |
showStars |
boolean | Optional | Display star count. Defaults to true. |
showForks |
boolean | Optional | Display fork count. Defaults to true. |
width |
number | Optional | Width of the card in pixels (300-600). Defaults to 400. |
height |
number | Optional | Height of the card in pixels (100-200). Defaults to 120. |
*Required unless LOCK_GITHUB_USER environment variable is set.
Examples:
# Basic usage
/api/v1/repository-card.svg?userName=octocat&repoName=github-widgets
# With custom theme
/api/v1/repository-card.svg?userName=octocat&repoName=github-widgets&theme=ocean
# Hide specific elements
/api/v1/repository-card.svg?userName=octocat&repoName=github-widgets&showUserName=false&showForks=false
# Custom dimensions
/api/v1/repository-card.svg?userName=octocat&repoName=github-widgets&width=500&height=150
# All parameters combined
/api/v1/repository-card.svg?userName=octocat&repoName=github-widgets&theme=midnight&width=550&height=140&showLanguage=falseResponse:
- Content-Type:
image/svg+xml - Cache-Control:
public, max-age=3600 - X-Cache:
HITorMISS(indicates cache status)
Error Responses:
400 Bad Request- Invalid username, repository name, or parameters out of range404 Not Found- Repository not found500 Internal Server Error- Server error during SVG generation
<img src="https://your-site.netlify.app/api/v1/timeseries-history.svg?userName=octocat" alt="GitHub Contributions" />GITHUB_TOKEN- GitHub Personal Access Token- Required scopes:
read:user - Create token here
- Required scopes:
-
LOCK_GITHUB_USER- Lock API to specific GitHub user- When set,
userNamequery parameter is disabled - Useful for personal deployments
- Example:
LOCK_GITHUB_USER=cyrus2281
- When set,
-
CACHE_MAX_SIZE- Maximum number of cached responses- Default:
100 - Increase for high-traffic deployments
- Default:
-
CACHE_TTL_MS- Cache time-to-live in milliseconds- Default:
3600000(1 hour) - Adjust based on update frequency needs
- Default:
- Via Netlify CLI:
# Login to Netlify
netlify login
# Deploy to production
npm run deploy- Via Git Integration:
- Push your code to GitHub
- Connect repository in Netlify dashboard
- Netlify will auto-deploy on push to main branch
- Set Environment Variables:
In Netlify dashboard or via CLI:
netlify env:set GITHUB_TOKEN "ghp_your_token_here"
netlify env:set LOCK_GITHUB_USER "your-username" # OptionalThe application uses standard Netlify Functions format. To deploy elsewhere:
- Adapt the function handler format for your platform
- Ensure Node.js 20.x runtime
- Set environment variables
- Configure routing to
/api/*→ function handler
The application follows a modular, extensible architecture:
- API Router - Routes requests to versioned handlers
- Handlers - Process requests and generate responses
- Services - Business logic (GitHub API, SVG generation)
- Utils - Shared utilities (cache, validation, errors)
- In-Memory LRU Cache - Fast, simple, resets on cold starts
- Cache Key Format:
timeseries-history:{username}:{startDate}:{endDate} - TTL: 1 hour (configurable)
- Max Size: 100 entries (configurable)
- Eviction: Least Recently Used (LRU)
Cache headers:
X-Cache: HIT- Response served from cacheX-Cache: MISS- Response generated fresh
- Create handler in
src/handlers/v1/new-endpoint.js:
export async function handler(event) {
// Your logic here
return {
statusCode: 200,
headers: { 'Content-Type': 'image/svg+xml' },
body: svgContent,
};
}- Add route in
netlify/functions/api.js:
case 'new-endpoint.svg':
return newEndpointHandler(event);- Reuse existing utilities (cache, validation, errors)
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
Apache-2.0 License - see LICENSE file for details