Skip to main content

How to keep extension service workers alive in Manifest V3

In version 3 of the Chromium extension platform, persistent background scripts were replaced with ephemeral service workers. Their ephemeral nature makes it impossible to retain global variables, with the solution being to use the new Storage APIs to persist data. However, this is not possible with some data (e.g. class instances obtained from another library), and this model also prevents using event listeners from non-Chrome services (such as Firebase's Realtime Database).

Luckily, there are many workarounds to this problem. The cleanest one as of Chrome 114 is to create an offscreen document that has access to the chrome.runtime API, allowing it to periodically "ping" the service worker every 25 seconds, just enough to reset the service worker's 30-second idle timeout. Please do note that this solution will only work in Chrome 109 and above.

Step 1

Create the HTML and JS file for the offscreen document.
offscreen.html
<!DOCTYPE html>
<html>
<head>
<script src="offscreen.js"></script>
</head>
<body>
How did you get here?
</body>
</html>

offscreen.js
setInterval(() => {
chrome.runtime.sendMessage({ "type": "service_worker_keepalive" });
}, 25e3);


Step 2

Listen for the message in the service worker.

service-worker.js
chrome.offscreen.createDocument({
url: "offscreen.html",
reasons: [ "WORKERS" ],
justification: "Service worker keepalive workaround"
});
chrome.runtime.onMessage.addListener(({ type, data }) => {
if (type == "service_worker_keepalive") {
console.log("[DEBUG] Keepalive ping received");
}
});


Step 3

Test the solution!

Hope this helped!

Comments