Chrome MV3 extension makes Chrome/Windows laggy when loaded — how should I profile content scripts, MutationObservers, and timers?
02:51 02 Jul 2026

I’m building a personal Chrome MV3 extension. Chrome and my PC run normally when the extension is disabled, but as soon as I load the unpacked extension, Chrome starts feeling laggy/heavy.

I’m not asking anyone to debug private production code. I’ve redacted the real domains and replaced them with fake hosts.

Setup:

  • Chrome MV3 extension

  • Windows

  • Unpacked extension loaded through chrome://extensions

  • Content scripts injected on several specific web apps

  • Some content scripts use all_frames: true

  • Some scripts use MutationObserver

  • Some scripts use polling intervals, for example 2s/3s/5s/10s

  • Service worker has recurring alarms, including a 1-minute alarm

  • Disabling the extension fixes the lag

What I’m trying to find:

  1. How to identify which content script/service worker path is causing CPU/memory usage.

  2. Whether all_frames: true plus DOM scanning/MutationObservers is a likely cause.

  3. Best way to profile an unpacked MV3 extension.

  4. What patterns to avoid in content scripts that run on large SPA pages.

Minimal redacted manifest shape:

{
  "manifest_version": 3,
  "name": "Redacted Extension",
  "version": "1.0",
  "permissions": ["storage", "scripting", "tabs", "alarms", "webNavigation"],
  "host_permissions": [
    "https://app1.example.com/*",
    "https://app2.example.com/*"
  ],
  "background": {
    "service_worker": "service_worker.js",
    "type": "module"
  },
  "content_scripts": [
    {
      "matches": ["https://app1.example.com/*"],
      "js": ["content-a.js"],
      "all_frames": true,
      "run_at": "document_end"
    },
    {
      "matches": ["https://app2.example.com/*"],
      "js": ["content-b.js"],
      "all_frames": true,
      "run_at": "document_end"
    }
  ]
}

Example pattern I’m worried about:

const observer = new MutationObserver(() => {
  clearTimeout(debounceTimer);
  debounceTimer = setTimeout(scanPage, 250);
});

observer.observe(document.body, {
  childList: true,
  subtree: true
});

setInterval(scanPage, 5000);

function scanPage() {
  const nodes = document.querySelectorAll("div, span, button, input");
  for (const node of nodes) {
    // reads text/attributes and updates extension state
  }
}

What should I check first? Should I profile through Chrome Task Manager, DevTools Performance, chrome://extensions service worker inspection, or another tool?

Github link for the repo is: https://github.com/jacobsscoots/CTL-Redacted

javascript google-chrome