10 Chrome DevTools Features Most Developers Miss

Written By  Crosscheck Team

Content Team

May 22, 2026 11 minutes

10 Chrome DevTools Features Most Developers Miss

Ten Chrome DevTools features most developers never open

If you only know Inspect Element and the Console tab, you are using maybe ten percent of Chrome DevTools. The other ninety is where the real time-savings live — a console function that logs every event a button fires, a setting that serves a patched local file into the live page, a tab that tells you exactly which bytes of your JavaScript bundle never ran. None of this is new. Most of it has shipped quietly across the last five Chrome releases. Almost none of it shows up in tutorials. This post walks ten of those features, with what they are, why they matter, and the one-line invocation that turns each one on.

Key takeaways

  • monitorEvents($0) logs every event a selected element fires to the Console — no listener setup required.
  • getEventListeners($0) prints every handler attached to an element, including framework-bound ones.
  • Local Overrides serve a patched local file into the live page so you can verify fixes without a deploy.
  • The Coverage tab shows the exact unused bytes in every JavaScript and CSS file — line by line, in red.
  • The three-snapshot heap technique isolates memory leaks by filtering snapshot three to "Objects allocated between snapshots 1 and 2."

1. monitorEvents($0, 'click') — log every event a node fires

The single most useful function in the DevTools Console, and probably the least known.

What it is. monitorEvents(object, events) is a Console-only utility that logs an event object to the Console every time the named events fire on the named DOM node. Pair it with $0 — the reference to whatever you most recently selected in the Elements panel — and you can monitor any element on the page in one line.

Why it matters. Half of "this button doesn't work" bugs are not handler bugs. The click never reaches the handler — intercepted by an overlay, swallowed by stopPropagation, attached to the wrong node by a misbehaving React effect. monitorEvents shows the event stream directly, so you can confirm whether dispatch is happening before you read handler code.

How to invoke. Click the element in Elements, switch to Console, and run:

monitorEvents($0, 'click');
// or, for everything: monitorEvents($0);
// stop with: unmonitorEvents($0);

The function accepts single event names ('click'), arrays (['mousedown', 'mouseup']), or one of the generic keywords mouse, key, touch, or control, which expand to that family of events. It is a DevTools-only function — calling it from application code throws monitorEvents is not defined. See the Console Utilities API reference for the full list.


2. getEventListeners($0) — see every handler attached to an element

Where monitorEvents watches future events, getEventListeners enumerates the ones already wired up.

What it is. A Console utility that returns an object listing every event listener attached to the given DOM node, grouped by event type. Each listener entry exposes the callback function, whether it's passive, whether it useCapture, and what the original listener was — including the unminified source if it's available.

Why it matters. Frameworks attach listeners through layers of abstraction — React's synthetic events delegate from the root, Vue binds via directives, and a click you wired in code can end up registered on document, on a wrapper, on the original button, or all three. getEventListeners($0) cuts through that. It is also how you find dangling listeners after teardown, the most common cause of React memory leaks.

How to invoke.

getEventListeners($0);
// returns: { click: [{listener, useCapture, passive, ...}], mouseover: [...] }

Pair it with $1 through $4 — references to your previous four element selections — when you want to compare handlers across siblings without re-clicking.


3. document.designMode = 'on' — edit any page like a Word document

A one-line trick that turns any web page into editable content.

What it is. document.designMode is a standard Web API property that toggles whether the whole document is editable. Set it to 'on' and every text node, heading, paragraph, and list item on the page becomes directly editable in place — type, delete, copy-paste, drag images around. No source change, no contenteditable attributes, no special tooling.

Why it matters. Mocking copy variations for stakeholders without firing up Figma, testing how layouts respond to longer or shorter strings (translation overflow, line-break edge cases), and building demo screenshots for documentation where the real product data is too sensitive to show.

How to invoke. Open the Console on any page and run:

document.designMode = 'on';
// turn it off with: document.designMode = 'off';

Changes don't persist — reload and they're gone. That is a feature, not a bug; the page becomes a sandbox.


4. Local Overrides — patch the live page with a local file

The closest DevTools comes to a developer environment built into the browser.

