News pipeline
The browser never calls third-party news services directly in production. It calls NovaReport's own Cloudflare Worker, which holds the provider keys server-side.
Step by step
- GNews through the Worker (
/gnews), 6-second timeout. If a filtered request (country/language) returns nothing, it is retried once without those filters. - Cooldown: after two consecutive Worker failures, the browser skips the Worker for 60 seconds, then tries again. One-off timeouts do not trigger it.
- Emergency public proxy — disabled by default and must stay off in production. Also requires
VITE_GNEWS_API_KEYto be set; without it the path is skipped even when enabled. - Direct GNews — only on
localhostwithVITE_GNEWS_API_KEYset. - GDELT through the Worker (
/gdelt), with automatic loosening of filters when results are empty. - Cached articles from the Worker (
/api/news/cached, articles it served in the last 14 days), 2-second timeout. The Worker fills this cache itself after answering/gnews,/gdeltand/api/newsdata; the browser never writes to it. - Mock data — only when
VITE_ENABLE_MOCK_NEWS=true. Never presented as live news in production.
When any real provider returns articles (GNews or GDELT), the results may be enriched with a secondary source — NewsData — through the Worker's /api/newsdata, under a 2-second timeout. The NewsData key is a Worker secret. If the Worker has no key it answers configured: false and the browser stops asking for the rest of the session; any other failure also disables the enrichment for the session, so one bad call does not slow every later feed load. Duplicates by URL are removed and results are sorted newest first.
If the Worker cannot be reached at all (or answers that the cache is not set up yet), the cache and NewsData calls pause for 5 minutes at a time. The main feed is not affected by that pause.
Last good answer. GNews (free plan) answers bursts with 429 and GDELT throttles shared traffic, so both can fail at once. For feed requests — top headlines and category pages, never searches — the Worker keeps the last successful answer in Workers KV (rewritten at most every 3 hours, kept 48 hours). When the provider then answers 429 or 5xx, the Worker returns that copy with status 200 and the header X-NovaReport-Stale (when it was saved) instead of the error, so the page shows slightly older stories rather than "Unable to load news".
Debugging
Each request records which provider answered (providerUsed) and whether a fallback was used. In the browser console, window.__NOVAREPORT_NEWS_DEBUG__ shows the last attempts.