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:

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.