Skip to content

Privacy and data exposure

This page exists because "share your fleet data with a network" is a sentence that ends most evaluations. Here is exactly what leaves your building and what does not.

Relay stores no trajectories

A road event is a point observation with an expiry. No published event carries a vehicle identifier, a session, a sequence or a path. Nothing in the contract can express "this vehicle then went there".

  • A published event carries lat/lon — a single reference point.
  • A geometry describes the extent of the hazard (a 40 km queue, a stretch of black ice), never the movement of a vehicle.
  • Reporter positions on a confirmation (lat/lon in a signal) are a single point, optional, and never published — they are internal evidence for a future trust weighting.

No published event has a field for a vehicle id, a driver, a plate, a VIN, a device id or a user. The inbound wire accepts exactly one vehicle-shaped field, and it stops at our door: reporter_token, your own opaque name for the vehicle that saw or confirmed an event, which is what the trust quorum counts. It is salted with your organisation id on arrival; the raw value is never stored, and neither the salted id nor anything derived from it appears in any API response — only counts are public. See Trust, and Retention below for what the salted id is kept on. Adding a published identifier would be an additive wire change and it is not planned; if it ever happened it would be a documented change to this page, not a quiet one.

Coordinates are rounded to 5 decimals (~1 m) on write. That is key-space normalisation, not a privacy measure — do not present it as one. The privacy property is the absence of trajectories, not coordinate fuzzing.

Your organisation id never leaves, and neither does a stand-in for it

Published events carry no publisher identity at all:

stored internally      org_id = "org_acme"
published on the wire  (nothing)

There was an intermediate design, and it is worth knowing why it went. publisher_id was a pseudonym derived from your org_id and stable forever, so consumers could group events by source. Stable forever is exactly the problem: a pseudonym that never changes is a map of your fleet's coverage missing only its label, and one publicly known incident of yours attaches the label. Grouping by it over an 8 km radius gave relative fleet density per operator, for free, to anyone with a key. It was removed in schema_version 2, before the first integration, which was the last moment removing a published field was possible.

What this does not fix, stated plainly. Your publishing behaviour is still yours: cadence, the areas you cover, which event types you emit, how long your geometries run. Somebody with those events and a data team can cluster them into sources without any identifier from us. The precise claim is that correlation now costs real work and yields a hypothesis, where before it was a labelled map served on request. If your client_event_id values are guessable (1, 2, incident-42), note that event_id is derived from them and your org_iduse opaque ones and that path closes too.

org_id is in our datastore and our analytics warehouse — the trust model, the signal keys and contribution metering all need the real identity. It is in no API response. There is no field, no header, no query parameter, no debug mode that returns it.

What this prevents. GET /v1/events used to hand every consumer a real-time, machine-readable map of a named telematics editor's fleet coverage — readable by that editor's direct competitor, at scale, for free. source_kind and feed_id already tell a consumer what it legitimately needs (a network event versus an ingested public feed); a nominative id at event granularity delivered something else entirely.

This change was made before the first integration, which was the last moment it was possible: removing a published field otherwise breaks the additive rule. Nothing of the kind will happen inside /v1 again.

Not a marketing summary. Bring these to counsel exactly as written, because "no identifier" invites the wrong paraphrase into "anonymous".

  1. No published field identifies your organisation — not org_id, and, since schema_version 2, no pseudonym either. publisher_id was the intermediate design described above, and it is gone.
  2. We can identify you internally, and nobody else on the network can — Datastore and BigQuery keep the real org_id, and it is in no API response, header, query parameter or debug mode.
  3. This is correlation friction reduced to zero identifiers, not anonymity — behavioural fingerprinting and a guessable client_event_id still let a third party cluster your events into a source, at the cost described above ("What this does not fix"). Say "no identifier"; never say "anonymous" — that word claims something we do not deliver.

What is public about your events

Everything in the event object is visible to every authenticated consumer. Concretely, a consumer reading an area you publish into learns:

  • what kind of hazard, where, when, in which direction, how severe, and your free-text description;
  • that it came from a network participant rather than a public feed;
  • how many reporters — vehicles, not organisations, since schema_version 2 — have confirmed or denied it.

It does not learn your name, your org_id, your client_event_id, how many vehicles you run, where else you are publishing at that moment, or anything about a vehicle.

description is free text you control. It is published verbatim, capped at 280 characters. Do not put an internal reference, a driver name, a plate or a customer identifier in it — nothing strips them, and the field is not the place for data you did not mean to publish.

Attribution, if you want it

A partner who wants the credit — "powered by X" — is a real and good case. It comes back later as an additive, opt-in field, never as a reversal of the no-publisher-identity decision above.

It needs a claimed, unique, moderated namespace, which means a registry; the field does not exist on the wire, and it arrives as a designed addition, never a side effect. A publisher-chosen public handle was rejected outright: an organisation that can set the string consumers read as who published this can set it to a competitor's name, which plants an impersonation vector in the one layer whose entire job is anti-poisoning.

Retention

  • Operational store — the live event set. Events are deleted after expiry; physical cleanup is best-effort and typically completes within 24 hours of the TTL. Expired events stop being served immediately regardless.
  • Analytics — one row per event state change, and one row per confirmation or denial, are mirrored to a warehouse, both keyed on the real org_id of the organisation that acted, and retained. A signal row also carries the salted reporter id — never the raw reporter_token — with the action, the reporter's optional position and the timestamp: it is the record that lets a minted fleet be told apart from a real one. Neither table is ever on the read path or exposed by any API route. They exist for contribution metering — publishing and confirming both count.
  • API keys — stored as a SHA-256 hash. The plaintext is never persisted anywhere.
  • Stream tickets — one row with an expiry, physically cleaned up on the same best-effort TTL.

There is no data-deletion API in v1. Events age out on their own; anything else is an operator action.

For your compliance review

  • DPAs, retention commitments and certifications are handled per agreement. Raise them in the contract conversation rather than inferring them from this page.
  • The wire has no publication-history query. The Console gives each organisation an append-only audit log of its own account actions — key issuance, revocations, membership changes, named by actor. The wire itself is not covered: what you published is retained on our side (see Retention above) and is not queryable back through any API.