Live sports stats on your GitHub profile README — place them wherever you want
Install it by adding the action to a workflow (see Quick start), or ask a question, report a bug, or contribute. See SUPPORT.md for where to get help.
The project currently supports 42 leagues. The support manifest, team directory, and player directory are generated from the same registry used by the action.
Currently supports NBA, MLB, NFL, NHL, MLS, Premier League, La Liga, Bundesliga, Serie A, Ligue 1, Primeira Liga, Eredivisie, WNBA, Liga MX, Brasileirão, NWSL, Saudi Pro League, J1 League, Scottish Premiership, Belgian Pro League, UEFA Champions League, UEFA Europa League, FIFA World Cup, NBA G League, NCAA Men's Basketball, NCAA Women's Basketball, College Football, NCAA Men's Ice Hockey, Formula 1, ATP Tennis, WTA Tennis, NASCAR Cup Series, IndyCar Series, Argentine Primera, A-League Men, Indian Super League, Chinese Super League, Greek Super League, Austrian Bundesliga, Danish Superliga, Norwegian Eliteserien, and Swedish Allsvenskan with more sports coming soon
See a live example in the 23seriy profile README. The action keeps the scoreboard current automatically, including the league logo, team logo, record, recent games, and season status.
Want the same result? Start with the three-step setup, then add the workflow to your profile repository. You can preview the output first with dry_run: true.
See rendered output from several sports and every input option without running
anything. Open the examples gallery to preview real boards (NBA,
MLB, NFL, NHL, Premier League, MLS, UEFA Champions League, College Football,
Formula 1, ATP Tennis, and WTA Tennis) plus demos of the title:, teams: (multi-team),
compact:, and badge: options. For every one of the 42 supported leagues,
see the league showcase — one file per league, built
from live data and refreshed daily, showing the default board plus the
title:, compact:, and badge: options. Or browse the league's
workflow examples for a copy-ready step.
This is what the action writes between your markers — heading, logos and all. Live output for the Lakers (heading levels lowered by one so it nests here):
Western Conference · Pacific Division 🔴 Off-season · Next season starts October 2026
📊 2025-2026 Record: 53W - 29L (64.6%) ████████████████▏░░░░░░░░
📅 Recent Games:
❌ L 110-115 vs OKC (May 11, 2026) [Playoffs]
❌ L 108-131 vs OKC (May 9, 2026) [Playoffs]
❌ L 107-125 @ OKC (May 7, 2026) [Playoffs]
❌ L 90-108 @ OKC (May 5, 2026) [Playoffs]
✅ W 98-78 @ HOU (May 1, 2026) [Playoffs]
- Add two marker comments to your profile
README.md(details). - Create a
GH_TOKENsecret (details). - Paste a one-step workflow (details).
That's it — the action keeps your scoreboard current. Want to see more before committing? Browse the examples gallery or set dry_run: true.
- 30-second setup
- Quick Start (3 steps)
- Project health
- See it in action
- Examples
- Preview
- Common setups
- Supported Sports
- Team & Player Abbreviations
- Customizing the board
- Run Locally
- Adding a New Sport
- Action Inputs (
with:) - Action Outputs
- Troubleshooting
- License
- Changelog
Your profile README lives in a public repository with the same name as your GitHub username. If you do not have one yet, create it first.
In your username/username repo's README.md, add these markers wherever you want the stats to appear:
<!-- readme-scoreboard-nba start -->
<!-- readme-scoreboard-nba end -->The name is yours to choose — it just has to match the marker: on the workflow
step below.
You only add the markers — the action fills in everything between them,
including the section heading (## My Favourite NBA Team) and its league logo.
Go to your profile repo Settings → Secrets and variables → Actions and add:
| Secret | Description |
|---|---|
GH_TOKEN |
Fine-grained token with Contents: Read and write on the target repo (create one) |
For least-privilege access, create a fine-grained token, select Only select
repositories, choose your profile repository, and grant only
Contents: Read and write. Classic tokens with repo scope are also
supported, but they grant broader access than this action needs.
That's all! No sports-specific API keys needed — all adapters use free, no-auth public APIs (ESPN, MLB Stats API, NHL.com, etc).
Create .github/workflows/scoreboard.yml in your profile repo:
name: Update Scoreboard
on:
schedule:
- cron: "0 */6 * * *" # Every 6 hours
workflow_dispatch: # Manual trigger
permissions:
contents: write
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: 23seriy/readme-scoreboard@v1
with:
gh_token: ${{ secrets.GH_TOKEN }}
sport: nba
team: LAL
marker: readme-scoreboard-nbaReplace nba, LAL, and readme-scoreboard-nba with your league, team, and
marker from step 1. A manual Run workflow uses the same configuration as
the schedule. Done! The action updates your profile README through the GitHub
API, so no checkout or separate commit step is needed.
Need a different team? Use Supported Sports to find the league key, the generated team directory to find the team abbreviation (or the player directory for an individual athlete), or league workflow examples for a copy-ready step.
For the first update, commit the workflow, open the Actions tab, select Update Scoreboard, and choose Run workflow. When it finishes, refresh your profile README to see the scoreboard.
Use one of these simple schedule choices by changing the cron line:
| Frequency | Cron | Use when |
|---|---|---|
| Every 6 hours | 0 */6 * * * |
You want scores refreshed throughout the day. |
| Daily | 0 12 * * * |
You want a lighter, once-a-day update. |
| Manual only | Remove schedule |
You only want updates from Run workflow. |
To verify live API data without changing a README, set dry_run: true. Dry runs
still render the normal preview and job summary, but they do not require a token
or target repository.
Pin the action to a release tag (for example, @v1) for reproducible workflows,
or to a commit SHA after reviewing the release. Using @main follows the
latest changes and is best suited to trying upcoming features.
| Goal | What to use |
|---|---|
| One scoreboard | Add one marker pair and one action step with sport and team. |
| Several sports | Give every sport its own marker name, such as readme-scoreboard-nba and readme-scoreboard-mlb. |
| Another repository | Set target_repo: owner/repository and grant the token access to that repository. |
| Test before publishing | Set dry_run: true; the action renders the result without changing a README. |
The Season column uses both a color and text so it remains understandable without emoji support: In progress shows the season end date, while Off-season shows the next season start date. Logos include descriptive alt text, and the status text is the source of truth for screen readers.
Give each sport its own marker pair. Every step rewrites whatever sits between its markers, so two sports sharing one pair means the second silently overwrites the first. Add matching pairs to your README:
<!-- readme-scoreboard-nba start -->
<!-- readme-scoreboard-nba end -->
<!-- readme-scoreboard-mlb start -->
<!-- readme-scoreboard-mlb end -->Then add a step per sport with its matching marker:
- uses: 23seriy/readme-scoreboard@v1
with:
gh_token: ${{ secrets.GH_TOKEN }}
sport: nba
team: LAL
marker: readme-scoreboard-nba
- uses: 23seriy/readme-scoreboard@v1
with:
gh_token: ${{ secrets.GH_TOKEN }}
sport: mlb
team: NYY
marker: readme-scoreboard-mlbOnce you use named markers, set one on every step — including the first.
A step left on the default readme-scoreboard will look for a pair by that
name, and fail the job if you renamed it. A missing marker also fails the job.
For a copy-ready step for any league, open the complete league workflow examples.
The board is generated between your markers, so you can shape it without editing generated output.
Not sure of the league key or team/player abbreviation? Open the generated
team directory (or its machine-readable
team-directory.json) to look up a league, abbreviation,
full name, and ID. For individual sports (ATP, WTA), use the generated
player directory (or its machine-readable
player-directory.json). Constructor-based series
such as Formula 1 are team sports, so look those up in the team directory. The
Supported Sports
table lists every league key and endpoint. Run npm run doctor -- --demo to validate
your choices locally before publishing.
Set compact: true to render a smaller block without the team logo or the
recent-games list — handy for a tighter profile:
- uses: 23seriy/readme-scoreboard@v1
with:
gh_token: ${{ secrets.GH_TOKEN }}
sport: nba
team: LAL
compact: trueSet teams: to a comma-separated list to render several boards from a single
step (one board per team, joined with a divider):
- uses: 23seriy/readme-scoreboard@v1
with:
gh_token: ${{ secrets.GH_TOKEN }}
sport: nba
teams: LAL, BOS, NYKFeature a specific player's season line and last game alongside a team board with the player: input. Supported for nba, wnba, ncaab, ncaaw, mlb, nfl, nhl, and every soccer league.
- uses: 23seriy/readme-scoreboard@v1
with:
sport: nba
team: LAL
player: "Luka Doncic"
gh_token: ${{ secrets.GH_TOKEN }}For MLB, add a batter's spotlight to a team board (e.g. Vladimir Guerrero Jr. on the Blue Jays):
- uses: 23seriy/readme-scoreboard@v1
with:
sport: mlb
team: TOR
player: "Vladimir Guerrero Jr."
gh_token: ${{ secrets.GH_TOKEN }}Football and hockey work the same way:
- uses: 23seriy/readme-scoreboard@v1
with:
sport: nfl
team: KC
player: "Patrick Mahomes"
gh_token: ${{ secrets.GH_TOKEN }}- uses: 23seriy/readme-scoreboard@v1
with:
sport: nhl
team: NYR
player: "Artemi Panarin"
gh_token: ${{ secrets.GH_TOKEN }}The WNBA shares the NBA's athlete endpoints, so it works the same way:
- uses: 23seriy/readme-scoreboard@v1
with:
sport: wnba
team: MIN
player: "Napheesa Collier"
gh_token: ${{ secrets.GH_TOKEN }}Every soccer league supports it too:
- uses: 23seriy/readme-scoreboard@v1
with:
sport: epl
team: ARS
player: "Bukayo Saka"
gh_token: ${{ secrets.GH_TOKEN }}Match the player's full name exactly as it appears on the team's live roster. The match is case-insensitive but otherwise exact — every letter and any diacritic must match the league's roster spelling, so you need to check the roster's actual rendering. For example, the Lakers roster spells Luka as Luka Doncic (no č), so player: "Luka Doncic" is the value that matches (using Luka Dončić would not). If the name doesn't match, the run fails with an error listing the first few roster names, so you can copy the correct spelling.
Each sport's spotlight shows stats that fit the position:
| Sport | Season line | Last game |
|---|---|---|
nba, wnba |
Points, rebounds, assists per game | Points, rebounds, assists, minutes |
mlb |
Batting average, home runs, RBIs | Hits, home runs, RBIs, batting average |
nfl |
Position-dependent — passing yards/TDs for a QB, rushing for a back, receiving for a receiver | The same position group's stats |
nhl |
Goals, assists, points for a skater; wins, GAA, save percentage for a goalie | Goals/assists/points, or saves/shots against for a goalie |
| soccer | Appearances, goals, assists | Goals, assists |
Every spotlight includes the opponent and game date, rendered in the league's timezone.
The spotlight also shows the player's headshot, right-aligned beside the heading, matching how the team logo sits beside the team board. The image is built from the athlete id the roster lookup already returns, so it needs no extra request or configuration:
**👑 Player Spotlight: Luka Doncic**
<img src="https://a.espncdn.com/i/headshots/nba/players/full/3945274.png" alt="Luka Doncic headshot" width="72" align="right" />
33.5 PPG · 7.7 RPG · 8.3 APGIf the upstream feed doesn't supply an athlete id, the headshot is simply omitted and the board renders exactly as before. Headshots are never shown in compact: true mode, which stays text-only.
Soccer season totals are summed from the player's game log, because ESPN publishes no season-stats endpoint for soccer athletes. If ESPN has no game log for the chosen player yet — common in the off-season or in the first weeks of a season — the run fails with a clear "No season stats available" error rather than rendering a line of zeroes.
Eight leagues intentionally don't support player:, either because the
upstream data isn't there or because the league has no athlete roster to
feature:
| Leagues | Reason |
|---|---|
ncaaf, gleague, ncaa_hockey |
ESPN publishes no per-athlete season stats — the stats endpoint 404s, and the game log is empty (for ncaa_hockey the gamelog 404s too). |
atp, wta, nascar, indycar |
These already render as a single player board (entity: player), so a spotlight inside one is redundant. |
f1 |
It renders a constructor board from a teams endpoint and has no athlete roster, so there is no player to spotlight. |
The WNBA and NCAA men's and women's basketball used to be on this list. They aren't any more: ESPN now serves athletes the same avgPoints/avgRebounds/avgAssists splits payload and game log that the NBA uses, so player: works there too. If a league's upstream data changes, re-check the endpoints — the exclusions above are verified against the live APIs, not assumed.
player: isn't supported together with teams: (multiple boards in one run) — use a single team: instead. In compact: true mode, the spotlight collapses to a single stat line and drops the last-game details, matching how compact mode trims the rest of the board.
Set title: to override the default "My Favourite <League> Team" heading:
- uses: 23seriy/readme-scoreboard@v1
with:
gh_token: ${{ secrets.GH_TOKEN }}
sport: nba
team: LAL
title: My Lakers ScoreboardSet badge: true to emit a compact shields-style badge row instead of the full
scoreboard block — useful when you want just a status chip:
- uses: 23seriy/readme-scoreboard@v1
with:
gh_token: ${{ secrets.GH_TOKEN }}
sport: nba
teams: LAL, BOS
badge: trueWhere the league API provides them, the board also shows the team's
standing position, its next scheduled game, and its last-five form
(✅/➖/❌). These lines appear automatically for supported leagues and are
omitted when a league doesn't supply the data, so existing boards stay clean.
Set dry_run: true to fetch and render live data without touching a README. The
output is printed to the job log and step summary, so you can inspect it before
you commit to a live update.
All sports use free, no-auth APIs — no secrets required.
Most leagues come from ESPN's public site.api.espn.com endpoints — each link below opens the live team list for that league. MLB and the NHL have their own official APIs.
For a machine-readable support map, see supported-leagues.json. It lists every league, sport category, API source, team endpoint, logos, and season window.
For copy-ready workflow steps, see league workflow examples.
For team setup, use the generated team directory or its machine-readable counterpart team-directory.json to look up a league, abbreviation, full name, and ID. For individual athletes, use the player directory or player-directory.json. A daily workflow keeps these files current.
The Season column is refreshed daily by .github/workflows/update-season-status.yml. It uses the league API's season window when available and falls back to the last known window during a temporary API outage. A separate daily season-date verification workflow checks that normalized opening dates remain valid as leagues roll into new seasons; it reports drift without changing the README automatically.
| Sport | League | Key | Season | Endpoint |
|---|---|---|---|---|
| 🏀 Basketball | nba |
🔴 Off-season · starts 2026-10-20 | basketball/nba |
|
| ⚾ Baseball | mlb |
🟢 In progress · ends 2026-11-12 | MLB Stats API | |
| 🏈 Football | nfl |
🟢 In progress · ends 2027-02-16 | football/nfl |
|
| 🏒 Hockey | nhl |
🔴 Off-season · starts 2026-09-29 | NHL Web API | |
| ⚽ Soccer | mls |
🟢 In progress · ends 2026-12-31 | soccer/usa.1 |
|
| ⚽ Soccer | epl |
🟢 In progress · ends 2027-06-01 | soccer/eng.1 |
|
| ⚽ Soccer | laliga |
🟢 In progress · ends 2027-06-01 | soccer/esp.1 |
|
| ⚽ Soccer | bundesliga |
🟢 In progress · ends 2027-07-01 | soccer/ger.1 |
|
| ⚽ Soccer | seriea |
🟢 In progress · ends 2027-07-01 | soccer/ita.1 |
|
| ⚽ Soccer | ligue1 |
🟢 In progress · ends 2027-06-01 | soccer/fra.1 |
|
| ⚽ Soccer | primeiraliga |
🟢 In progress · ends 2027-07-01 | soccer/por.1 |
|
| ⚽ Soccer | eredivisie |
🟢 In progress · ends 2027-06-01 | soccer/ned.1 |
|
| 🏀 Basketball | wnba |
🟢 In progress · ends 2026-11-01 | basketball/wnba |
|
| ⚽ Soccer | ligamx |
🟢 In progress · ends 2027-06-01 | soccer/mex.1 |
|
| ⚽ Soccer | brasileirao |
🟢 In progress · ends 2026-12-31 | soccer/bra.1 |
|
| ⚽ Soccer | nwsl |
🟢 In progress · ends 2026-12-31 | soccer/usa.nwsl |
|
| ⚽ Soccer | saudipro |
🟢 In progress · ends 2027-07-01 | soccer/ksa.1 |
|
| ⚽ Soccer | j1 |
🟢 In progress · ends 2027-07-01 | soccer/jpn.1 |
|
| ⚽ Soccer | scottish |
🟢 In progress · ends 2027-06-01 | soccer/sco.1 |
|
| ⚽ Soccer | belgian |
🟢 In progress · ends 2027-07-01 | soccer/bel.1 |
|
| ⚽ Soccer | ucl |
🟢 In progress · ends 2027-07-01 | soccer/uefa.champions |
|
| ⚽ Soccer | uel |
🟢 In progress · ends 2027-07-01 | soccer/uefa.europa |
|
| ⚽ Soccer | worldcup |
🟢 In progress · ends 2026-12-31 | soccer/fifa.world |
|
| 🏀 Basketball | gleague |
🔴 Off-season · starts 2026-12-19 | basketball/nba-development |
|
| 🏀 Basketball | ncaab |
🔴 Off-season · starts 2026-11-02 | basketball/mens-college-basketball |
|
| 🏀 Basketball | ncaaw |
🔴 Off-season · starts 2026-11-02 | basketball/womens-college-basketball |
|
| 🏈 Football | ncaaf |
🟢 In progress · ends 2027-01-28 | football/college-football |
|
| 🏒 Hockey | ncaa_hockey |
🔴 Off-season · starts 2026-10-02 | hockey/mens-college-hockey |
|
| 🏆 Racing | f1 |
🟢 In progress · ends 2026-12-31 | racing/f1 |
|
| 🎾 Tennis | atp |
🟢 In progress · ends 2027-01-01 | tennis/atp |
|
| 🎾 Tennis | wta |
🟢 In progress · ends 2027-01-01 | tennis/wta |
|
| 🏆 Racing | nascar |
🟢 In progress · ends 2026-12-31 | racing/nascar-premier |
|
| 🏆 Racing | indycar |
🟢 In progress · ends 2026-12-31 | racing/irl |
|
| ⚽ Soccer | argentina |
🟢 In progress · ends 2026-12-31 | soccer/arg.1 |
|
| ⚽ Soccer | aleague |
🟢 In progress · ends 2027-07-01 | soccer/aus.1 |
|
| ⚽ Soccer | isl |
🟢 In progress · ends 2027-07-01 | soccer/ind.1 |
|
| ⚽ Soccer | csl |
🟢 In progress · ends 2026-12-31 | soccer/chn.1 |
|
| ⚽ Soccer | greek |
🟢 In progress · ends 2027-07-01 | soccer/gre.1 |
|
| ⚽ Soccer | austria |
🟢 In progress · ends 2027-07-01 | soccer/aut.1 |
|
| ⚽ Soccer | denmark |
🟢 In progress · ends 2027-07-01 | soccer/den.1 |
|
| ⚽ Soccer | norway |
🟢 In progress · ends 2026-12-31 | soccer/nor.1 |
|
| ⚽ Soccer | sweden |
🟢 In progress · ends 2026-12-01 | soccer/swe.1 |
Looking up a team abbreviation? The generated team directory
(and its machine-readable team-directory.json) lists
every league in one place — name, abbreviation, and ID. For individual sports,
the player directory (and its machine-readable
player-directory.json) does the same for players.
Both are refreshed daily by a scheduled workflow and are the single source of
truth, so this README no longer duplicates each league's roster inline.
Requires Node.js 24 or newer. The version is pinned in .nvmrc, so nvm use
selects the right one, and package.json declares the same minimum so package managers warn on
an older runtime.
cp sample.env .env
# Fill in your values
npm install
npm startBefore a live run, check the configuration without making any API requests:
npm run doctorFor a preview configuration, use npm run doctor -- --demo. The doctor checks
the sport, team abbreviation, marker, and target_repo format and reports
several valid team examples when one is unknown.
Preview output without API keys:
SPORT=nba TEAM=LAL node src/index.js --demo
SPORT=mlb TEAM=NYY node src/index.js --demo
SPORT=nfl TEAM=KC node src/index.js --demo
SPORT=nhl TEAM=TOR node src/index.js --demo
SPORT=mls TEAM=MIA node src/index.js --demo
SPORT=epl TEAM=LIV node src/index.js --demo
SPORT=laliga TEAM=RMA node src/index.js --demo
SPORT=bundesliga TEAM=MUN node src/index.js --demo
SPORT=seriea TEAM=INT node src/index.js --demo
SPORT=ligue1 TEAM=PSG node src/index.js --demo
SPORT=primeiraliga TEAM=SLB node src/index.js --demo
SPORT=eredivisie TEAM=AJA node src/index.js --demo
SPORT=wnba TEAM=MIN node src/index.js --demo
SPORT=ligamx TEAM=AME node src/index.js --demo
SPORT=brasileirao TEAM=PAL node src/index.js --demo
SPORT=nwsl TEAM=GFC node src/index.js --demo
SPORT=saudipro TEAM=HIL node src/index.js --demo
SPORT=j1 TEAM=KAW node src/index.js --demo
SPORT=scottish TEAM=CEL node src/index.js --demo
SPORT=belgian TEAM=BRU node src/index.js --demo
SPORT=ucl TEAM=RMA node src/index.js --demo
SPORT=uel TEAM=MUN node src/index.js --demo
SPORT=worldcup TEAM=ARG node src/index.js --demo
SPORT=gleague TEAM=OSC node src/index.js --demo
SPORT=ncaab TEAM=ARIZ node src/index.js --demo
SPORT=ncaaw TEAM=UCONN node src/index.js --demo
SPORT=ncaaf TEAM=ALA node src/index.js --demo
SPORT=ncaa_hockey TEAM=BC node src/index.js --demo
SPORT=f1 TEAM=LP node src/index.js --demo
SPORT=atp TEAM=SIN node src/index.js --demo
SPORT=wta TEAM=SAB node src/index.js --demo
SPORT=nascar TEAM=HAM node src/index.js --demo
SPORT=indycar TEAM=PAL node src/index.js --demo
SPORT=argentina TEAM=RIV node src/index.js --demo
SPORT=aleague TEAM=MCY node src/index.js --demo
SPORT=isl TEAM=BFC node src/index.js --demo
SPORT=csl TEAM=SIPG node src/index.js --demo
SPORT=greek TEAM=OLY node src/index.js --demo
SPORT=austria TEAM=SLZ node src/index.js --demo
SPORT=denmark TEAM=KBH node src/index.js --demo
SPORT=norway TEAM=BODO node src/index.js --demo
SPORT=sweden TEAM=MAL node src/index.js --demoThese ESPN college leagues have large, changing team directories. Use the abbreviation shown by ESPN; the adapter discovers the current team list when needed. Common examples:
| Competition | Sport input | Example team |
|---|---|---|
| NCAA Men's Basketball | ncaab |
ARIZ (Arizona) |
| NCAA Women's Basketball | ncaaw |
UCONN (Connecticut) |
| College Football | ncaaf |
ALA (Alabama) |
| NCAA Men's Ice Hockey | ncaa_hockey |
BC (Boston College) |
The corresponding ESPN directories are men's basketball, women's basketball, college football, and men's ice hockey.
When the action runs in GitHub Actions, it also adds a concise run summary to the job with the sport, team, destination, and whether the README was updated or skipped.
To refresh the generated tables after cloning this repository, run:
npm ci --ignore-scripts
npm run teams:directory
npm run teams:directory:markdown
npm run leagues:examples
npm run leagues:manifestA league is one registry entry plus one adapter file, and the filename has to match
the league key — the action loads adapters with require("./adapters/<key>").
- Add the league to
src/config/leagues.js: key, name, category, endpoint, renderer, emoji, entity, logo, season window, and fallback. This one entry drives the supported-sports table, the manifest, and both generated directories. - Create
src/adapters/<key>.js, extending the base class that matches the data source:BaseSoccerAdapter(soccer),BaseEspnLeagueAdapter(ESPN league endpoints),BaseRacingDriverAdapter(driver standings), orBaseFreeApiAdapterfor a league with its own official API, such as the NHL or MLB. - Add tests under
tests/adapters/, and add a--demoline to the list above so the league is covered by the local preview. - Only if the league needs its own rendering, add a case to
src/renderers/markdown.jsand setrendererin the registry entry to match.
Adapters come in two shapes and both are supported: a class instance
(src/adapters/nhl.js) or a plain object
(src/adapters/nba.js). The base classes supply the contract —
fetchData, getDemoData, getLogoUrl, TEAM_EMOJI, TEAM_IDS, and DEMO_TEAMS —
plus the optional player-spotlight methods.
See CONTRIBUTING.md for the full workflow, including the generated files you may need to refresh.
| Input | Required | Default | Description |
|---|---|---|---|
gh_token |
Yes* | — | Token with Contents: Read and write on target_repo |
sport |
No | nba |
League key (for example, nba). See Supported Sports. |
team |
Yes | — | Team or player abbreviation (e.g. LAL, NYR, MIA, or SIN for Jannik Sinner). Invalid abbreviations show example names. |
player |
No | — | Player full name to feature alongside the team board (e.g. Luka Doncic or Napheesa Collier); must match the roster's exact spelling, including any diacritics. Supported for nba, wnba, ncaab, ncaaw, mlb, nfl, nhl and every soccer league; not supported together with teams: (use team: instead). |
entity |
No | team |
Entity type: team (default) or player. Inferred from the sport — individual sports like ATP Tennis and WTA Tennis default to player. |
teams |
No | — | Comma-separated team/player abbreviations to render multiple boards in one run (e.g. LAL, NYY, ARS). |
title |
No | My Favourite <League> Team |
Custom heading text for the scoreboard (individual sports default to <League> Player). |
badge |
No | false |
Render shields-style badges instead of a full scoreboard block. |
marker |
No | readme-scoreboard |
HTML comment marker name. Must match a marker pair in your README, or the job fails. Give each sport a unique name — sharing one pair means the later step silently overwrites the earlier |
target_repo |
No | your profile repo | Repo to update, format: owner/repo |
dry_run |
No | false |
Fetch and render live data without updating a README. Accepts true/false (also 1/0 or yes/no) |
compact |
No | false |
Use a smaller block without team logos or recent-game details. Accepts true/false |
Inputs are validated before any API request or README update. If a team abbreviation
is not recognized, the action reports several valid abbreviations for that league;
target_repo must use the owner/repository format.
* Required for live remote README updates. Not required in --demo or dry_run mode.
The action exposes outputs for downstream workflow steps:
| Output | Values | Description |
|---|---|---|
updated |
true / false |
Whether the target README changed during this run |
mode |
live, dry-run, preview |
How the action ran |
target_repo |
owner/repo or empty |
Repository selected for the update |
For example, use ${{ steps.scoreboard.outputs.updated }} after giving your
action step the id scoreboard.
Every successful update ends with a small Last updated timestamp. The action
only replaces the README after a successful data fetch, so a temporary API
outage leaves the last known scoreboard in place. The GitHub Actions summary
also reports the data source and generation time.
| Message or symptom | What to check |
|---|---|
TEAM environment variable is required |
Set the team input, or run with --demo for a preview. |
Marker not found |
Add matching start and end marker comments to the target README and use the same marker value in the workflow. |
Could not update README or a permission error |
Confirm GH_TOKEN can read and write Contents in target_repo. |
TARGET_REPO must use the owner/repository format |
Use a value such as 23seriy/23seriy, with exactly one /. |
Unsupported sport or an unknown team |
Check the supported-sports table and use the current abbreviation listed for that league. |
For a safe local check that makes no API requests, run npm run doctor -- --demo.
The repository also runs a daily API health check. It tests every supported league endpoint independently, reports the affected league when a request fails, and continues checking the remaining leagues so one outage does not hide others. A failure report also includes the slowest response time to help spot degradation. The same job verifies every league logo: each one has to resolve, and to match the logo ESPN reports for that league, so neither a broken image nor the wrong competition's artwork reaches these pages unnoticed.
A weekly dependency-health workflow runs the full test suite, lint, and a high-severity security audit. It reports outdated packages without changing the repository automatically.
MIT







































