Privacy
Last updated 11 August 2026
There is no server that knows you. No account, no login, no database of yours anywhere. Your logs are a value in your browser's storage on this device, and the only way they leave is if you export them yourself. The one server this app runs is a stateless relay for data sources that need an API key, or that publish a file too big to hand a phone — it receives your coordinates rounded to about 11 km (anything sharper is refused, in code), holds no state, keeps no logs, and its source is public. Opt-in accounts with encrypted sync are on the roadmap — when they ship, this page changes first, and local-only stays the default.
What stays on your device
Everything you type or tap. Ratings, confounder tags, notes, saved places, settings, the
exposure readings captured with each entry, and the last good air reading kept for offline
use. They live under these keys in this browser's localStorage, plus one
marker in IndexedDB used to notice that the browser wiped the rest:
breathing-index.diary.v1— your entries-
breathing-index.settings.v1— places, sources, your chosen mold counting station, units, usage-ping opt-out breathing-index.lastSeries.v1— the last air reading, for offlinebreathing-index.place.v1— the place name for your coordinates-
breathing-index.pollenHistory.v1— the pollen readings for days already seen, per coarse grid cell, because grass is graded over three days and no source publishes a past one -
breathing-index.smokeHistory.v1— the satellite smoke density for the hours already seen, per coarse grid cell, because the smoke analysis publishes only the latest hour and the app draws the last two days of it -
breathing-index.moldStations.v1— the list of mold counting stations the relay can read, kept for a day so the Settings picker opens without a round trip -
breathing-index.moldHistory.v1— the spore counts for days already seen, per station, because a station publishes one day and replaces it and the count is graded over three of them -
breathing-index.durability.v1,breathing-index.sentinel.v1,breathing-index.banked-day.v1— housekeeping
Clearing site data deletes all of it, permanently, and I cannot get it back for you — I never had it. Settings has an export button. Use it.
No cookies. Nothing here is a cookie, and the app sets none.
What gets sent, and to whom
Four other services see a request from your browser. That is the whole list.
| Open-Meteo | Air quality and weather. Sees your coordinates, rounded to three decimals (about 110 m), and nothing else. |
|---|---|
| The relay |
Pollen forecasts (Google), station measurements (AirNow, US only, off unless you turn
it on in Settings), the satellite smoke map (NOAA HMS, North America), nearby air
sensor readings (PurpleAir) and reference-monitor readings outside the US (OpenAQ)
travel through the relay described above, so those sources see the relay's request,
not your browser — and the relay itself never receives your location sharper than
about 11 km. Its routes are /v1/pollen, /v1/airnow,
/v1/smoke, /v1/purpleair and /v1/openaq, each
taking nothing but those rounded coordinates, plus
/v1/mold/stations and /v1/mold, which take no coordinates at
all. Mold counts come from health departments and hospitals that post a number on a web
page once a weekday morning; you choose a counting station by name in Settings, and the
relay is told that station's id and nothing else. Every reader of that station gets the
same answer, so the request says nothing about which of them you are.
|
| BigDataCloud | Turns those coordinates into the place name in the header. Same rounded coordinates, asked once per location and then cached. |
| Mixpanel | Usage pings — the table below. Off if you turn it off. |
Fonts and icons are served from this domain, so opening the app is not a request to Google or a CDN. There is no ad network, no tag manager, no embedded anything.
Usage pings, exactly
Turn them off in Settings and the analytics code is never even loaded. While they are on, these are the events. No rating, tag, note, place name, coordinate, or pollutant value appears in any of them.
| Page view |
Automatic, on load and on every in-app navigation: the URL path and query string of the
screen (/, /diary, /settings…).
|
|---|---|
| Prediction viewed |
diaryEntries — how many entries your log holds
stale — whether the reading shown was a cached one
locationSource — auto, saved or
default, never which place
|
| Diary entry saved |
coldStart — whether the forecast was still unpersonalized
saveMs — how long the save took
totalEntries — how many entries after it
Not the rating.
|
| Conflict tagged |
kind — superseded or unmodeled-trigger, the type
of card, not the tag you chose
|
| Intro dismissed | choice — location or manual |
| Diary eviction seen | No properties. Records that a browser wiped somebody's logs. |
| Diary restored | entries — how many entries the backup you loaded added |
| Persistence requested |
granted — whether the browser agreed to stop treating your logs as
disposable cache
|
Mixpanel attaches its own defaults to every event: a random device id (not an account), browser and operating system name and version, screen size, referrer, and the current URL. It also records the city, region and country it works out from the network address your request arrives on — the same rough guess any server you contact can make. That is the only geography in a ping. The precise location you grant the app is never sent, and neither is any pollutant value, rating, tag, or note.
What the pings are for: knowing whether people can log an entry and whether anything is broken. Nothing is sold, shared, or joined to anything else. There is nobody to sell it to; this is one person's side project. My own devices tag their pings with a flag so I can subtract myself from the count.
Children
Not directed at children under 13, and since nothing identifying is collected, there is nothing of theirs for me to hold.
Changes
If the app ever sends something new, this page changes in the same commit — that is a rule I hold myself to, not a promise in the abstract. The date at the top is the last time it did.
Contact
Drew Hoover — drewhoover.com. The code is public at github.com/DrewHoo/breathing-index, so you can check any of this rather than take my word for it.