Privacy policy for Aperture
https://github.com/dhrupo/aperture/blob/main/PRIVACY.md
Aperture collects nothing. There is no account, no server that Aperture
operates, no analytics, no telemetry, and no error reporting. Every line
below is verified against the source in this repository, not aspirational.
- Settings —
storage.sync, so your browser syncs them across your own
signed-in browsers. This is Chrome's or Firefox's own sync mechanism (both
work the same way here — Aperture callsbrowser.storage.sync, via
webextension-polyfill,
so the exact same code path runs on both, not a Chrome-only feature with a
Firefox afterthought); Aperture has no server in that path at all. If a
sync write fails — sync is capped at 102,400 bytes total / 8,192 bytes per
item, the same limits on both browsers — Aperture falls back to
storage.localso your changes aren't lost, just not synced to your
other browsers; that fallback is still local to your browser, still never
leaves your device, and no third party is ever involved.
(src/lib/storage/sync.ts,saveState()) - Notes, todos, cached and uploaded photos, and any typeface you upload —
IndexedDB, local to the device. Font files in particular are never
uploaded anywhere: the bytes are read from the file you picked, stored
locally, and handed straight to the browser's own FontFace API.
(src/lib/storage/idb.ts,src/lib/photo/cache.ts,src/lib/fonts.ts) - A mirror of your current background and colours —
localStorage, so
the page can paint the right colours before any JavaScript framework has
booted, and a rotation timestamp so a new tab doesn't refetch a photo it
already has cached. (src/lib/storage/mirror.ts,src/widgets/background/index.ts)
Nothing above ever leaves your machine except via your browser's own sync
(Chrome's or Firefox's), which you control from
chrome://settings (Chrome),brave://settings (Brave), or Firefox Account settings (Firefox).Aperture makes no request on install and no request "just for opening a
tab" beyond the one default-on case explained below (Background's Wikimedia
Picture of the Day). Every other request fires only when you take the
specific action next to it, directly from your browser to that service —
Aperture has no backend in the middle.
| Endpoint | Widget | When |
|---|---|---|
|
api.open-meteo.com, geocoding-api.open-meteo.com | Weather | Only after you've set a location (by Detect or by typing a city) — see below ||
get.geojs.io | Weather | Only when you click the Detect button. Never automatic, never on install, never on mount. ||
commons.wikimedia.org (Wikimedia Picture of the Day), falling back to api.openverse.org | Background | Automatically, because Background ships on with source Wikimedia by default — see below ||
upload.wikimedia.org | Background | Automatically, immediately after every successful commons.wikimedia.org request above — that request returns a description of today's photo, not its bytes; the actual image is a second, unavoidable fetch to this separate host, on the same default-on schedule (src/lib/photo/rotation.ts's fetchPhotoBlob, driven by the photo's own thumburl). || An arbitrary third-party image host (Flickr, a museum's own CDN, whatever Openverse indexed for your search) | Background | Only if you switch the source to Openverse, or Wikimedia's automatic Picture-of-the-Day lookup finds nothing for today and falls back to Openverse. This set is not enumerable — Openverse aggregates CC-licensed images from many hosts, and Aperture fetches the photo's actual bytes directly from whichever one indexed it, not through Openverse's own servers. |
|
images.unsplash.com | Background | Only after you've switched the source to Unsplash and supplied your own API key — this is the second, byte-fetching request that follows a successful api.unsplash.com call (see the row below). ||
api.unsplash.com | Background | Only if you switch the background source to Unsplash and supply your own API key. No key ships with Aperture; with none configured, no request is made. ||
icons.duckduckgo.com | Links | On every render of every link you've added (an <img src>, not cached or deduplicated by Aperture — the browser's own HTTP cache is what keeps this from refetching on every single paint) |Weather does not guess your location. It ships enabled, but on first
run — and on every run until you configure a location — it renders a "Set
your location" empty state and makes no network request at all
(
src/widgets/weather/Weather.vue: "mounting with no location configureddoes NOT call coarseLocation() on its own").
get.geojs.io is contactedonly from the explicit Detect button click
(
src/widgets/weather/Weather.vue: "the one place coarseLocation() is evercalled — exclusively from the 'Detect' button"). If you'd rather not use
approximate IP location at all, type a city into "Enter city" instead —
that goes straight to Open-Meteo's geocoding search, never to geojs.io.
Background photos are the one feature that does fetch automatically by
default, and we want to be precise about that rather than silent: the
Background layer isn't a widget you toggle on a slot, it's always present
(
src/newtab/App.vue), and its default source is Wikimedia's Picture of theDay, refreshed at most once a day (
rotateEvery: 'day') and served from alocal IndexedDB cache the rest of the time
(
src/lib/photo/rotation.ts, src/widgets/background/Background.vue). Thatrequest asks only for "today's featured photo" — no location, no query
derived from anything about you, nothing identifying is sent. It is
genuinely two requests, not one:
commons.wikimedia.org's API answerswith the photo's metadata and URL, then Aperture fetches the actual image
bytes from
upload.wikimedia.org — both automatic, both on the sameonce-a-day schedule, both to Wikimedia's own infrastructure. If either fetch
fails (offline, rate-limited, no Picture of the Day for today), Aperture
falls back — first to Openverse (see the endpoint table above), then to the
photo pack bundled in the extension itself — so the page never blocks on the
network.
Switching Settings → Background to Bundled, Solid colour, or
Custom upload stops all background network requests entirely — those
three sources never touch a provider (
Background.vue's applySolid /applyCustomWallpaper, and pickPhoto({ source: 'bundled' })).Editing an unrelated setting can never trigger a request. Every
background field (search query, API key, solid colour, wallpaper name) is
checked against a
FIELD_RELEVANCE table before it's allowed to act —typing into the Unsplash key field while a different source is selected
does nothing, by construction, not by a scattered set of ad-hoc checks
(
src/widgets/background/Background.vue, FIELD_RELEVANCE). This closed areal bug found during development, where an unrelated field could fire a
live request; the fix is table-driven so a new field or source can't
quietly reopen the same hole — see that table's own comment in
Background.vue, and tests/unit/background-vue.spec.ts's exhaustivemismatched-field/source matrix, for the fix in full.
Aperture self-hosts its two typefaces — Inter and JetBrains Mono, both
variable fonts, both OFL-1.1 — as
.woff2 files inside the extension(
public/fonts/inter-variable.woff2, public/fonts/jetbrains-mono-variable.woff2,with their licence files alongside). There is no Google Fonts link, no
external stylesheet, and no remote font request of any kind
(
src/newtab/styles.css's @font-face rules point at local /fonts/...paths only).
You can also add your own typeface (Settings -> Add your own font), and that
path makes no network request either. The file you pick is read in the page,
its bytes are stored in IndexedDB, and it is registered with the document
through the browser's own
FontFace API — there is no upload, no fontservice, and no third party involved at any point. Removing a font deletes
those bytes. (
src/lib/fonts.ts)Aperture ships two manifests —
manifest.config.ts (Chrome/Brave) andmanifest.firefox.config.ts (Firefox) — and both request exactly onepermission:
storage. There is no host_permissions, nooptional_permissions, no tabs, no history, nothing that would leteither build read your browsing activity or the content of any site you
visit.
scripts/verify-permissions.mjs checks both built manifests onevery change, in CI, not just once by hand. You can verify this yourself
too: install from source, open
chrome://extensions (Chrome),brave://extensions (Brave), or about:debugging#/runtime/this-firefox(Firefox) and check Aperture's permissions there, or read either manifest
config file directly.
Firefox's manifest additionally declares
browser_specific_settings.gecko.strict_min_version: "142.0" — Firefox 142is the practical minimum, set by
data_collection_permissions (below),which Firefox for Android gained in 142. Chrome
doesn't support
browser_specific_settings at all, which is exactly whythis is a second, separate manifest rather than one shared file with an
extra field Chrome would ignore.
Aperture's Firefox manifest declares
browser_specific_settings.gecko.data_collection_permissions: { required:
["none"] } — Mozilla's machine-readable statement of what an extensioncollects, required for all new Firefox extensions.
none is the literalanswer here, and everything above is what backs it: no account, no server
this project operates, no analytics, no telemetry, no error reporting, and
exactly one permission. This is the same claim the rest of this document
makes, in the form AMO can check.
Photos from Wikimedia Commons, Openverse, and Unsplash are all
Creative-Commons-or-equivalent licensed, and Aperture displays the title,
author, and licence for the current photo live on the page, linking back to
the source (
src/ui/Attribution.vue) — this isn't just a README credit, therunning extension shows it.
On the page the credit sits behind a persistent info control in the
bottom-right corner and is revealed by hovering it or focusing it from the
keyboard. It is collapsed, not removed: the attribution is always real
rendered content (present in the page's text, exposed to assistive
technology, selectable and copyable), and the full credit additionally
renders as ordinary content inside the settings panel whenever that panel is
open. See
README.md for the bundled photo pack's attributions.Aperture is open source under the MIT licence. If anything above doesn't
match what you observe the extension doing, that's a bug — please open an
issue with the request you saw and we'll fix the code or fix this document,
whichever is wrong.