How Periodic Background Sync API Works in JavaScript
The Periodic Background Sync API allows Progressive Web Apps (PWAs) to schedule data synchronization tasks that execute periodically in the background, even when the web application is closed. This article explains the technical workflow of the API, covering permission checks, registration with service workers, event handling, and how browsers determine execution timing based on device conditions.
Prerequisites and Browser Conditions
The Periodic Background Sync API cannot be triggered arbitrarily; it requires specific security and engagement conditions before execution:
- Service Worker and HTTPS: The web application must be served over HTTPS and have an active Service Worker registered.
- PWA Installation: Most browsers require the web app to be installed to the device (PWA mode).
- Site Engagement Score: Browsers (such as Chromium-based browsers) use site engagement heuristics. High-engagement sites receive sync events more frequently, while low-engagement sites may have sync execution delayed or denied to preserve battery and mobile data.
Requesting Permission and Registering the Sync Task
To schedule a task, the main JavaScript thread must check for
permission and register a sync tag with a specified minimum interval
using registration.periodicSync.register().
async function registerPeriodicSync() {
const registration = await navigator.serviceWorker.ready;
// Verify that the periodicSync API is supported
if ('periodicSync' in registration) {
const status = await navigator.permissions.query({
name: 'periodic-background-sync',
});
if (status.state === 'granted') {
try {
await registration.periodicSync.register('update-news-feed', {
// Minimum interval in milliseconds (e.g., 24 hours)
minInterval: 24 * 60 * 60 * 1000,
});
console.log('Periodic sync registered successfully.');
} catch (error) {
console.error('Periodic sync registration failed:', error);
}
}
}
}The minInterval parameter specifies the minimum time the
browser must wait before invoking the sync. It acts as a lower bound,
not an exact execution timer.
Handling the Periodic Sync Event in the Service Worker
Once registered, the browser wakes up the Service Worker when
conditions (such as network availability and power state) are met and
fires a periodicsync event.
Inside the Service Worker file, an event listener matches the registered tag and executes the asynchronous task:
self.addEventListener('periodicsync', (event) => {
if (event.tag === 'update-news-feed') {
event.waitUntil(fetchAndCacheLatestNews());
}
});
async function fetchAndCacheLatestNews() {
try {
const response = await fetch('/api/latest-news');
const data = await response.json();
const cache = await caches.open('news-cache-v1');
await cache.put('/api/latest-news', new Response(JSON.stringify(data)));
} catch (error) {
console.error('Background sync failed to fetch data:', error);
}
}The event.waitUntil() method keeps the Service Worker
alive until the returned Promise resolves or rejects, ensuring the
background operation completes before the worker terminates.
Managing and Unregistering Periodic Tasks
To avoid unnecessary background execution, applications can inspect active tags or unregister them when they are no longer required:
async function removePeriodicSync(tag) {
const registration = await navigator.serviceWorker.ready;
if ('periodicSync' in registration) {
const tags = await registration.periodicSync.getTags();
if (tags.includes(tag)) {
await registration.periodicSync.unregister(tag);
console.log(`Periodic sync '${tag}' unregistered.`);
}
}
}Execution Behavior and Constraints
The Periodic Background Sync API does not guarantee exact timing. The browser’s task scheduler evaluates multiple runtime parameters—including battery level, whether the device is on Wi-Fi or cellular data, and user activity—before waking the Service Worker to process scheduled sync events.