Cafezuri.ch - Mapping Zürich's Cafés
Description

An index of ~400 cafés inside Zürich's city boundary, built on OpenStreetMap and the city's own open data. No Google, no API keys for the map, and a nightly job that automatically updates and verifies data.

Client
Finished
2026
Services

UX Design

UI Design

Backend Dev

Frontend Dev

DevOps

Collaborators
One page with ~400 cafés and an easy to read timetable

Every café gets a row, and every row carries an hours ribbon with a red line marking the current time. It turns "Is anything open?" into a shape you instantly understand, rather than ~400 strings you have to dig through individually. Opening hours come from OpenStreetMap, where they're written in a genuine little grammar like this Mo-Fr 07:45-16:30; Sa 09:00-16:00, with syntax for public holidays, seasonal rules and "sunset" — which we hand to a real parser rather than a regex we'd regret. 81% of cafés already had them when we did the initial import. A lot of data is still missing on OpenStreetMap though, only 23% have a phone number, which tells you something about what volunteers think is worth recording.

The hardest problem was identity, not data

OpenStreetMap element IDs are not permanent. A mapper can delete a node and re-create it, or promote a point to a building outline. Six of our ~400 cafés are already outlines. Key your votes and editorial scores on node/123 and they silently orphan the first time someone tidies up.

So every café gets a cid of our own, minted once and kept forever, derived from a SHA-256 of the first OSM ID we ever saw so a lost registry regenerates identically. Each refresh reconciles in four passes: Exact ID match, then a fuzzy re-match by name and proximity within 90 m, then mint, then retire. Nothing is ever deleted, which means a café that closes keeps its record, its ID and its URL, because it might come back at a later date.

A bug we enjoyed more than we should have

The fuzzy matcher scores names with Sørensen–Dice over character bigrams. Two distinct one-character names have no bigrams at all, so the denominator is zero and the score is 0/0 — NaN. Both callers rejected weak matches with if (sim < threshold) skip, and every comparison against NaN is false. The guard didn't fail closed, it failed open: Two unrelated cafés could be declared the same shop, one quietly inheriting the other's votes. A threshold that admits exactly what it exists to refuse is a good reminder to test the boundary, not the middle.

Rendering: on demand, cached until it isn't

Café pages render per request on Netlify and sit in the durable cache under a tag per café. When an owner updates their page, we purge that one tag: Their change is live in seconds, no rebuild, and a cache hit bills no function invocation. The index and the static pages are prerendered the ordinary way.

Behind it: Astro as our frontend framework, Supabase as our database with row-level security for the community recommendations, MapLibre GL on swisstopo's vector tiles (free inside Switzerland, no key), and Keystatic as the editor, which commits straight to GitHub, so every editorial decision is a normal commit with a normal diff and a normal author.

The nightly job that does nothing, well

A GitHub Action refreshes from the Overpass API every night. If OpenStreetMap returns the same data twice, the pipeline writes a byte-identical file — timestamps and all — so git diff --quiet exits early: No commit, no deploy, no build minutes. Getting that property right meant not stamping every record with today's date, which is the obvious implementation and the wrong one.

Where OSM is silent, the City of Zürich's licensed catering register fills the gaps: CC0, authoritative for addresses, and good for 103 missing postcodes and 92 missing street names. OSM always wins where both have an answer.

No Google, on purpose

We built against Google Maps (Google Places API) first and removed it entirely almost immediately. Biggest factor was licensing: Google's terms let you display a rating and other information from their API but never store it, which makes an honest offline-capable index awkward to build and impossible to own. Another big factor: When we found a café with the wrong hours there was nothing useful we could do about it. Getting edits accepted on Google Maps is not instant and to be honest, we would just feed the giant more data. In OpenStreetMap you just fix it, and the fix belongs to everyone, the whole community of mappers and every open source project that makes use of the data.

Enjoy your coffee!

You can read our announcement for a less technical post or just click the button below to check out cafezuri.ch, find your next coffee spot or contribute to the open mapper community. Enjoy!

cafezuri.ch
More Projects
OPF - Open Project Framework

OPF - Open Project Framework

A card set for planning digital projects. Each card stands for one deliverable, from the first analysis to ongoing operation. Laid out together, the cards define the scope of a project: transparent, negotiable, open. The card set explains itself: anyone who can read a card can join the conversation. New team members learn the shape and scope of digital projects at the table, not in the wiki. After the introductory workshop, your team runs OPF workshops on its own — or, if you wish, with our support in your client workshops.

2019
Website

UX Design

UI Design

Backend Dev

Frontend Dev

Consulting

fxintell - Blockchain Analytics for Tezos

fxintell - Blockchain Analytics for Tezos

fxintell is an advanced analytics tool for all the Tezos NFT markets, including fxhash, objkt, Versum, Teia/HEN, 8bidou, and typed.

2022
Website

UI Design

Backend Dev

Frontend Dev

Project Management

Lihra - Inspirational Quotes

Lihra - Inspirational Quotes

We've set ourselves the goal to create a simple and fully automated eCommerce website. And since we also wanted a place to collect our favourite quotes, the idea for Lihra was born. Now you can send inspirational postcards for a flat fee all around the world!

2021
Website

UX Design

UI Design

Backend Dev

Frontend Dev

Social Media Management

Content Management

Project Management

Web Publishing

Project Overview