Handling offline search with Workbox fallbacks and background sync

Users expect search to work even when connectivity is unreliable. This codelab walks through a demo search app that uses Workbox to handle offline requests, notify users when a query could not be sent, and retry those queries once the connection returns.

Baseline behavior

Start by checking the current state of the app when offline. In Chrome DevTools, open the Network panel and set the throttling drop-down to Offline. Enter a search query in the demo and click Search. The browser shows its standard error page because the request to the server endpoint fails with no fallback in place.

Serving an offline page

The service worker in public/sw.js already adds an offline page to the precache list, so the HTML file is always available from the service worker's install event. In a production setup you would generate this precache manifest at build time with a tool such as webpack or gulp.

Next, register a fallback for any request that fails. Add a default Network Only strategy for all routes, then declare a global error handler with workbox.routing.setCatchHandler(). When a failed request is for a document, return the precached offline HTML page instead of the browser error.

To verify, return the throttling setting to Online, navigate back to the search page, and do an empty cache and hard reload to activate the updated service worker. Switch back to Offline and submit another search; the offline page should now render.

Asking for notification permission

The offline page (views/index_offline.html) contains the logic to request notification permissions. A subscribe to notifications button calls requestNotificationPermission(), which invokes Notification.requestPermission(). The promise resolves with granted, denied, or default, and that value is passed to showOfflineText() to tailor the message shown to the user.

Queuing failed searches with Background Sync

Workbox Background Sync persists failed requests in IndexedDB and retries them when connectivity returns. Add this to public/sw.js:

  • workbox.backgroundSync.Plugin adds failed requests to a retry queue persisted in IndexedDB.
  • maxRetentionTime limits how long a request may be retried; set it to 60 minutes.
  • The onSync callback fires when the connection is restored, retrieving queued requests and fetching them from the network.
  • Store the network response in an offline-search-responses cache, appending the &notification=true query parameter so the entry can be used when the user later opens the notification.

Use a Network Only strategy for requests to the search endpoint at /search_action, passing in the background sync plugin. That makes Workbox always try the network and hand failed requests to the queue.

Requests that arrive by notification should be served from cache. Register a CacheFirst strategy so those responses don't hit the network again. Finally, add the notification display code to the service worker.

Trying the retry flow

With the service worker updated and the throttling set back to Offline:

  1. Submit a search query and click the Search button.
  2. Click subscribe to notifications and allow the permission prompt.
  3. Submit another query while still offline.
  4. Switch the throttling setting back to Online.

When the connection returns, the queued request is replayed and the user sees a notification. Workbox covers this scenario with built-in abstractions over the Background Sync API, so offline queries are not lost and recover automatically. The same pattern applies beyond search forms — chat messages, social posts, and other write operations can share this implementation.