HELGE SVERREAll-stack Developer
Bergen, Norwayv13.0
est. 2012  |  300+ repos  |  4000+ contributions
Tools  |   Theme:
Chrome DevTools Tips You Probably Missed
February 28, 2026

I scraped through every article in Chrome's official DevTools Tips series — all 30 of them — looking for things I didn't already know. Most of it was stuff you'd pick up naturally after a few years of staring at the Network panel. But some of it made me genuinely annoyed at Past Me for not knowing sooner.

Here are the five that stuck. Each one solves a specific debugging situation you've definitely been in, and each one takes about ten seconds to learn.

1. Freeze the Page to Inspect Disappearing Elements

You know the drill. You hover over something, a tooltip appears, you move your mouse toward DevTools to inspect it, and it vanishes. You try again. It vanishes again. You start adding display: block !important to random things in the console and hate your life.

There's a better way. Open Sources > Snippets, create a new snippet, and paste this:

setTimeout(() => { debugger; }, 3000);

Run the snippet. You now have three seconds. Hover over the tooltip, trigger the dropdown, do whatever makes the element appear — and then wait. The debugger statement fires, execution pauses, and the entire page freezes exactly as it is. The tooltip stays. The dropdown stays. Everything stays.

Now switch to the Elements panel and inspect to your heart's content. The DOM is frozen mid-state. When you're done, hit the resume button in Sources and the page continues like nothing happened.

This works for anything: hover menus, autocomplete suggestions, notification toasts, focus-triggered popups. If you can make it appear, you can freeze it.

Bonus: For focus-triggered elements specifically (like autocomplete dropdowns that close when you click into DevTools), open the Rendering drawer via the Command Menu (Cmd+Shift+P > "Show Rendering") and enable "Emulate a focused page". This tells the page it still has focus even while you're clicking around in DevTools. It solves a different but related frustration, and I genuinely can't believe I went years without knowing about it.

2. Logpoints: console.log Without Touching Your Code

This one borders on embarrassing. I've been adding console.log() statements, saving, waiting for hot reload, checking the console, then cleaning up the logs before committing — for over a decade. The entire time, DevTools had a feature that does this without modifying a single line of source code.

In the Sources panel, right-click any line number and select "Add logpoint". Type an expression — anything you'd put inside a console.log():

"user:", user, "state:", state.status, "count:", items.length

That's it. Every time execution hits that line, DevTools logs the values to the Console. No pausing, no source modification, no cleanup. The logpoint persists across page reloads (tied to the file and line number), and it disappears when you close DevTools or remove it.

This is strictly better than console.log() in every way that matters during debugging:

  • No git noise. You never accidentally commit debug statements.
  • No rebuild cycle. The logpoint is live the instant you add it.
  • No cleanup. Close DevTools and it's gone.
  • Works on production. Open DevTools on any deployed site, add logpoints to the source-mapped files, and debug in real time.

That last point is the one that changed things for me. I can add logpoints to production code running on a staging server, without deploying anything. If you're debugging an issue that only reproduces in a specific environment, this is worth its weight in gold.

3. monitor() and monitorEvents(): Spy on Any Function

The Console has a set of utility functions that aren't part of standard JavaScript — they only exist inside DevTools. Most developers know $0 (the currently selected element) and maybe $('selector') as a shorthand for querySelector. But the monitoring functions are in a different league.

Watch every call to a function:

monitor(handleSubmit)

Now every time handleSubmit is called, DevTools logs the call with all its arguments. No breakpoints, no source changes. Just visibility into when and how a function gets invoked.

> function handleSubmit called with arguments: FormData, Event

Watch every event on an element:

monitorEvents(document.querySelector('#search-input'), ['focus', 'blur', 'input'])

This logs every focus, blur, and input event on that element. Incredibly useful when you're debugging event ordering issues — like figuring out why a blur handler fires before a click handler on an adjacent button, which is the kind of thing that makes you question your career choices.

Find every instance of a constructor in memory:

queryObjects(Promise)

This returns every live Promise object in the heap. Replace Promise with any constructor — Map, WeakRef, AbortController, your own classes — and you get a count of how many instances exist. Quick way to check for memory leaks without opening the Memory panel.

Turn them off with unmonitor(fn) and unmonitorEvents(el) when you're done.

4. Shift+Hover in the Network Panel

Hold Shift and hover over any request in the Network panel. Two things happen:

  1. The request's initiators (what triggered it) turn green.
  2. The request's dependencies (what it triggered) turn red.

The first green row above the one you're hovering over is the direct initiator — the script or resource that caused this request to fire. Everything red below it loaded as a consequence of this request.

This immediately answers "why is this request happening?" and "what breaks if I block it?" — questions that normally require clicking into the Initiator tab, reading a stack trace, mentally tracing the chain, and probably adding a breakpoint or two.

Combine this with fetch priority columns for the full picture. Enable "Big request rows" in Network panel settings, then right-click the column header and add the Priority column. Each request now shows two values: the browser's initial priority and its final priority. Images often start at Low and get bumped to High once the browser discovers they're in the viewport. If you see that happening for your LCP image, that's a clear signal to add fetchpriority="high" to skip the re-prioritization delay.

5. Wildcard Header Overrides

Most developers know you can right-click a network request and override its content locally. Fewer know you can override response headers, and almost nobody knows you can do it with wildcards.

Right-click any request in the Network panel and select "Override headers". DevTools lets you add, modify, or remove any response header for that URL. Want to test if a stricter Content-Security-Policy would break your site? Override it. Want to see what happens with different Cache-Control settings? Override it. Need to test CORS without touching your server config? Override the Access-Control-Allow-Origin header.

The real power is wildcards. When editing header overrides, you can use patterns like:

*.example.com/*

This applies your header override to every request matching that pattern. Set Cache-Control: no-store across your entire domain with a single rule. Add a custom header to all API responses. Remove X-Frame-Options from every response to test iframe embedding.

Two more things worth knowing:

  • Filter overridden requests with has-overrides:yes in the Network panel filter box. This shows only requests you've modified, so you don't lose track of what you've changed.
  • Local overrides automatically disable the HTTP cache while active. No need to separately check the "Disable cache" checkbox.

These aren't the only useful things in the DevTools Tips series — there's a solid walkthrough on debugging speculative navigations, a good explainer on bfcache debugging, and the Animations tab with its drag-to-adjust timing is genuinely delightful once you try it. But these five are the ones I now use regularly and wish I'd known years ago.




<!-- generated with nested tables and zero regrets -->