Skip to content
Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace
GitHub Star Tracker star mark

GitHub Star Tracker

A GitHub Action that tracks star counts across all your repositories on a schedule, generates visual reports with charts and badges, and sends notifications when changes are detected.

CICodecovLicense: AGPL-3.0Product Hunt

Documentation · Getting Started · Configuration · Examples · Troubleshooting

Important

Coming from Star History, Starchart.cc or similar? You're in the right place.

GitHub announced that access to the stargazers API is being restricted to repository admins and collaborators. Tools that chart stars for repositories they don't own will start receiving empty responses or 403 errors.

GitHub Star Tracker keeps working. It runs inside your workflow, with your token, against your repositories: exactly the access GitHub is keeping. Star counts, reports, badges, CSV and notifications are unaffected in every case.

The one thing that depends on your role rather than your token's scopes is the stargazer endpoint, and it is what star-history charts and stargazer tracking are reconstructed from. If you track a repository you do not administer (an organization repo where you are a read-only member, or any repo reached through a fine-grained token with no explicit grant on its organization), those two fall back to the stored per-run snapshots. Known Limitations has the detail.


Table of Contents


What You Get

A writing run commits these artefacts to a dedicated data branch. Two runs commit nothing: a read-only run, which renders and reports in full but never pushes, and any run whose output is byte-for-byte what the branch already holds.

  • Animated SVG charts: star history, per-repo trends, top repos comparison, and growth forecasts, with automatic dark/light mode support:

    Star HistoryTop RepositoriesGrowth Forecast
  • Shields.io-style badge: embeddable star count that updates automatically:

    Stars
  • Markdown report: summary tables, delta indicators, every New Repository and Removed Repository since the baseline, stargazer details, and forecast tables.

  • CSV & JSON data: machine-readable exports for dashboards, spreadsheets, or downstream pipelines.

The HTML report is the one thing that is not committed. It is written outside the data branch worktree for the email body, and reaches you through the report-html and report-html-path outputs instead.


Features

  • Animated SVG charts: star history, per-repo trends, comparisons, and growth forecasts, with an optional Trend Line over the observed curve
  • Dark/light mode: SVG charts auto-adapt to the viewer's color scheme via prefers-color-scheme
  • Historical snapshots: configurable retention (default: 52 runs) with JSON persistence
  • Smart filtering: by visibility, Owner, min stars, exact names or regex, archived, forks
  • Stargazer tracking: see who starred your repos, with avatars and dates
  • Email notifications: built-in SMTP, with a fixed or adaptive threshold and a Notification Mode that decides whether losses count
  • GitHub Enterprise: GHES support, auto-detected or explicit API URL
  • Multi-language: English, Spanish, Catalan, Italian
  • CSV export: machine-readable output for data pipelines
  • Eleven action outputs for workflow chaining: lost-stars, new-stargazers, new-stars, notification-sent, report, report-csv, report-html, report-html-path, should-notify, stars-changed and total-stars
  • No install step: its five runtime dependencies are bundled into the committed dist/, so the runner clones and executes, with no npm install in your workflow (ADR 0003)
  • Enforced coverage: the build gate is 85% on lines, functions, branches and statements, over an extensive unit test suite
  • Future-proof: unaffected by GitHub's 2026 stargazers API restrictions, since it uses your own credentials on your own repositories

Quick Start

1. Create a Personal Access Token

  1. Go to GitHub Settings > Tokens
  2. Generate a classic token with repo or public_repo scope, or a fine-grained token with Contents: Read and write on the repositories you want tracked
  3. Add it as a repository secret named STAR_TRACKER_TOKEN

Note

The default GITHUB_TOKEN is not sufficient. See the PAT guide for details, including why a fine-grained token can leave the stargazer sections empty.

2. Add the Workflow

Create .github/workflows/star-tracker.yml:

