missile-dashboard
March 6, 2026 ยท View on GitHub
Data compiled by the Institute for National Security Studies (INSS), an Israeli think tank affiliated with Tel Aviv University. These figures were widely cited in reports published on Feb 28 - March 5, 2026, by outlets such as The New Arab, Middle East Eye, and CBS News.
Live feed integration
The dashboard now polls /api/live-feed on a 15-minute interval in main.js.
- Copy
.env.exampleto.env. - Set one or more server-side feed URLs:
TARGETS_JSON_API_URLTARGETS_CSV_API_URLTARGETS_HTML_SOURCE_URL(must contain a<table>with rows)
- For full frontend + API locally, run
vercel dev(or runnpm run devfor frontend-only).
Sources are attempted in this order: JSON API -> CSV API -> HTML scraper. If all fail, the UI falls back to the bundled snapshot.
API routes
GET /api/live-feed- Public route used by the dashboard
- Query params:
ai=1includes cached Gemini summaryforce=1bypasses in-memory refresh TTL
GET /api/cron-refresh- Protected with
Authorization: Bearer <CRON_SECRET> - Forces feed refresh, runs Gemini daily fact-check, and returns:
- normalized rows (
factCheck.rows) - citations with dates (
factCheck.citations) - a ready-to-paste
fallbackTargetDataPreviewmodule snippet
- normalized rows (
- Protected with
Vercel cron (free-friendly)
vercel.json is set to run once daily:
0 9 * * * -> /api/cron-refresh
To keep costs lower while still polling every 15 minutes on the frontend:
- keep
VITE_FEED_REFRESH_MINUTES=15 - keep
AI_REFRESH_MINUTES=1440(Gemini once/day cache) - optionally set
DATA_REFRESH_MINUTES=1440if you want source scraping once/day too
Accepted JSON shapes
- Array root:
[{"country":"UAE","drones":941,"ballistic":189,"cruise":8}]
- Wrapped array:
{"data":[...]}{"targets":[...]}{"results":[...]}
Field aliases supported by the normalizer include:
- Country:
country,target,name - Drones:
drones,drone,uav - Ballistic:
ballistic,ballistic_missiles,missiles - Cruise:
cruise,cruise_missiles - Total:
total,count,attacks(or computed from components)
Gemini config
Set:
GEMINI_API_KEYGEMINI_MODEL(default:gemini-3.1-pro-preview)ENABLE_AI_SUMMARY=trueGEMINI_TOPICfor cron topic summary textDAILY_FACTCHECK_SOURCE_URLS(comma-separated trusted source URLs used by daily fact-check)
Daily update workflow (recommended)
- Cron runs once/day (
/api/cron-refresh). - Endpoint fetches trusted source pages from
DAILY_FACTCHECK_SOURCE_URLS. - Gemini returns strict structured JSON (rows + citations + warnings).
- Server validates/normalizes values against your baseline schema.
- Use
fallbackTargetDataPreviewfrom response to updatefallback-target-data.jswhen acceptable.
This keeps fallback-target-data.js as the offline fallback for main.js, while preserving dated citations and structured fact rows from the daily run.