Skip to content

Send User-Agent on schedule fetches to avoid Akamai 403 - #225

Closed
gerber55555 wants to merge 1 commit into
dathbe:masterfrom
gerber55555:fix/schedule-403-user-agent
Closed

Send User-Agent on schedule fetches to avoid Akamai 403#225
gerber55555 wants to merge 1 commit into
dathbe:masterfrom
gerber55555:fix/schedule-403-user-agent

Conversation

@gerber55555

Copy link
Copy Markdown

Problem

The Upcoming Games section silently renders empty for some users. The per-team schedule endpoint (site.api.espn.com, Akamai edge) now returns 403 for requests without a User-Agent header — Node's fetch sends none by default. Every getTeamSchedule call fails, the error is caught, and null is cached per team, so the section just shows nothing.

Notes from debugging on a Raspberry Pi:

  • Requests with no UA → 403
  • Requests with a spoofed browser UA → also 403 (Akamai fingerprints TLS; a Chrome UA on a Node TLS stack reads as a bot)
  • Honest non-browser UAs (curl/7.74.0, MMM-MyScoreboard (...)) → 200
  • Behavior varies by edge/region: the same UA-less request succeeds from one network and 403s from another, so not everyone is affected
  • The scoreboard host (site.web.api.espn.com) is different infrastructure and unaffected — live scores keep working, which makes this failure easy to miss

Fix

Send an honest module User-Agent on schedule fetches:

User-Agent: MMM-MyScoreboard (+https://github.com/dathbe/MMM-MyScoreboard)

Also extends the fetch mock to record request init (fixing an unrelated latent bug where the setError wrapper dropped the init argument) and adds a regression test asserting the header is sent.

Testing

  • 114 unit tests pass, curated e2e suite passes
  • Verified live on a Pi that previously 403'd: schedule fetch returns 200 and the Upcoming Games section renders again

🤖 Generated with Claude Code

site.api.espn.com (the per-team schedule host used by the Upcoming Games
feature) sits behind Akamai bot protection that now rejects requests
without a User-Agent header — Node's fetch sends none by default, so
every getTeamSchedule call returned 403 and the Upcoming Games section
silently rendered empty. Spoofed browser UAs are also rejected (TLS
fingerprint mismatch); an honest non-browser UA passes.

The scoreboard host (site.web.api.espn.com) is different infrastructure
and unaffected, which is why live scores kept working.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dathbe

dathbe commented Aug 7, 2026

Copy link
Copy Markdown
Owner

I had the same issue with MyStandings. This module was working for me, so I didn’t mess with it. But I’m unsurprised it popped up here too. Will review and merge.

@gerber55555

Copy link
Copy Markdown
Author

I had the same issue with MyStandings. This module was working for me, so I didn’t mess with it. But I’m unsurprised it popped up here too. Will review and merge.

Yea it's only with the upcoming games (schedule), the live scoreboard uses a different endpoint so it doesn't have that issue.

@dathbe

dathbe commented Aug 9, 2026

Copy link
Copy Markdown
Owner

Fixed with #226

@dathbe dathbe closed this Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants