Skip to main content
Reality Oracle
OverviewCitizensReality FeedVerified ActorsIntel SubscribersMarket PredictionInvestment FundsHow It WorksGates
Products
Backtest ForensicsLiving MapDrift AlertsPath QueriesCustom AxesRisk Maps
Solutions
Compliance OfficersRisk Managers / CROPortfolio ManagersCTOs & Engineering
Enterprise
Enterprise OverviewReality Oracle · SuperappThe AppsArchitectureAudit ManifestTrust CenterPricing
Developers
DocumentationAPI ReferenceSDKsArchitectureAudit Manifest
Resources
BlogUse CasesCustomer StoriesPressChangelog
Company
AboutFoundersCareersContact
Trust
Trust Center
More
PricingJoin Waitlist
··11 min read

AIS: the one streaming source

aisstream.io over WebSocket — the streaming exception, and why it stays an exception.

AIS: the one streaming source

Every source in World Monitor is a poller on a schedule — except one. AIS (ship positions) arrives over a WebSocket stream from aisstream.io, and it is the one streaming source. This post is about why it is the exception, and why it stays the exception.

Every source in World Monitor is a poller on a schedule — except one. AIS (ship positions) arrives over a WebSocket stream from aisstream.io, and it is the one streaming source. This post is about why it is the exception, and why it stays the exception.

Why AIS is different

AIS is a high-frequency positional stream: thousands of vessels, each emitting a position every few seconds. Polling it on a schedule would mean either a very short schedule (which is a polling loop pretending to be a stream) or missing positions between polls (which defeats the point). The honest design is to hold the WebSocket open and ingest positions as they arrive. That is what streaming.rs does — a persistent connection to aisstream.io, positions parsed into GeoSignal values as they land, the cache upserted on every message.

The polling sources are circles on a timeline; the streaming source is a continuous line. One transport is a schedule; the other is a connection held open.
The polling sources are circles on a timeline; the streaming source is a continuous line. One transport is a schedule; the other is a connection held open.

Why it stays the exception

The temptation, once you have one streaming source, is to stream everything. Resist it. A streaming source is a persistent connection — a resource you hold open for the lifetime of the process, with backpressure, reconnect, and partial-failure concerns that a poller does not have. Most feeds do not need it. Flights, quakes, weather, fire, conflict, satellites — these update on a schedule of minutes to hours, and a poller is the simpler, more robust choice. The line is: poll by default, stream only when the cadence demands it. AIS demands it; nothing else currently does.

Poll by default; stream only when the cadence demands it. A persistent connection is a cost you pay for every second you hold it — pay it only when the data rate earns it.

How the stream is bounded

Even the streaming source is bounded. The token-bucket budget that gates the polling sources does not apply directly — the stream is not a request — but the upsert into the Postgres cache is batched, and the GeoPublisher hands deltas on the same per-tile channel structure as the polling sources. A client on the realtime WS does not receive a firehose of AIS positions; it receives the deltas for its viewport tiles, same as every other source. The stream is bounded at the publish layer even when it is not bounded at the ingest layer.

  • One streaming source, one persistent connection — AIS over WebSocket from aisstream.io.
  • Polling is the default; streaming is the exception, earned by cadence, not by preference.
  • The stream is bounded at publish: per-tile channels mean a client gets its viewport, not the firehose.

The operational cost

A streaming source is an operational commitment. The connection drops; you reconnect. The upstream throttles; you back off. The stream stalls; you detect it. Each of these is code in streaming.rs that a poller does not need. That cost is worth paying for AIS, where the cadence makes polling a lie. It is not worth paying for a feed that updates every fifteen minutes, where a poller is simpler, cheaper, and easier to reason about. The discipline is to add streaming sources reluctantly, and only when the data rate leaves no other choice.

A persistent connection is a cost you pay for every second you hold it. The polling sources pay nothing when idle. Know which one you are choosing, and why.

— streaming source design note

What it is not

This is not a claim that AIS data is accurate or complete. It is a feed of positions as reported by vessels; gaps, spoofing, and stale reports are properties of the source, not of the platform. The platform ingests, normalizes, caches, and publishes — it does not verify. Calibration of any forecast that consumes AIS is a separate, gated loop (Gate 1b). We are pre-revenue and building the POC; the stream is wired, and its honesty is that it is a stream of reports, not a stream of facts.

§Keep reading