Sync across Chromes
Two sync layers, with a clear divide. The free tier rides on Chrome's own profile sync. Pro adds a butter-hosted cloud sync for harder cases.
butter is built to make "open a new tab on any of my Chromes and see the same dashboard" feel effortless. There are two sync layers — one on by default, one a Pro feature — and a small set of things that intentionally don't sync today.
Layer one: Chrome sync (free, automatic)
Every value stored under butter's sync: storage prefix
rides on
Chrome's built-in
sync — the same system that syncs your bookmarks, autofill, and
open tabs across devices. Three things live in there:
- Layout — every widget on the dashboard, its position, size, and per-instance settings.
- Theme — light / dark / system.
- Background — default / solid hex / gradient ID.
The advantages of riding Chrome sync: no account on our side, no extra signup, no servers we'd need to keep running. The disadvantages: it only works if you're signed into Chrome with sync enabled, and Chrome enforces small per-extension quotas you can theoretically hit if you keep a hundred widgets on a long dashboard.
Most people won't ever touch a quota; if you do, the Pro layer is designed for it.
Layer two: butter cloud sync (Pro, opt-in)
Pro users can turn on cloud sync from Settings → Account once signed in. When on, butter mirrors the same payload (layout + theme + background) to a row in our Supabase database, keyed to your account. Two things this gets you that Chrome sync alone doesn't:
- Cross-browser portability. Sign into butter from a different Chrome profile (or a different machine without Chrome sync enabled) and your dashboard pulls down on first open.
- Conflict awareness. Chrome sync silently last-write-wins. butter cloud sync uses an optimistic, version-checked model — every push includes the version the client last saw, and if another device wrote in between, the server returns the new version and a conflict flag so the client can pull and reconcile instead of clobbering.
How the cloud sync loop works
Once enabled on a device, a small CloudSyncManager sits behind the dashboard and:
- Reconciles on boot. When the new tab opens, it checks the server for a newer version. If found, it pulls the cloud payload and applies it to the local stores.
- Pushes on change. A 1.5-second debounce coalesces rapid edits, so dragging a widget around the grid doesn't burn twenty server versions — only the final position pushes.
- Avoids echo-pushes. While a reconcile is applying cloud state locally, the push loop is paused — so adopting a pulled payload doesn't immediately bounce back up as a new write.
Each device generates a stable per-install ID the first time you turn sync on. The ID is stored locally, never in the synced payload, and only ever shown as a "this was written by your other device" hint around conflict prompts.
What syncs at each tier
The cloud-sync payload is at schema v2. What rides on it depends on which tier of sync you've turned on:
| Data | Chrome sync (free) | Pro cloud sync |
|---|---|---|
| Layout (widgets, positions, sizes, per-widget settings) | Yes | Yes |
| Theme + background | Yes | Yes |
| Todo content (tasks) | No (device-local) | Yes |
| Scratchpad text | No (device-local) | Yes |
| Pomodoro running state | No | No (intentionally) |
| OAuth tokens (GitHub / Linear) | No | No (security boundary) |
| Network response caches | No | No (per-device, refetched on demand) |
| AI Inbox triage cache | No | No (refetched per device) |
Pomodoro state is deliberately device-local even with Pro cloud sync on — sharing a running timer across machines would mean the alarm fires on a Chrome you're not using.
Sign-out behaviour
- Cloud-sync devices stop pushing. Local sync state is wiped on sign-out, so the next sign-in starts fresh (and reconciles from whatever the server has).
- Your data isn't deleted. The cloud row stays — sign back in and it returns. To actually delete it, use the account deletion flow from the Stripe / account portal once Pro is set up.
- Chrome sync is independent. Signing out of butter doesn't affect Chrome's own profile sync — your local layout continues to ride on it.