Skip to content

cyrus2281/github-widgets

Repository files navigation

GitHub Widgets

A serverless application for generating dynamic GitHub contribution widgets as SVG images. Built with Netlify Functions and designed to be embedded anywhere.

Widgets

GitHub Contribution Timeseries

time-series-sample

Experience Timeline

experience-timeline-sample

Most Starred Repositories

most-starred-sample

User Stats

user-stats-sample

Repository Card

repository-card-sample

Contents

Features

  • 🎨 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_USER environment 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

Themes

All widgets support customizable color themes to match your style preferences. Choose from 6 pre-built themes or use the default.

Available Themes

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

Usage

Add the theme parameter to any widget URL:

/api/v1/timeseries-history.svg?userName=octocat&theme=ocean

Previews

Radical Theme (Default):

Radical Theme

Ocean Theme:

Ocean Theme

Sunset Theme:

Sunset Theme

Forest Theme:

Forest Theme

Midnight Theme:

Midnight Theme

Monochrome Theme:

Monochrome Theme

Quick Start

Prerequisites

  • Node.js 20.x or higher
  • GitHub Personal Access Token (create one here)
  • Netlify account (for deployment)

Installation

  1. Clone the repository:
git clone https://github.com/yourusername/github-widgets.git
cd github-widgets
  1. Install dependencies:
npm install
  1. Create a .env file from the example:
cp .env.example .env
  1. Add your GitHub token to .env:
GITHUB_TOKEN=ghp_your_token_here

Local Development

Run the development server:

npm run dev

The API will be available at http://localhost:8888/api/v1/

Testing

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"

API Documentation

Base URL

  • Production: https://your-site.netlify.app/api/v1/
  • Local: http://localhost:8888/api/v1/

Endpoints

GET /api/v1/timeseries-history.svg

time-series-sample

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=ocean

Response:

  • Content-Type: image/svg+xml
  • Cache-Control: public, max-age=3600
  • X-Cache: HIT or MISS (indicates cache status)

GET /api/v1/experience-timeline.svg

experience-timeline-sample

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 name
  • start (required): Start date in format YYYY, YYYY-MM, or YYYY-MM-DD
  • end (optional): End date in same format as start, or empty for "present"
  • title (optional): Job title/position
  • logo (optional): URL to company logo image
  • color (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: HIT or MISS (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 dates
  • 404 Not Found - Invalid endpoint
  • 500 Internal Server Error - Server error during SVG generation

GET /api/v1/most-starred.svg

most-starred-sample

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.5

Response:

  • Content-Type: image/svg+xml
  • Cache-Control: public, max-age=3600
  • X-Cache: HIT or MISS (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 available
  • 500 Internal Server Error - Server error during SVG generation

GET /api/v1/user-stats.svg

user-stats-sample

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=false

Response:

  • Content-Type: image/svg+xml
  • Cache-Control: public, max-age=3600
  • X-Cache: HIT or MISS (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 found
  • 500 Internal Server Error - Server error during SVG generation

GET /api/v1/repository-card.svg

repository-card-sample

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=false

Response:

  • Content-Type: image/svg+xml
  • Cache-Control: public, max-age=3600
  • X-Cache: HIT or MISS (indicates cache status)

Error Responses:

  • 400 Bad Request - Invalid username, repository name, or parameters out of range
  • 404 Not Found - Repository not found
  • 500 Internal Server Error - Server error during SVG generation

Embedding in Markdown

![GitHub Contributions](https://your-site.netlify.app/api/v1/timeseries-history.svg?userName=octocat)

Embedding in HTML

<img src="https://your-site.netlify.app/api/v1/timeseries-history.svg?userName=octocat" alt="GitHub Contributions" />

Environment Variables

Required

  • GITHUB_TOKEN - GitHub Personal Access Token

Optional

  • LOCK_GITHUB_USER - Lock API to specific GitHub user

    • When set, userName query parameter is disabled
    • Useful for personal deployments
    • Example: LOCK_GITHUB_USER=cyrus2281
  • CACHE_MAX_SIZE - Maximum number of cached responses

    • Default: 100
    • Increase for high-traffic deployments
  • CACHE_TTL_MS - Cache time-to-live in milliseconds

    • Default: 3600000 (1 hour)
    • Adjust based on update frequency needs

Deployment

Deploy to Netlify

  1. Via Netlify CLI:
# Login to Netlify
netlify login

# Deploy to production
npm run deploy
  1. Via Git Integration:
  • Push your code to GitHub
  • Connect repository in Netlify dashboard
  • Netlify will auto-deploy on push to main branch
  1. 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"  # Optional

Deploy to Other Platforms

The application uses standard Netlify Functions format. To deploy elsewhere:

  1. Adapt the function handler format for your platform
  2. Ensure Node.js 20.x runtime
  3. Set environment variables
  4. Configure routing to /api/* → function handler

Architecture

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)

Caching Strategy

  • 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 cache
  • X-Cache: MISS - Response generated fresh

Adding New Endpoints

  1. 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,
  };
}
  1. Add route in netlify/functions/api.js:
case 'new-endpoint.svg':
  return newEndpointHandler(event);
  1. Reuse existing utilities (cache, validation, errors)

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Submit a pull request

License

Apache-2.0 License - see LICENSE file for details