What it is. Local Overrides let you save a copy of any served file — JavaScript, CSS, HTML, JSON, even response headers — to a local folder, edit it, and have DevTools serve the modified version into the live page on every subsequent reload. The override survives navigations, refreshes, and even closing and reopening DevTools. The browser is, in effect, running a tiny man-in-the-middle proxy you control.

Why it matters. The classic use is verifying a fix without a deploy. A bug appears in production, the patch is one line, you want to confirm the line fixes it before shipping. Edit the file, reload, watch the bug disappear. The other use is overriding third-party scripts you don't control — silencing a noisy analytics call, hot-patching a CDN-hosted polyfill — long enough to file a ticket with the team that owns it.

How to invoke. Open the Network panel, right-click any request, and choose Override content or Override headers. DevTools prompts you for a local folder once, then takes you to either the Sources panel (for content) or an inline editor (for headers). The official override docs cover the wildcard patterns for matching multiple URLs. The Network panel marks overridden requests with a purple dot, and Sources → Overrides lists everything you've patched.

A common header override:

Access-Control-Allow-Origin: *

— added once, the CORS error is gone for the rest of the session. Source-mapped files can't be overridden, and the browser cache is disabled while Local Overrides are active. Both are deliberate.


5. HAR capture and replay — share the network log

A built-in export format that turns the Network panel into a debuggable artifact.

What it is. HAR (HTTP Archive) is a JSON format that captures every request the browser made — URL, method, headers, request body, response body, timing breakdown, initiator chain. Chrome DevTools can export the current Network panel as a HAR file in one click, and it can also import a HAR file from anywhere and render it back in the Network panel as if you had recorded it yourself.

Why it matters. HAR is the right way to attach a network trace to a bug report — Postman, Insomnia, Charles Proxy, Wireshark, and DevTools itself can all open them, so whoever picks up the ticket steps through the exact same requests. The import flow also makes Chrome the cheapest HAR viewer on the planet — drop a customer's HAR in and inspect what their session actually did.

How to invoke. In the Network panel, click the Export HAR (sanitized) button in the action bar, or right-click any request and choose Save all as HAR (sanitized). Sanitized means cookies, Authorization, and Set-Cookie headers are stripped — the right default for sharing. If you need the credentialed version for internal debugging, enable Allow to generate HAR with sensitive data in DevTools Settings → Preferences → Network first. To import, click the Import HAR icon at the top of the Network panel.

Even sanitized HARs can leak data the page itself loaded. Treat them like screenshots — fine for trusted recipients, not safe to paste into a public issue tracker.


6. The Network filter bar — -domain:, method:POST, status-code:500

The Network filter accepts a whole query language most developers never type.

What it is. The filter input above the Network table looks like a simple search box. It is actually a structured query parser with a dozen operators — domain:, method:, status-code:, mime-type:, larger-than:, scheme:, has-overrides:, is:running — and a leading hyphen on any of them inverts the match. Operators stack with AND semantics, so you can build queries like "all POST requests to our API that returned anything except 200, excluding the analytics CDN."

Why it matters. Modern pages make hundreds of requests on initial load. Finding the failed call by scrolling is impossible. The filter bar turns the Network panel into a queryable log.

How to invoke. Click in the filter input and type, or paste any of these:

method:POST -status-code:200          # All POSTs that didn't succeed
domain:api.example.com larger-than:1M # Big API responses
-domain:*.googletagmanager.com        # Hide all GTM noise
status-code:500                       # Server errors only
is:running                            # Requests still in flight

The Network features reference documents every operator. Combine with Preserve log checked, and the filter survives navigations — which is how you debug multi-step OAuth handshakes and redirect chains without losing the trail. The full beginner walkthrough is in Chrome DevTools for QA and developers; this section is the shortcut.


7. The Coverage tab — find unused JavaScript and CSS bytes

The fastest way to discover that you're shipping a megabyte of code nobody runs.

What it is. The Coverage tab records which lines of every JavaScript and CSS file actually executed during a page load and any interaction you performed. It outputs a table per file, showing total bytes versus unused bytes, plus a red-bar visualisation. Click any row to open the file in Sources with used lines marked blue in the gutter and unused lines marked red.

Why it matters. Bundle-size budgets fail because nobody has a precise picture of which code is dead. A library you imported for one feature on one route ships across the whole app. A CSS file your design system never trimmed carries selectors that haven't matched a DOM node in two years. The Coverage tab gives you the per-line truth — including bytes that were used but only on a path you didn't trigger, which is the real fix surface.

