Coffee in Zürich
Around 400 Zürich cafés in one index, built on open data rather than Google, and kept current by everyone who edits the map.
I could not remember which cafés near the office were open on a Sunday. Not a serious problem — but the kind nobody ever solves properly, because solving it means collecting four hundred sets of opening hours and then keeping them right.
The Google question
The obvious way to build this is Google Places, and I want to be plain about why I did not.
Google will let you display a rating. It will not let you keep one. Store their data and you are outside the terms, so there is no index to build — only a live window onto someone else's database, rented for as long as the terms happen to stay as they are.
The second reason mattered more. When I found a café listed with the wrong opening hours, there was nothing I could do except report it and wait for someone else to agree with me.
Open data inverts both. A correction is not a support ticket, it is an edit. It lands for everyone reading the same source — this site, the map on somebody's phone, whatever gets built on it next year. That is the whole argument, and it was enough.
What open data actually asks of you
OpenStreetMap hands you the data and the problems with it in the same motion.
Opening hours are not stored as times. They are a small syntax with rules for
holidays, seasons and exceptions, and Mo-Fr 07:45-16:30; Sa 09:00-16:00 wants a
parser rather than a split on the semicolon.
Parsed, they are still unreadable four hundred at a time. So each row carries a ribbon of the day with a red line at the current moment, and the question stops being read this and becomes is the line inside the bar.
Coverage is uneven, and the shape of it is the interesting part: 85% of cafés have an address, 81% opening hours, 69% a website, and 23% a phone number. That is not neglect. It is an honest record of what the people maintaining the map think is worth knowing, and almost nobody thinks that about a phone number.
The identifiers move, too. An element ID in OpenStreetMap is not a promise — restructuring upstream quietly detaches anything keyed to it. Every café carries a stable hash of its own instead, with fuzzy matching to re-link whatever shifted overnight.
Where the map runs out, the city's licensed catering register fills in. It is CC0, so it can simply be used.
Built at a hackathon, with Claude Code
The whole thing came together over a hackathon, written with Claude Code.
Astro renders the pages, MapLibre GL draws the map over swisstopo tiles, Supabase holds the community recommendations, Keystatic handles editing, and Netlify serves it with caching per café.
A scheduled job pulls from OpenStreetMap every night, so it stays current without me. That was rather the point. A directory that needs tending is a directory that rots, and this one is looked after by everybody who edits the map.