diff --git a/angular.json b/angular.json
index 5059e457b1a8b480d2d3267d5732429df3e7302c..c339134d928766a806c798c3c5d72f7bfd6b7d8b 100644
--- a/angular.json
+++ b/angular.json
@@ -23,6 +23,8 @@
               "src/favicon.ico",
               "src/.htaccess",
               "src/cassiopee.webmanifest",
+              "src/pwabuilder-sw.js",
+              "src/pwa-offline.html",
               {
                 "glob": "**/*.json",
                 "input": "src/",
@@ -114,6 +116,8 @@
               "src/assets",
               "src/favicon.ico",
               "src/cassiopee.webmanifest",
+              "src/pwabuilder-sw.js",
+              "src/pwa-offline.html",
               "src/**/*.json",
               "src/**/*.md",
               "src/**/*.png"
diff --git a/src/index.html b/src/index.html
index fa9969a06219d26d9c1fca64e2b2a665eba18db3..511c4534d529343cc7b054277cc3cd4fa4c8983b 100644
--- a/src/index.html
+++ b/src/index.html
@@ -12,7 +12,9 @@
    <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
    <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#ffffff">
+
    <link rel="manifest" href="cassiopee.webmanifest">
+   <meta name="theme-color" content="#003A80">
 
    <meta name="viewport" content="width=device-width, initial-scale=1">
 </head>
@@ -280,6 +282,18 @@
       }
    </script>
 
+    <script type="module">
+        /*
+        This code uses the pwa-update web component https://github.com/pwa-builder/pwa-update to register your service worker,
+        tell the user when there is an update available and let the user know when your PWA is ready to use offline.
+        */
+        import 'https://cdn.jsdelivr.net/npm/@pwabuilder/pwaupdate';
+
+        // généré par https://www.pwabuilder.com/serviceworker le 2020-09-02
+        const el = document.createElement('pwa-update');
+        document.body.appendChild(el);
+    </script>
+
 </body>
 
 </html>
\ No newline at end of file
diff --git a/src/pwa-offline.html b/src/pwa-offline.html
new file mode 100644
index 0000000000000000000000000000000000000000..987f857cd539223b5f3f7a640209df4477e96919
--- /dev/null
+++ b/src/pwa-offline.html
@@ -0,0 +1,8 @@
+<html>
+    <head>
+        <meta charset="utf-8">
+    </head>
+    <body>
+        <h1>Network is required to use Cassiopée</h1>
+    </body>
+</html>
\ No newline at end of file
diff --git a/src/pwabuilder-sw.js b/src/pwabuilder-sw.js
new file mode 100644
index 0000000000000000000000000000000000000000..797a10ec0b49a53363f37992239bf9bf02b6e2fa
--- /dev/null
+++ b/src/pwabuilder-sw.js
@@ -0,0 +1,48 @@
+// This is the "Offline page" service worker
+// généré par https://www.pwabuilder.com/serviceworker le 2020-09-02
+
+importScripts('https://storage.googleapis.com/workbox-cdn/releases/5.0.0/workbox-sw.js');
+
+const CACHE = "cassiopee-pwa";
+
+// TODO: replace the following with the correct offline fallback page i.e.: const offlineFallbackPage = "offline.html";
+const offlineFallbackPage = "pwa-offline.html";
+
+self.addEventListener("message", (event) => {
+  if (event.data && event.data.type === "SKIP_WAITING") {
+    self.skipWaiting();
+  }
+});
+
+self.addEventListener('install', async (event) => {
+  event.waitUntil(
+    caches.open(CACHE)
+      .then((cache) => cache.add(offlineFallbackPage))
+  );
+});
+
+if (workbox.navigationPreload.isSupported()) {
+  workbox.navigationPreload.enable();
+}
+
+self.addEventListener('fetch', (event) => {
+  if (event.request.mode === 'navigate') {
+    event.respondWith((async () => {
+      try {
+        const preloadResp = await event.preloadResponse;
+
+        if (preloadResp) {
+          return preloadResp;
+        }
+
+        const networkResp = await fetch(event.request);
+        return networkResp;
+      } catch (error) {
+
+        const cache = await caches.open(CACHE);
+        const cachedResp = await cache.match(offlineFallbackPage);
+        return cachedResp;
+      }
+    })());
+  }
+});