Periodic Background Sync API in JavaScript Explained

The Periodic Background Sync API enables Progressive Web Apps (PWAs) to schedule recurring data synchronization tasks that run in the background, even when the web application is closed. This article covers what the Periodic Background Sync API is, how it works alongside service workers, the JavaScript implementation required to register and execute periodic tasks, and the specific browser constraints governing its execution.

What is the Periodic Background Sync API?

The Periodic Background Sync API allows web applications to periodically fetch fresh data, such as news articles, weather updates, or feed content, in the background. Unlike the standard Background Sync API, which triggers a one-time sync as soon as network connectivity is restored, the Periodic Background Sync API triggers sync events at recurring intervals.

This capability reduces load times by pre-fetching data, ensuring users see updated content immediately upon launching the application.

Prerequisites and Browser Requirements

Because background execution consumes device battery and network data, browsers impose strict requirements before allowing periodic synchronization:

  1. PWA Installation: The application typically must be installed on the user’s device as a PWA.
  2. Site Engagement Score: Browsers (such as Chromium-based browsers) use a Site Engagement score to determine if the user interacts with the app frequently enough to justify background resource usage.
  3. HTTPS: The site must be served over a secure HTTPS connection (or localhost for development).
  4. Permissions: The user or browser must grant the periodic-background-sync permission.

How JavaScript Schedules Recurring Tasks

Scheduling a periodic task involves two main parts: requesting permission and registering the task in the main application script, and handling the event inside the service worker.

1. Check for Support and Register the Task

In your main application JavaScript file, verify that the browser supports the API, check permissions, and register a periodic sync tag with a minimum interval.

async function registerPeriodicSync() {
  const registration = await navigator.serviceWorker.ready;

  // Check if Periodic Background Sync is supported
  if ('periodicSync' in registration) {
    // Check permission status
    const status = await navigator.permissions.query({
      name: 'periodic-background-sync',
    });

    if (status.state === 'granted') {
      try {
        // Register periodic sync with a tag and minimum interval (in milliseconds)
        await registration.periodicSync.register('update-latest-news', {
          minInterval: 24 * 60 * 60 * 1000, // 24 hours
        });
        console.log('Periodic background sync registered successfully.');
      } catch (error) {
        console.error('Periodic background sync registration failed:', error);
      }
    } else {
      console.log('Periodic background sync permission not granted.');
    }
  } else {
    console.log('Periodic Background Sync is not supported by this browser.');
  }
}

2. Handle the Event in the Service Worker

Once registered, the browser fires the periodicsync event inside your service worker based on the specified interval and device conditions.

// service-worker.js

self.addEventListener('periodicsync', (event) => {
  if (event.tag === 'update-latest-news') {
    event.waitUntil(fetchAndCacheLatestNews());
  }
});

async function fetchAndCacheLatestNews() {
  try {
    const response = await fetch('/api/news/latest');
    const data = await response.json();
    
    const cache = await caches.open('news-cache-v1');
    await cache.put('/api/news/latest', new Response(JSON.stringify(data)));
    console.log('Background sync completed: News cache updated.');
  } catch (error) {
    console.error('Failed to update news in background:', error);
  }
}

Managing Registered Tags

You can inspect and remove registered sync tasks using the getTags() and unregister() methods on the periodicSync manager.

Retrieve Active Sync Tags

const registration = await navigator.serviceWorker.ready;
if ('periodicSync' in registration) {
  const tags = await registration.periodicSync.getTags();
  console.log('Active periodic sync tags:', tags);
}

Unregister a Sync Tag

const registration = await navigator.serviceWorker.ready;
if ('periodicSync' in registration) {
  await registration.periodicSync.unregister('update-latest-news');
  console.log('Periodic sync tag removed.');
}

Important Execution Behavior

The minInterval parameter is only a suggested minimum value. The browser does not guarantee exact timing like a traditional setInterval or server-side cron job. The actual execution frequency is dynamically calculated by the operating system and browser based on: