# Privacy Policy — Transit Project

**Last updated: 10 August 2026**

> **Not legal advice.** I'm not a lawyer. This is written to be accurate about
> what the code actually does, which is a necessary start and not a substitute
> for review. You are charging money and selling into the EU, so have someone
> qualified read it.

---

## Who is responsible for your data

Transit Project is operated by **Jack Edlavitch**, contactable at
**info@transitproject.online**. Under UK/EU data protection law that is the
"data controller" for everything described below.

## The short version

Transit Project is three things, and they have genuinely different answers, so
this policy treats them separately rather than averaging them into one
reassuring paragraph.

- **The city boards** — the product most people buy. No account, no server of
  ours involved at all. Your location stays in your browser. It is sent to
  transit agencies only in order to ask them what is near you.
- **Buying a licence** — Stripe takes the payment. We keep your purchase email
  and a random identifier per device, only to reissue your key and to count the
  five devices your licence covers.
- **The Spotter app** — optional. Signed out, nothing leaves your phone. Signed
  in, your sightings sync between your devices.

There is no advertising, no analytics, no tracking, and nothing is sold to
anybody. That is not a promise about intentions; there is no analytics code in
the site to switch on.

---

## 1. The city boards

A board is a web page that runs entirely in your browser and talks straight to
transit agencies. There is no server in between that we operate.

### What stays on your device

Held in your browser's local storage, readable only by this site, and never
transmitted to us:

- the location you set, as an address and coordinates
- your display settings — theme, which cards you show, row density
- your licence key and a random device identifier (see §2)
- anything the Spotter has logged, unless you sign in (see §3)

Clearing the site's data in your browser erases all of it. There is no copy.

### What leaves your device, and who receives it

Drawing a live board means asking other people questions, and the questions
contain your location. Specifically:

| Who | Why | What they receive |
|---|---|---|
| The transit agency for your city — WMATA, MTA, SEPTA, MBTA, BART, NJ Transit, LA Metro, transitous and others | Next departures and vehicle positions near you | Your approximate coordinates, and your IP address |
| **adsb.lol** | Aircraft overhead | Your approximate coordinates, and your IP address |
| **amtraker** | Amtrak train positions | Your IP address |
| **adsbdb** | Which route a flight is on | The flight's callsign, not anything about you |
| **CARTO** (`basemaps.cartocdn.com`) | The map background | Your IP address, and which map areas you view |
| **OpenStreetMap Nominatim** | Turning a typed address into coordinates | The address or coordinates you look up |
| **planespotters.net**, **Wikimedia Commons** | Photographs of aircraft and trains | The aircraft or line being shown |

This is unavoidable rather than a design choice: "what is near me" cannot be
asked without saying where you are. Each of these is a direct request from your
browser to them, under their own privacy policies, and we neither see nor keep a
copy.

**We do not receive your location.** Nothing in the list above reports back to
us, and there is no endpoint of ours for it to report to.

---

## 2. Buying a licence

### Payment

Payment is handled entirely by **Stripe**. Card details go from you to Stripe;
they never touch this site and we never see them.

### What we store, and why

When a purchase completes, our licence server records, against your licence key:

| What | Why | How long |
|---|---|---|
| The email address you gave Stripe | So a lost key can be reissued to the person who bought it | Until you ask us to delete it |
| Your Stripe checkout session id | So the same purchase cannot claim two keys, and so a support request can be matched to a real payment | Until you ask us to delete it |
| A random identifier for each device you activate, and when it was last seen | To enforce the five-device limit the licence is sold with | Until you ask us to delete it |

**The device identifier is not a fingerprint.** It is sixteen random hexadecimal
characters generated by your own browser the first time you activate, stored
locally, and meaningless anywhere else. It identifies a browser profile as "one
of the five", and nothing more. It tells us nothing about your device, and two
people with identical hardware get different values.

Checking a licence sends your key and that identifier to our licence server,
which — like any web request — also sees your IP address. We do not log it.

### The feed relay

Licensed boards can be configured to fetch their live data through a relay we
run, so that a licence is required for live data rather than only for the
interface. Where that is in use, the relay sees your IP address and which feed
you asked for. It does not store either, and it is not part of the boards
today — this section is here because it is wired into the product and may be
switched on.

---

## 3. The Spotter app

The Spotter is a separate phone app for logging vehicles you have seen. **It
works fully without an account**, and signed out nothing about you ever leaves
your device: sightings live in your browser's local storage and we cannot see
them.

If you choose to sign in, we store:

| What | Why | How long |
|---|---|---|
| Your email address | To sign you in and send sign-in codes | Until you delete your account |
| Your sightings — vehicle, route, place, note, and **the location where you logged it** | To sync your log between your devices | Until you delete them, or your account |
| A session token | To keep you signed in | About 13 months, then it expires |
| Temporary sign-in codes | To verify it is you | 15 minutes |
| **A password, if you choose to set one** | So you can sign in without waiting for an email | Until you change or remove it, or delete your account |
| Rate-limiting counters, tied to a hashed email or IP | To stop abuse of the sign-in system | Up to 1 hour |
| If you sign in with Apple, a mapping from Apple's identifier for you to your address | Apple only sends the address the first time; without this you would land in a new empty account on every later sign-in | Until you delete your account |

