Chrome Extension Debugging Guide
Where each part of an extension logs, how to open the right DevTools window, and the errors that catch everyone out.

Extensions are confusing to debug because each surface runs in its own context with its own console. Once you know which DevTools window to open, most bugs take minutes.
Three consoles, three surfaces
- Popup — right-click the toolbar icon and choose 'Inspect popup'.
- Service worker — open chrome://extensions and click the 'service worker' link on your extension card.
- Content script — use the normal page DevTools; your logs appear alongside the site's, filtered by the extension context selector.
Read the Errors panel first
On chrome://extensions, a red Errors button appears whenever loading or the service worker fails. It shows the file and line, which beats guessing.
Errors that catch everyone
- 'Refused to execute inline script' — MV3 CSP; move the code into an external file.
- 'Cannot access contents of the page' — missing host_permissions or activeTab.
- 'Extension context invalidated' — the extension reloaded while a content script was still running; refresh the page.
- 'Receiving end does not exist' — you messaged a tab with no content script injected yet.
- Service worker logs disappearing — the worker went idle; re-open the inspector or use chrome.storage for durable traces.
A quick triage order
- Does the extension load without a manifest error?
- Does the service worker register and stay error-free?
- Does the popup render and log?
- Is the content script injected on the URL you are testing?
- Are permissions granted for the API you are calling?
Debugging chrome.storage state directly
From the service worker's inspector console, run chrome.storage.local.get(null, console.log) (or .sync) to dump every stored key at once — far faster than adding temporary console.log calls throughout your code to see what's actually persisted.
Verifying which permissions are actually granted
Run chrome.permissions.getAll(console.log) in any extension console to list currently granted permissions and origins, which is essential when optional_permissions are involved and a feature silently no-ops because the user never granted the runtime request.
Debugging message passing failures
- 'Could not establish connection. Receiving end does not exist.' means no listener was registered on the other side — check the content script actually injected on that tab.
- Wrap chrome.runtime.sendMessage callbacks with a check on chrome.runtime.lastError; unchecked errors here fail silently and look like the listener just never ran.
- For long-lived connections use chrome.runtime.connect() and check port.onDisconnect to catch a service worker that went idle mid-conversation.
Remote debugging and the chrome://inspect page
chrome://inspect/#extensions lists every installed extension with its own 'inspect' link, which is a faster way to jump into a service worker or background context than navigating through chrome://extensions when you have many extensions installed.
Performance profiling a service worker
Open the service worker's DevTools and use the Performance panel exactly as you would on a page — record while triggering the action you suspect is slow (e.g. a large chrome.storage read or a big scripting.executeScript injection) to see where time is actually spent.
Logging that survives a service worker restart
- Write a small ring buffer of recent log lines to chrome.storage.session on each important event.
- Read it back from the options page or popup with a 'View debug log' button.
- This avoids losing the trail of what happened right before a crash, since the console itself clears when the worker terminates.
Frequently asked questions
Why do my console.log lines vanish in the service worker?
MV3 workers shut down after ~30 seconds of inactivity and the inspector detaches. Re-open the service worker inspector or persist logs to chrome.storage.local.
How do I debug an extension only on the Chrome Web Store, not locally?
Download and unzip the .crx (or reproduce it from your uploaded source), load it with Load unpacked, and debug the local copy — you cannot attach DevTools directly to a Web Store-installed instance in the same interactive way.
Why does 'Inspect views service worker' sometimes not appear on the card?
It only shows while the worker is active; if it went idle, click any action that wakes it (like clicking the toolbar icon) or reload the extension, then the link reappears.
Can I use console.trace() inside a Manifest V3 service worker?
Yes, all standard console methods work in the service worker context exactly as in a page, including console.trace, console.table and console.group.