diff --git a/front/src/App.vue b/front/src/App.vue
index 0a918a7c130832d00e86126a450f6e9e9c187ba2..5417a07e14fcdbbfac810ee2e55da025d1ce23c3 100644
--- a/front/src/App.vue
+++ b/front/src/App.vue
@@ -263,7 +263,7 @@ export default {
     updateApp () {
       this.$store.commit('ui/serviceWorker', {updateAvailable: false})
       if (!this.serviceWorker.registration || !this.serviceWorker.registration.waiting) { return; }
-      this.serviceWorker.registration.waiting.postMessage('skipWaiting');
+      this.serviceWorker.registration.waiting.postMessage({command: 'skipWaiting'})
     }
   },
   computed: {
@@ -317,9 +317,16 @@ export default {
     },
   },
   watch: {
-    '$store.state.instance.instanceUrl' () {
+    '$store.state.instance.instanceUrl' (v) {
       this.$store.dispatch('instance/fetchSettings')
       this.fetchNodeInfo()
+      if (this.serviceWorker.registration) {
+        let sw = this.serviceWorker.registration.active
+        if (sw) {
+          sw.postMessage({command: 'serverChosen', serverUrl: v})
+
+        }
+      }
     },
     '$store.state.ui.theme': {
       immediate: true,
diff --git a/front/src/registerServiceWorker.js b/front/src/registerServiceWorker.js
index a182d037429278d58e9a7e718ac4beb51f9d46c0..4998b6bca57735db0727bac7ab78b1b42ac3c71f 100644
--- a/front/src/registerServiceWorker.js
+++ b/front/src/registerServiceWorker.js
@@ -6,13 +6,10 @@ import store from './store'
 
 if (process.env.NODE_ENV === 'production') {
   register(`${process.env.BASE_URL}service-worker.js`, {
-    ready () {
+    ready (registration) {
       console.log(
-        'App is being served from cache by a service worker.'
+        'App is being served from cache by a service worker.', registration
       )
-    },
-    registered (registration) {
-      console.log('Service worker has been registered.')
       // check for updates every 2 hours
       var checkInterval = 1000 * 60 * 60 * 2
       // var checkInterval = 1000 * 5
@@ -20,6 +17,13 @@ if (process.env.NODE_ENV === 'production') {
         console.log('Checking for service worker update…')
         registration.update();
       }, checkInterval);
+      store.commit('ui/serviceWorker', {registration: registration})
+      if (registration.active) {
+        registration.active.postMessage({command: 'serverChosen', serverUrl: store.state.instance.instanceUrl})
+      }
+    },
+    registered () {
+      console.log('Service worker has been registered.')
     },
     cached () {
       console.log('Content has been cached for offline use.')
diff --git a/front/src/service-worker.js b/front/src/service-worker.js
index 6fc563f72b0f3d8bb8aecf2a625b9420abb0d20e..c1bc1804d0432c599a3892e88c9109e7c224c803 100644
--- a/front/src/service-worker.js
+++ b/front/src/service-worker.js
@@ -1,14 +1,20 @@
 // This is the code piece that GenerateSW mode can't provide for us.
 // This code listens for the user's confirmation to update the app.
+workbox.loadModule('workbox-routing');
+workbox.loadModule('workbox-strategies');
+workbox.loadModule('workbox-expiration');
+
 self.addEventListener('message', (e) => {
   if (!e.data) {
     return;
   }
-
-  switch (e.data) {
+  console.log('[sw] received message', e.data)
+  switch (e.data.command) {
     case 'skipWaiting':
       self.skipWaiting();
       break;
+    case 'serverChosen':
+      self.registerServerRoutes(e.data.serverUrl)
     default:
       // NOOP
       break;
@@ -18,7 +24,7 @@ workbox.core.clientsClaim();
 
 // The precaching code provided by Workbox.
 self.__precacheManifest = [].concat(self.__precacheManifest || []);
-console.log('Files to be cached by service worker [before filtering]', self.__precacheManifest.length);
+console.log('[sw] Files to be cached [before filtering]', self.__precacheManifest.length);
 var excludedUrlsPrefix = [
   '/js/locale-',
   '/js/moment-locale-',
@@ -28,6 +34,67 @@ var excludedUrlsPrefix = [
 self.__precacheManifest = self.__precacheManifest.filter((e) => {
   return !excludedUrlsPrefix.some(prefix => e.url.startsWith(prefix))
 });
-console.log('Files to be cached by service worker [after filtering]', self.__precacheManifest.length);
+console.log('[sw] Files to be cached [after filtering]', self.__precacheManifest.length);
 // workbox.precaching.suppressWarnings(); // Only used with Vue CLI 3 and Workbox v3.
 workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
+
+const router = new workbox.routing.Router();
+router.addCacheListener()
+router.addFetchListener()
+
+var registeredServerRoutes = []
+self.registerServerRoutes = (serverUrl) => {
+  console.log('[sw] Setting up API caching for', serverUrl)
+  registeredServerRoutes.forEach((r) => {
+    console.log('[sw] Unregistering previous API route...', r)
+    router.unregisterRoute(r)
+  })
+  if (!serverUrl) {
+    return
+  }
+  var regexReadyServerUrl = serverUrl.replace('.', '\\.')
+  registeredServerRoutes = []
+  var networkFirstPaths = [
+    'api/v1/',
+    'media/',
+  ]
+  var networkFirstExcludedPaths = [
+    'api/v1/listen'
+  ]
+  var strategy = new workbox.strategies.NetworkFirst({
+    cacheName: "api-cache:" + serverUrl,
+    plugins: [
+      new workbox.expiration.Plugin({
+        maxAgeSeconds: 24 * 60 * 60 * 7,
+      }),
+    ]
+  })
+  var networkFirstRoutes = networkFirstPaths.map((path) => {
+    var regex = new RegExp(regexReadyServerUrl + path)
+    return new workbox.routing.RegExpRoute(regex, () => {})
+  })
+  var matcher = ({url, event}) => {
+    for (let index = 0; index < networkFirstExcludedPaths.length; index++) {
+      const blacklistedPath = networkFirstExcludedPaths[index];
+      if (url.pathname.startsWith('/' + blacklistedPath)) {
+        // the path is blacklisted, we don't cache it at all
+        console.log('[sw] Path is blacklisted, not caching', url.pathname)
+        return false
+      }
+    }
+    // we call other regex matchers
+    for (let index = 0; index < networkFirstRoutes.length; index++) {
+      const route = networkFirstRoutes[index];
+      let result = route.match({url, event})
+      if (result) {
+        return result
+      }
+    }
+    return false
+  }
+
+  var route = new workbox.routing.Route(matcher, strategy)
+  console.log('[sw] registering new API route...', route)
+  router.registerRoute(route)
+  registeredServerRoutes.push(route)
+}