**Your location history deserves calling out.** A sighting can include the
coordinates where you logged it. Taken together, that is a record of places you
have been. It is only ever stored if you are signed in, only ever readable by
your own account, and never shared.

**About passwords.** You do not need one — you can sign in with an emailed code,
or with Google or Apple, and never set one at all. If you do set one, we store
only a salted PBKDF2-SHA256 hash of it, never the password itself, and you can
remove it again at any time from **Your account**. We would still rather you used
a password manager and a password you use nowhere else.

**If you sign in with Google or Apple**, we receive your email address and
whether they have verified it, and nothing else. We do not receive your Google or
Apple password, and we cannot see anything else in those accounts. Using those
buttons does tell Google or Apple that you use this product — if you would rather
not, sign in with an emailed code instead. Apple's **Hide My Email** works here:
we will only ever see the relay address Apple invents for us.

---

## Who else is involved

| Service | Used for | What it sees |
|---|---|---|
| **Cloudflare** | Runs our licence and account servers | Licence keys, device identifiers, purchase emails, account data, IP addresses |
| **Stripe** | Takes payment | Your name, email and payment details — we receive only the email |
| **Resend** | Sends sign-in code emails | Your email address |
| **Google** | Only if you press "Continue with Google" | That you signed in to this product, and when |
| **Apple** | Only if you press "Continue with Apple" | That you signed in to this product, and when |
| **GitHub Pages** | Serves the site itself | Your IP address, as any web host does |
| Transit agencies, adsb.lol, amtraker, adsbdb, CARTO, Nominatim, planespotters.net, Wikimedia | Live data, maps and photographs | See the table in §1 |

The last row applies **whether or not you have an account or a licence**,
because a board cannot draw a map or find your next train without asking
somebody.

## Your rights

You can ask at any time to:

- **See** everything we hold about you
- **Correct** anything wrong
- **Delete** your account, your licence record, or both
- **Export** your data — the Spotter also has built-in CSV and JSON export
- **Object** to how we use it, or withdraw consent

Email **info@transitproject.online**. We will respond within 30 days. If you are
in the UK or EU you may also complain to your data protection authority.

**To delete most of it yourself:** clear the site's data in your browser. That
removes your location, settings, licence key and device identifier. The
server-side records described in §2 and §3 need an email to us.

## Children

Not intended for children under 13, or under 16 in parts of the EU. We do not
knowingly collect their data. If you believe a child has given us information,
email us and we will delete it.

## Where the data lives

On Cloudflare's global network and GitHub's, which means data may be stored or
processed outside your country, including in the United States.

Where data is transferred out of the UK or European Economic Area, the transfer
relies on the **Standard Contractual Clauses** in the data processing agreements
published by our processors — Cloudflare, which runs the servers, and Resend,
which sends sign-in emails.

## Security, honestly stated

Sign-in codes and session tokens are stored hashed, and account identifiers are
derived from a salted hash of your email rather than the address itself. Licence
keys are cryptographically signed rather than guessable. Passwords — which are
optional, and which many accounts will not have — are stored only as a salted
PBKDF2-SHA256 hash at 100,000 rounds, never in a form we could read back.

Being straight about the trade: an earlier version of this system had no
passwords at all, and that was genuinely safer. Passwords were added because
waiting on an email to log a train you can see is a poor way to use an app. If
that trade is not one you want, do not set a password — everything still works
without one.

That said: no service is perfectly secure, and this one is run by an individual
rather than a security team. If we discover a breach affecting your data we will
tell you and the relevant regulator within 72 hours.

## Changes

If this policy changes in a way that matters, we will say so on the site before
it takes effect.

---

## Notes for the operator — delete this section before publishing

1. **Confirm the controller name.** Written as a natural person. If you trade
   through a company, that company is the controller and §"Who is responsible"
   must say so.
2. **The EU/UK transfer wording claims Standard Contractual Clauses, so go and
   accept them.** You ship Amsterdam, Cologne and Stuttgart boards, so EU
   customers are the target rather than a hypothetical. Accept Cloudflare's DPA
   (dashboard → account settings) and Resend's; both incorporate the SCCs. Until
   you do, that paragraph describes something that is not true.
3. **Check the map and geocoding terms — this is now urgent, because the product
   is paid.** Nominatim's usage policy is aimed at low-volume, non-commercial
   use and a paid kiosk geocoding on every location change can breach it.
   Map tiles moved off CARTO in September 2026, when it began requiring an API
   key for its raster basemaps and watermarking unauthenticated tiles; its free
   tier was non-commercial anyway. Esri's Canvas basemaps need no key, and their
   attribution is drawn by basemap.js.
4. **There is still no route to delete an account or a licence record.** Neither
   Worker has a `/delete` endpoint, so a right-to-erasure request means editing
   KV by hand. The policy above promises deletion within 30 days; keep that
   promise manually until it is built, and build it before volume makes that
   impossible.
5. **The feed relay section is written as "may be switched on".** When
   feed-proxy-worker.js is deployed and `feedProxy` is set in config.js, remove
   that qualifier — at that point every board's live data goes through it and
   the relay genuinely does see every viewer's IP.
6. **Link this from the home page, buy.html and the Spotter's settings.** A
   privacy policy nobody can find does not count. It is currently only linked
   from the home-page footer.
7. You may also need a record of processing activities if you sell into the
   EU/UK.