How to invoke. Open the Command Menu with Cmd/Ctrl + Shift + P, type coverage, hit Enter. Choose Per function or Per block instrumentation. Click the reload icon to start recording. Interact with the page. Click stop. Read the red bars top to bottom — they sort by largest unused portion first.

The Coverage tab is also a useful unminifier. Double-click a minified file in the result table and Sources pretty-prints it, which is occasionally the fastest path to reading a bundle you don't control.


8. The three-snapshot heap technique — isolate a real memory leak

The Memory panel workflow that actually works.

What it is. A leak-hunting procedure that takes three heap snapshots — baseline, after-action, after-action-again — then filters the third snapshot to Objects allocated between snapshots 1 and 2. Anything in that filtered view is an object that was created during the first iteration of the suspect action and still survives after the second, which is the definition of a leak. The technique was first documented by the Gmail team and is the standard reference for hunting detached DOM trees.

Why it matters. The naive "take one snapshot and look for big numbers" approach drowns in noise — lazy-initialised globals, framework caches, fonts that loaded during the recording, everything looks like a leak. The three-snapshot diff filters out the one-off allocations and surfaces the pattern that repeats. Combined with the Class filter typed Detached, it pinpoints DOM subtrees that have been removed from the document but are still held alive by a JavaScript reference — the most common React, Vue, and vanilla-DOM leak in the wild.

How to invoke. Open the Memory panel, choose Heap snapshot, then:

  1. Click the trash-can icon to force a GC.
  2. Take Snapshot 1.
  3. Perform the suspect action — open a modal, navigate a route, mount a list — then close, navigate back, or unmount.
  4. Force GC, take Snapshot 2.
  5. Repeat the same action, force GC, take Snapshot 3.
  6. With Snapshot 3 selected, change the right-hand filter from All objects to Objects allocated between Snapshots 1 and 2.
  7. Type Detached into the Class filter.

Yellow nodes in the retainers panel are the JavaScript references holding the subtree alive — that is your leak. The official heap snapshot docs cover the colour codes and the read order in full. For a wider performance investigation, the companion piece is Chrome DevTools performance auditing.


9. Console selectors — $0, $_, $$, $x()

Four selectors that compress most of what you'd otherwise paste from Stack Overflow.

What they are. Built-in DevTools Console shortcuts, none of them part of the standard library, none available outside the Console.

  • $0 — reference to whatever you most recently selected in the Elements panel. $1 through $4 give you the previous four.
  • $_ — the value of the last expression you evaluated in the Console.
  • $$(selector) — shorthand for Array.from(document.querySelectorAll(selector)). Returns a real array, so you can .map(), .filter(), .forEach() directly.
  • $x(xpath) — runs an XPath expression against the document and returns the matching nodes. Useful when CSS selectors can't express what you need ("the <td> whose text content contains 'failed'").

Why they matter. The four together turn the Console from a calculator into a query surface. $$('button:disabled').length is a one-line count of disabled buttons. $_.id reads the id of the last expression's result without re-typing it. $x("//td[contains(., 'failed')]") finds the cell you couldn't write a CSS selector for.

How to invoke. Type them in the Console. Examples:

$0.disabled; // is the selected button disabled?
$$('a[href^="/blog"]').map(a => a.href); // all blog links on the page
$_.textContent; // text of the last evaluated node
$x("//h2[contains(., 'Pricing')]")[0]; // first H2 whose text mentions Pricing

Combine with copy() — another Console-only utility — to put any object on the clipboard: copy($$('button').map(b => b.textContent)) puts every button label in your clipboard as JSON.


10. Live cookie and storage editing in the Application panel

The fastest way to test logged-out, logged-in, and edge-case states without juggling accounts.

What it is. The Application panel under Storage lists every cookie, every localStorage entry, every sessionStorage entry, and every IndexedDB record the page has set, in a table you can edit in place. Click any value, change it, and the next request the page makes uses the new value. You can also delete a single cookie, clear all storage with one click, or set a brand-new cookie with arbitrary HttpOnly, Secure, SameSite, Domain, Path, and Expires values.

