Live data · public service

Alerts Map — live data that other sites embed

An air-raid alert map where the page is only part of the product. Alerts, moving targets, the front line and thermal points arrive from five independent sources, refresh on their own clocks — 15, 10 and 20 seconds — and leave through an open JSON API and a widget that other websites put into a frame of their own.

I want similarVisit site
Category
Live data · public service
Estimated cost
from €20,000
Refresh
alerts 15 s · targets 10 s · feed 20 s
Sources
five, independent of each other
Stack
PHP 8.3, Python workers, SQLite, Leaflet
map.megainet.art
Alerts Map
Project homepage — map.megainet.art

01Project overview

Alerts Map shows where an air-raid alert is right now: by oblast and by district, with moving targets on the map, the front line, thermal points from satellites and a feed of monitoring channels underneath. It is read by people who need the answer in seconds, and it is read on a phone, at night, on bad mobile internet.

The page, though, is only part of the product. The same data leaves through an open JSON API with keys and rate limits, and through a widget that other websites embed in a frame of their own. We designed and built all of it: the collectors, the storage, the API, the map and the widget.

02Context and the problem

The data that answers «is there an alert here» does not exist in one place. Official alerts come by oblast. Local alerts for communities come from a different service. Where the targets are is written, in words, by monitoring channels. The front line is published by a mapping project. Fires are seen by satellites. Five sources, five formats, five different ideas of what «now» means.

The second problem is silence. Any of those sources can stop — a channel goes quiet, an API starts timing out — and the honest failure mode is to say so, not to keep drawing yesterday’s picture. A map that looks calm because its source died is worse than no map.

03Project goals

  • one picture assembled from five independent sources, each on its own refresh clock;
  • an answer in seconds on a phone, on a weak connection, at night;
  • data that can leave the site: an open API with keys, limits and tariffs, and an embeddable widget;
  • three languages, because the audience is not only local;
  • a source that fell silent must be visible as silent, not as calm;
  • the server’s own address must never reach the sources it reads.

04Five sources, one picture

  • Official alerts by oblast — the backbone of the map;
  • local alerts for communities and districts, from a separate service;
  • monitoring channels in Telegram — read both from public previews and, for closed channels, over the messaging protocol itself;
  • the front line, from a mapping project that publishes it;
  • thermal points from NASA satellites — fires seen from orbit.

Collectors run as two long-lived workers under the system supervisor, each restarted on its own, and write into local storage. The website never talks to a source directly: it reads what the collectors have already written, which is why a slow source makes the map older rather than unavailable.

05Four files instead of one database

The data lives in four separate SQLite files: the alert log, push subscriptions and their per-region state, map events with the feed, and API keys with their rate counters. There is no shared database on purpose — the failure of one file must not take the others down. If push subscriptions are unavailable, the map still draws; if the key store is busy, the page still answers.

The same files are written by the control panel of the whole group — issuing a key, resetting an alert state — so every connection opens with a wait timeout. SQLite gives up instantly on a busy database by default, and «instantly» here would mean an error page while a worker was merely writing a row.

06Three clocks on one page

Different data ages at different speeds, so it refreshes at different speeds: alerts every 15 seconds, moving targets every 10, the feed every 20. One common interval would be wrong in both directions at once — too slow for targets, wasteful for the feed, and a needless request every few seconds for thousands of open tabs.

Each block also carries its own «last updated». A page that redraws silently teaches you to trust it exactly when it should not be trusted; a timestamp that stops moving is the fastest possible way to say «this part is stale».

07An open API with keys and tariffs

The map publishes what it knows: current alerts, events, an analytics endpoint with a heat map of «oblast × time bucket», the rhythm of the day, target types and directions. Anonymous callers get a modest per-minute limit; a key raises it, and the tariffs go up in steps for those who build on it.

Keys are issued from the shared control panel, never typed by hand, and usage is counted per key per day. One endpoint is deliberately closed to everyone but the key’s owner — the one that tells a key its own tariff, limit and consumption. Everything else is open, because a public-service map that hides its data is only half a public service.

08A widget that lives on other people’s sites

The widget is the part of the product that leaves home. Two fixed sizes — a status strip and a square panel — three languages, two themes, and a frame policy written specifically so that embedding is allowed here and nowhere else on the site: the map and the widget may be framed, the account and the support pages may not.

Because it lives in a frame, the widget has no cookies of its own and does not choose an interface generation: it looks the same for everyone. That is a decision, not a limitation — a widget that renders differently depending on a visitor’s previous choices would be impossible to support on someone else’s page.

09Push that knows your region

A subscription is tied to a region, and the state of every region is kept next to the subscriptions. That is what makes a notification arrive on the edge — when the alert in your oblast starts or ends — instead of on every refresh of the source. The difference is the whole product: one is a signal, the other is noise that people turn off within a day.

There is a native application on top of the same data, and it talks to an app API rather than to the web pages. A health endpoint of its own answers the fleet registry, because a liveness check must not be more expensive than the work it checks.

10Three languages, including the widget

The map speaks Ukrainian, English and Russian, and so do the API reference, the account pages and the widget. A new interface string is added to all three at once and a check counts the missing ones: the count has to be zero. Half-translated interfaces do not announce themselves — they quietly show one language inside another and look fine to whoever wrote them.

Region names are a separate story: they come from the sources in their own spelling, so the map keeps a dictionary of its own rather than trusting whatever arrived in the feed.

11Reading sources without showing your address

Everything the collectors fetch goes out through a SOCKS5 proxy, including the messaging protocol used for closed channels — the proxying there is done in code, without an extra dependency. The server’s own address never reaches a source, and a source that decides to block someone blocks the proxy, not the machine that serves the map.

The rate limiter sits in front of the API for the same reason in reverse: a public endpoint with live data attracts scrapers, and a limit per key per minute is what keeps a public service usable for the people it was written for.

12Technology stack

  • PHP 8.3 without a framework: a small router, endpoints and renderers;
  • Python workers under the system supervisor — one on the standard library alone, one speaking the messaging protocol;
  • SQLite, four separate files, each with its own reason to exist;
  • Leaflet for the map, hashed assets, a widget with fixed sizes;
  • web push with per-region state, a native app on the same data;
  • SOCKS5 egress for every outbound request, per-key rate limits in front of the API.

13The result

A map that answers in seconds and keeps answering when one of its five sources stops. Data that other sites can take: an open API with keys and tariffs, and a widget in three languages and two themes. Notifications that fire on the edge of an event rather than on every poll. A native application on the same data, and a control panel where keys are issued and states are reset.

14Takeaways

Three things we would carry to any project with live data. Separate the collector from the page: a website that fetches a source while a visitor waits is a website that goes down whenever the source does. Give every block its own clock and its own timestamp: a single interval is wrong in both directions, and a silent redraw hides staleness. Say when you do not know: an empty block that admits it is worth more than a calm-looking map with yesterday’s data.

And one product lesson: the moment data can be embedded elsewhere, the widget becomes the product. It needs fixed sizes, its own frame policy and translations — the same care as the main page, not a leftover of it.

If you have live data and need a map, an API and a widget that other sites can take, this is the kind of work we do end to end.

What searches this page answers

air raid alert map development, real time map web development, live data dashboard development, embeddable widget for other sites, public json api with api keys, rate limiting api tariffs, sqlite for live data, python workers systemd, telegram channel parser, nasa firms thermal points map, leaflet map application development, web push by region, native app for a web service, map widget iframe embed, how to build a live map service, open data api development, map megainet, alerts map ukraine, air raid alert right now.