name: Track Starson:
schedule:
- cron: '0 0 * * *'# Daily at midnightworkflow_dispatch:
permissions:
contents: writejobs:
track:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: fbuireu/github-star-tracker@v1with:
github-token: ${{ secrets.STAR_TRACKER_TOKEN }}

3. Run and View

  • Manual run: Actions > Track Stars > Run workflow
  • View report: Check the star-tracker-data branch in your repository

Configuration

Set options directly in the workflow or via a YAML config file. See the Configuration guide for full details.

- uses: fbuireu/github-star-tracker@v1with:
github-token: ${{ secrets.STAR_TRACKER_TOKEN }}visibility: 'public'# public | private | all | ownedlocale: 'es'# en | es | ca | itinclude-charts: truetrack-stargazers: truemin-stars: '5'exclude-repos: 'test-repo,/^demo-.*/'compare-against: 'last-run'# last-run | 24h | 7d | 30dnotification-threshold: '500'# 0 | N | autonotification-mode: 'gains'# net | gains
All Inputs
InputDefaultDescription
github-token-Required. PAT with repo or public_repo scope
chart-animationtrueAnimate SVG charts (true) or render them static (false) for email/static contexts
chart-begin-at-zerofalseStart the Y-axis at zero (true) or zoom into the data range (false)
chart-curvemonotoneCurve when smoothing: monotone (no overshoot, best for stars), catmull-rom, cubic-bezier, rounded-step. Email approximates non-monotone curves
chart-custom-milestones-Comma-separated star counts for the milestone reference lines, replacing the built-in defaults (e.g. 250, 750, 2500). Requires chart-milestones
chart-line-color#dfb317Hex color of primary chart line/fill/points (not comparison). Accepts hex with or without a leading #
chart-line-width2.5Stroke width (px, >0) of data lines in all charts
chart-max-points30Curve granularity: points across the full span (capped at 365); 0 reconstructs at weekly resolution. Not a time window (see chart-range)
chart-milestonestrueShow milestone reference lines on the main star-history chart (true) or hide them (false)
chart-rangeallTime window plotted: 30d, 90d, 1y or all
chart-show-pointstrueDraw a marker on each data point (true) or hide them for a cleaner dense line (false)
chart-smoothingtrueSmooth curve (true) or straight segments to show spikes; applies to email charts too
chart-themeautoColor theme for the SVG charts: auto (follows prefers-color-scheme), light or dark
chart-trend-linefalseOverlay a dashed moving-average trend line on the main chart
chart-y-axis-sideleftY-axis labels side: left or right
compare-againstlast-runSnapshot used as comparison baseline: last-run, 24h, 7d or 30d. If history is shorter than the window, the oldest stored snapshot is used and the report's date shows how far back it really goes
config-pathstar-tracker.ymlPath to YAML config file
data-branchstar-tracker-dataBranch for tracking data
email-fromlocalizedSender name or address; defaults to a localized sender name
email-themeautoColor theme for the HTML email and its charts: auto (same as chart-theme), light or dark. Email charts are images, so a dark-mode reader needs this to resolve to dark
email-to-Recipient address
exclude-orgs-Owners to exclude (exact name or /regex/)
exclude-repos-Repos to exclude (exact name or /regex/)
github-api-url-GitHub API base URL (for GHES). Auto-detected on GHES runners
include-archivedfalseInclude archived repos
include-chartstrueGenerate star trend charts
include-forksfalseInclude forked repos
localeenen, es, ca, or it
max-history52Max snapshots to keep
min-stars0Min stars to track
notification-modenetHow the threshold measures that change: net (absolute change, so a large drop also fires) or gains (upward movement only)
notification-threshold00 (every run with changes), N (accumulated change since the last notification), or auto (adaptive)
only-orgs-Only track repos under these Owners (exact name or /regex/)
only-repos-Only track these repos (exact name or /regex/)
read-onlyfalseMake this a Read-Only Run: it still fetches, reports, sets outputs and emails, it just never commits or pushes. Use it for a second workflow that shares a data branch with the workflow that writes it
send-on-no-changesfalseEmail even with no changes
smart-samplingfalseSample stargazer pages for high-star repos (avoids rate limits)
smart-sampling-pages30Max evenly-spaced stargazer pages per sampled repo
smart-sampling-threshold1500Star count above which a repo is sampled
smtp-host-SMTP hostname (enables email)
smtp-password-SMTP password
smtp-port587SMTP port
smtp-username-SMTP username
top-repos10Top repos in charts/forecasts
track-stargazersfalseTrack individual stargazers
velocity-metricsfalseAdd a growth-velocity section (stars/day, % growth, days to next milestone) to the report
visibilityallpublic, private, all, or owned

[!IMPORTANT] notification-threshold decides when you get an email; compare-against decides what period the report body covers. The two are independent: the threshold accumulates from the Notification Baseline, while the report diffs against a stored snapshot. So a threshold that takes several runs to trip still produces a report covering only the compare-against window. Set them to match if you want the email body to span what the threshold accumulated.

See notification-threshold for how the counter behaves on a fresh data branch, when you raise the value, and on a read-only run.

In the YAML config file, option keys may be written with either dashes or underscores (include-charts and include_charts are both accepted), so you can copy option names straight from this table without rewriting the separators.

Outputs
OutputDescription
lost-starsStars lost vs. the comparison baseline. Per run, not cumulative
new-stargazersNew stargazers vs. the stored stargazer list, which every writing run rewrites - not driven by compare-against
new-starsStars gained vs. the comparison baseline. Per run, not cumulative
notification-senttrue / false - whether an email was actually delivered. should-notify is the decision; this is the outcome
reportFull Markdown report
report-csvCSV report (for data pipelines)
report-htmlHTML report (for email)
report-html-pathFile path to the HTML report (for large reports / custom mailers)
should-notifytrue / false - the cumulative threshold signal, driven by notification-threshold and notification-mode (and requires an actual change)
stars-changedtrue / false - anything changed vs. the comparison baseline (per run)
total-starsTotal star count

To email on every N stars, use notification-threshold: 'N' with notification-mode: 'gains' and gate the step on if: steps.tracker.outputs.should-notify == 'true'. Gating on new-stars >= N would require N stars inside a single run, which on a daily schedule almost never happens.

API Reference: Complete inputs, outputs, and data formats


How It Works

---
config:
look: handDrawn
---
flowchart TD
trigger(["Workflow Trigger"])
config["Parse configuration"]
fetch["Query GitHub REST API (repositories endpoint)"]
filter["Apply filter criteria"]
init["Initialize orphan branch"]
read["Deserialize previous state snapshot"]
compare["Compute delta metrics"]
stargazers["Fetch stargazers (starred_at)"]
history["Build real star history"]
forecast["Compute growth forecast"]
md["Markdown report"]
json["JSON dataset"]
csv["CSV report"]
svg["SVG badge"]
html["HTML digest"]
charts["SVG charts"]
commit["Git commit & push (data branch)"]
setout["Export action outputs"]
email{"SMTP set up, and due to send?"}
send["Dispatch notification"]
trigger --> config --> fetch --> filter
filter -->|no repositories matched| setout
filter --> init --> read --> compare
compare --> stargazers --> history --> forecast
forecast --> md & json & csv & svg & html & charts
md & json & csv & svg & html & charts --> email
email -->|Yes| send --> commit
email -->|No| commit
commit --> setout
style trigger stroke:#1565c0,stroke-width:3px
style config stroke:#e65100,stroke-width:3px
style fetch stroke:#e65100,stroke-width:3px
style filter stroke:#e65100,stroke-width:3px
style init stroke:#7b1fa2,stroke-width:3px
style read stroke:#7b1fa2,stroke-width:3px
style compare stroke:#7b1fa2,stroke-width:3px
style stargazers stroke:#7b1fa2,stroke-width:3px
style history stroke:#7b1fa2,stroke-width:3px
style forecast stroke:#7b1fa2,stroke-width:3px
style md stroke:#2e7d32,stroke-width:3px
style json stroke:#2e7d32,stroke-width:3px
style csv stroke:#2e7d32,stroke-width:3px
style svg stroke:#2e7d32,stroke-width:3px
style html stroke:#2e7d32,stroke-width:3px
style charts stroke:#2e7d32,stroke-width:3px
style commit stroke:#c2185b,stroke-width:3px
style setout stroke:#c2185b,stroke-width:3px
style email stroke:#c2185b,stroke-width:3px
style send stroke:#c2185b,stroke-width:3px
Loading