Why it matters. Auth bugs are the canonical place this saves time. "What happens if the auth cookie expires mid-flow?" — delete the cookie, fire a request, watch the behaviour. "What happens if the user has a stale feature flag in localStorage?" — edit the value, reload. "Does the dashboard handle a malformed JSON payload in sessionStorage gracefully?" — set it to {, reload, watch the error boundary fire. Recreating these states by signing into different test accounts takes minutes; editing storage takes seconds.

The same panel exposes service workers (force-update, unregister, simulate offline), cache storage (inspect the Service Worker cache by name), and the Clear site data button that wipes every storage type for the origin — the cleanest way to test a first-visit flow without creating a new browser profile.

How to invoke. Open DevTools, switch to the Application panel, expand Storage → Cookies → [your origin] for cookies, or Storage → Local storage for localStorage. Double-click any cell to edit. To set a new cookie, scroll to the bottom of the cookie table and click the empty row.


A note on Lighthouse and React DevTools

Lighthouse is still bundled as a DevTools panel — Lighthouse 12 is what ships today, dropped the PWA category in May 2024, and audits Performance, Accessibility, Best Practices, and SEO. For CI, the supported path is the separate @lhci/cli package against staging URLs, not the DevTools panel. The deep walkthrough is in Chrome DevTools performance auditing.

React DevTools is a separate extension, not a built-in Chrome feature. Its Profiler tab is the right surface for hunting unnecessary re-renders in React 19 — a more sustainable approach than scattering useMemo everywhere, especially since the React Compiler now handles many manual memoizations.


FAQ

Which Chrome DevTools features are most underused?

The Console utility functions — monitorEvents, getEventListeners, $0, $$, $x(), copy() — and Local Overrides. They are documented in the official Console Utilities API reference and the Overrides docs but rarely appear in tutorials, so most developers reach DevTools through Elements and Console and never explore further.

Does monitorEvents work in current Chrome?

Yes. monitorEvents and the related unmonitorEvents and getEventListeners are Console-only utilities that have been stable for years and are documented for current Chrome. They cannot be called from application code — only from the DevTools Console — and they cover any DOM node, not just $0.

How do I edit a web page directly in the browser?

Open the Console on any page and run document.designMode = 'on'. The whole document becomes editable in place, like a Word document, until you reload or run document.designMode = 'off'. Changes do not persist. It is a Web API standard, not a DevTools feature, but the Console is the easiest place to toggle it.

What's the difference between Local Overrides and Workspaces?

Local Overrides let you intercept any served file with a local copy — useful when you don't own the source or can't deploy. Workspaces map a folder on disk to the served origin so edits in DevTools save back to your project files — useful during local development on code you do own. They can be combined: Workspaces for your own source, Overrides for third-party scripts you can't change.

Is the Coverage tab still where it used to be?

Yes. Open it via the Command Menu (Cmd/Ctrl + Shift + P, type coverage, hit Enter) or via More tools → Coverage. The Coverage panel opens in the Drawer at the bottom of DevTools and works the same way it has since 2019 — reload to instrument, interact to record, stop to read results.

What's the fastest way to find a memory leak in a single-page app?

Use the three-snapshot heap technique. Take a heap snapshot, perform the suspect action and unwind it, take a second snapshot, repeat the action and unwind it, take a third snapshot. Filter snapshot three to Objects allocated between snapshots 1 and 2 and type Detached into the Class filter. Anything that appears is a DOM subtree still held alive after both iterations — the definition of a leak.


Where Crosscheck fits

Every feature above only helps if DevTools was open before the bug happened. Console errors that fired before you opened the panel are gone. Network requests from earlier in the session aren't preserved unless Preserve log was already checked. The session leading up to a failure — the clicks, the order, the prior page state — is not something DevTools captures retroactively. Crosscheck is a free Chrome extension that records that context in the background and bundles it into a single bug report — console logs, network requests, screenshots, screen recording, environment metadata — sent straight to Jira, Linear, ClickUp, GitHub, or Slack when you click Report Bug. DevTools is where you go to understand a bug; Crosscheck is what makes sure the bug you understood reaches the developer with the evidence intact.

Try Crosscheck free

Related Articles

Contact us
to find out how this model can streamline your business!
Crosscheck Logo
Crosscheck Logo
Crosscheck Logo

Speed up bug reporting by 50% and
make it twice as effortless.

Overall rating: 5/5