Implementation of Cross-device Sync in Browser Extension
Cross-device sync allows user's extension settings and data to follow them across all their devices where they're logged in with same Google/Microsoft account. This is automatic for chrome.storage.sync in Chrome, but requires explicit implementation in Firefox and Edge.
Chrome: automatic sync
chrome.storage.sync automatically syncs data across Chrome instances of same user:
// background.js
chrome.runtime.onInstalled.addListener(async () => {
const defaults = {
theme: 'system',
highlightColor: '#fbbf24',
shortcuts: {},
};
await chrome.storage.sync.set(defaults);
});
// Listen for sync changes
chrome.storage.onChanged.addListener((changes, area) => {
if (area === 'sync') {
// User signed in on another device and settings synced
reloadUI();
}
});
Limits: 100 KB total, 8 KB per key. Suitable for settings, not bulk data.
Firefox: manual sync via sync API
Firefox doesn't auto-sync storage.sync, but supports WebExtensions Sync:
// background.js
const SYNC_KEY = 'extensionSettings';
async function syncToRemote() {
const settings = await browser.storage.local.get('settings');
// Send to own server or cloud service
await fetch('https://api.example.com/sync', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(settings)
});
}
async function syncFromRemote() {
const response = await fetch('https://api.example.com/sync');
const remoteSettings = await response.json();
await browser.storage.local.set(remoteSettings);
}
// Sync on install and periodically
browser.runtime.onInstalled.addListener(() => syncToRemote());
browser.alarms.create('sync-settings', { periodInMinutes: 60 });
browser.alarms.onAlarm.addListener((alarm) => {
if (alarm.name === 'sync-settings') {
syncFromRemote();
}
});
Cross-browser sync architecture
Unified approach for Chrome, Firefox, Edge:
// shared/sync.ts
export interface SyncProvider {
upload(data: Record<string, any>): Promise<void>;
download(): Promise<Record<string, any>>;
}
export const chromeSync: SyncProvider = {
async upload(data) {
await chrome.storage.sync.set(data);
},
async download() {
return await chrome.storage.sync.get(null) as Record<string, any>;
}
};
export const remoteSync: SyncProvider = {
async upload(data) {
await fetch('/api/sync', {
method: 'POST',
body: JSON.stringify(data)
});
},
async download() {
const res = await fetch('/api/sync');
return await res.json();
}
};
// Select provider based on browser
export const syncProvider = isChromeOrEdge() ? chromeSync : remoteSync;
Timeline
Basic chrome.storage.sync: 1 day. Full cross-browser with remote server: 5–7 days.