How It Works: The full execution pipeline, phase by phase. Architecture: the DDD(ish) layering, one ubiquitous language and a pure core, and how much of the tactical catalogue is taken

How the charts read dates

The charts plot the real historical curve: every star is placed on the date it was actually given. Each stargazer carries a starred_at timestamp (GitHub's application/vnd.github.star+json media type), and the action reconstructs the cumulative star count over real time from those dates, so the timeline runs from a repo's very first star up to now, regardless of when you started running the action.

The per-run snapshots on the data branch are still kept for the report's delta tables and notifications ("how many stars changed against the comparison baseline", which compare-against selects), but the charts themselves no longer depend on them.

One caveat: GitHub caps the stargazers listing at roughly 40,000 per repo (oldest first), so on a very large repo the most recent stars fall outside the Reachable Stargazers and the Covered Stars behind the curve stop short of the true total. The reachable portion is drawn accurately and the recent tail is bridged with a straight ramp up to the current total, so the early curve stays honest and the chart never goes flat at the end. Pair this with smart-sampling to keep the request cost bounded on big repos.

The line style is configurable via chart-curve (monotone by default, plus catmull-rom, cubic-bezier and rounded-step), along with theme, colors, milestones, point markers, the time window and more. See the examples gallery for a rendered comparison of every option.


Embedding in Your README

Star Badge

![Stars](https://raw.githubusercontent.com/YOUR_USER/YOUR_REPO/star-tracker-data/stars-badge.svg)

Star History Chart

![Star History](https://raw.githubusercontent.com/YOUR_USER/YOUR_REPO/star-tracker-data/charts/star-history.svg)

Tip

SVG charts automatically adapt to dark and light mode. No extra configuration needed: they use prefers-color-scheme to match the viewer's theme.

Viewing Reports: All access methods (data branch, badges, outputs, email)


Documentation

GuideDescription
Getting StartedSetup from token to first run
How It WorksExecution flow, phase by phase
ArchitectureDDD(ish) layers, and where the DDD stops
ConfigurationAll options and settings
API ReferenceInputs, outputs, and data formats
ExamplesReal-world workflow configurations
Star Trend ChartsChart types, embedding, and customization
Email NotificationsBuilt-in SMTP and external action setup
Viewing ReportsData branch, badges, outputs, raw data
Data ManagementStorage, rotation, and manual management
InternationalizationMulti-language support
Personal Access TokenClassic and fine-grained token setup
Technical StackTechnologies and design decisions
Known LimitationsConstraints and workarounds
TroubleshootingCommon issues and solutions

For why the action is built the way it is, one decision per file, see the architecture decision records. They include the AGPL-3.0-only licence and what it asks of anyone redistributing or hosting a modified version.


Support & Contributing

If you find this project useful, consider supporting its development:

SponsorBuy Me A Beer


Use of AI

This project uses AI assistance primarily for documentation purposes. AI tools (GitHub Copilot, Claude) were used to:

  • Write and improve documentation (README, wiki pages)
  • Generate boilerplate code and configuration files
  • Assist with code reviews and suggestions

The core logic, architecture decisions, and implementation were developed by the maintainer. All AI-generated content has been reviewed and validated.


AGPL-3.0 © Made with 🤘🏼 by Ferran Buireu

About

⭐ GitHub Action to automatically track star count changes across repositories with visual charts, email notifications, and historical reports

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

16 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages