Dev Blog

BLOG

Keeping your sound and display settings the same on every device

While you're signed in, sound, display, and other settings now stay the same on every device using your account. How we split them from settings each device keeps for itself, such as master volume and recording latency, why we only ask when this device and your account disagree, and checking the JSON field by field to reject broken values.

Published October 17, 2026

While you're signed in to Metronome.fm, settings such as your sound and display now stay the same on every device you sign in to with the same account. A sound you pick on your phone is already there when you open the app on your computer.

Until now, only your keyboard shortcut assignments were saved to your account. Everything else lived only in the browser (localStorage). Each time you switched devices, you had to pick your sound, per-sound volumes, beat display, and so on all over again.

That doesn't mean every setting belongs in your account, though. Some settings, like master volume and recording latency correction, are naturally different on each device. This post covers how we split the settings we sync from the ones we keep on each device, and how syncing works.

Settings we sync and settings we keep on each device

We listed every setting the app kept in the browser and sorted each one into "a preference that follows the person" or "something that depends on the device."

Synced (follows you)
Kept on each device (depends on the device)
Sound
Master volume and mute
Per-sound volumes (accent, guide, bass, voice)
Left/right panning
Voice count and count-in
Vibration
Timer and gap click
Starting voice commands with the wake word
Beat display, beat flash, and the order of the buttons in the bar at the bottom of the screen (footer)
Recording latency correction and the camera used for video
Tuner and drone
Drawer width and panel open/closed state
Theme, accent color, and language
Per-room sound timing offset in sync rooms

The rule we used was: "Would the same person want a different value on their phone and their computer?" Sound and beat display are preferences, so they should be the same on every device.

Volume was the one we went back and forth on. Per-sound volumes (such as the balance between accented and normal beats) sync as preferences, and only the master volume stays on each device. Master volume is set to match each device's speakers. A volume you raised on your phone could be far too loud if your computer used it too.

Other settings that naturally differ by device also stay on the device. Recording latency correction is a measured delay from the speaker to the microphone, so it differs per device. Left/right panning depends on what you have connected (such as earphones), and vibration only means something on devices that can vibrate. Starting voice commands with the wake word keeps the microphone in use, and microphone permission is granted per device too. We don't sync any of these, even while syncing.

How the metronome plays right now, such as the tempo and time signature, isn't synced. It would mean writing to your account every time you move the BPM, and using the same setup on another device is already covered by saving a setting with a name (saved settings are stored in your account).

Asking only when settings differ

One option we considered was asking "Sync your settings?" every time you sign in on another device. But right after signing in, you usually want to start playing. We figured a question at that moment would be hard to answer without knowing what happens next, so we cut down the cases where we ask.

The modal shown when settings differ. Number 1 marks the three buttons: use account settings, overwrite with this device's settings, and don't sync this device
The screen shown when this device's settings differ from your account
  1. From the top: use account settings, overwrite with this device's settings, don't sync this device

When you sign in, or come back to the tab or window, the app compares this device's settings (the local settings) with your account's. It checks the rows of this table from the top and uses the first one that applies.

Situation
What happens
The account has no settings yet
Write the local settings to the account
The local and account settings match
Nothing
This device has synced before, and the local settings haven't changed since
Replace the local settings with the account's
This device has synced before, and the local settings have changed since
Write the local settings to the account
First sync on this device, and the local settings were never changed
Replace the local settings with the account's
First sync on this device, and the local settings were changed and differ from the account
Ask which one to use

Only the last row asks you to choose. It mostly appears when an existing user syncs a second device for the first time, or when someone uses the app for a while without signing in and then signs in.

The table tells "were the local settings changed?" in two ways. If this device has synced before, it compares against the settings from the last sync. For that, each device keeps the settings from its last sync as JSON. If the local settings differ from that JSON, they were changed on this device. Settings changed while offline are detected the same way and can be written to your account once you're back online.

On a device's first sync there is nothing to compare against, so it compares with the app's defaults instead. Language is the one exception and isn't compared. Its default comes from the browser's language setting, so it can differ between devices even if you never changed anything.

Choosing per device whether to sync

You can choose for each device whether it syncs. For that, account settings has a Settings sync section. It starts on.

The Settings sync section in account settings. Number 1 marks the on/off switch for syncing settings on this device
The Settings sync section in account settings
  1. Turns syncing on or off for this device. The choice stays on each device

This on/off choice is kept in the browser, not in your account. When you turn syncing back on, the device is treated as if it were syncing for the first time, because both this device and your account may have changed while it was off.

Storing settings in a JSON column and checking each field

Account settings are stored in a single JSON column on the users table in the database. That way we don't need a migration to change the table every time a setting is added.

In exchange, the code has to check that the JSON has the right shape. The same zod schema checks it before writing on the server and after reading in the browser.

// Drop only the fields that don't fit, so one broken field doesn't take the others with it
const item = <T extends z.ZodType>(schema: T) =>
  schema.optional().catch(undefined);

const userSchema = z.object({
  accentVolume: item(z.number().min(0).max(100)),
  beatDisplay: item(z.enum(["meter", "pendulum", "ring"])),
  // …
});

Each field gets .catch(undefined), so only the fields that don't fit are dropped. Say a new version of the app adds another kind of beat display, and an older version of the app, still open on another device, reads that value. If we threw out the whole object, every other setting would fall back to its default. Checking field by field leaves that device's current beat display as it is and still syncs everything else.

Some values change between app versions, such as the order of the buttons in the bar at the bottom of the screen. When a version adds a new button, people who were already using the app start with that button hidden. So the JSON also stores a version number for how the settings were saved, and when it's read, older values go through a step that converts them to the current shape. It's the same step used for the values kept in the browser.

The lists of which settings sync and which stay on the device are written in one place in the code. It's easy to start keeping a new setting in the browser and forget to add it to either list. To catch that, a unit test checks that every field kept in the browser is in one of the two lists.

Waiting 2 seconds and writing once

After you change a setting, the app waits 2 seconds and then writes to your account in one go, because values keep changing while you drag a volume slider. Writes to your account are also capped at 60 per minute per user.

Settings changed on other devices are read again when you come back to the tab or window and when you reconnect after being offline. To avoid reading every time you switch tabs or windows, coming back reads again at most once every 30 seconds.

Share this post

Post on X