Skip to content

Periodic background sync for updates: refreshing content vs. notifying about it

In one line: Periodic background sync lets an installed PWA’s service worker periodically refresh content in the background, so the app already has fresh data ready when the user opens it — a silent update, distinct from a push notification, which is a visible, user-facing alert about new content.

Both APIs run in the service worker and both deal with “there’s something new,” but they serve different jobs:

  • Periodic background sync downloads data quietly, on a browser-decided schedule, so the app’s own UI is current the next time it’s opened. There is no notification and no guarantee of exactly when it runs.
  • Push notifications (via the Push API) deliver a message from the server that is meant to interrupt the user, typically by calling showNotification() to display a visible alert.

A common pattern is to use periodic background sync for routine content refresh, and reserve push notifications for updates important enough to justify interrupting the user — not every periodic refresh needs an accompanying notification.

ServiceWorkerRegistration.periodicSync exposes a PeriodicSyncManager:

const registration = await navigator.serviceWorker.ready;
if ('periodicSync' in registration) {
try {
await registration.periodicSync.register('refresh-feed', {
minInterval: 24 * 60 * 60 * 1000,
});
} catch {
console.log('Periodic Sync could not be registered.');
}
}

In the service worker, a periodicsync handler checks event.tag and refreshes the relevant data, optionally showing a notification only when the new content warrants one:

self.addEventListener('periodicsync', (event) => {
if (event.tag === 'refresh-feed') {
event.waitUntil(
refreshFeedCache().then((hasImportantUpdate) => {
if (hasImportantUpdate) {
return self.registration.showNotification('New content available');
}
})
);
}
});

MDN marks PeriodicSyncManager and ServiceWorkerRegistration.periodicSync as experimental and of limited availability because they do not work in some of the most widely used browsers. Check the browser compatibility data carefully before using them in production.

Availability is gated by install and engagement

Section titled “Availability is gated by install and engagement”

Per Chrome’s documentation, periodic background sync is only available to a web app the user has installed and launched as a distinct application — it does not work in a regular browser tab — and access is further gated on the user’s engagement with that installed app, so that rarely-used installs don’t consume battery or data in the background.

async function scheduleContentRefresh(tag, minInterval) {
const registration = await navigator.serviceWorker.ready;
if (!('periodicSync' in registration)) {
// Not available in this browser/context — fall back to refreshing
// on page load instead of in the background.
return false;
}
await registration.periodicSync.register(tag, { minInterval });
return true;
}
  • Feature-detect with 'periodicSync' in registration before calling register().
  • Only rely on it for installed, launched PWAs — it is unavailable in a plain browser tab.
  • Pass a realistic minInterval; the actual sync interval will be at least that value, but the browser may sync less often based on engagement and other signals.
  • Reserve showNotification() calls from the periodicsync handler for updates genuinely worth interrupting the user — not every background refresh.
  • Have a fallback refresh path (e.g. on page load) for browsers or contexts where periodic background sync is unavailable.