67 Weird Debugging Tricks Your Browser Doesn't Want You to Know

A list of useful, not-obvious hacks to get the most out of your browser’s1 debugger. Assumes an intermediate-level-or-higher understanding of the developer tools.

Advanced Conditional Breakpoints

By using expressions that have side effects in places you wouldn’t expect, we can squeeze more functionality out of basic features like conditional breakpoints.

Logpoints / Tracepoints

For example, we can console.log in breakpoints. Logpoints are breakpoints that log to the console without pausing execution. While Microsoft Edge has had logpoints built-in for a while and Chrome just added them in v73, Firefox does not. But, we can use conditional breakpoints to simulate them in any browser.

Conditional Breakpoint - console.log

Use console.count instead of console.log if you also want a running count of how many times the line is executed.

UPDATE (May 2020): All the major browsers now directly support logpoints/tracepoints (Chrome Logpoints, Edge Tracepoints, Firefox Logpoints)

Watch Pane

You can also use console.log in the watch pane. For example, to dump a snapshot of localStorage everytime your application pauses in the debugger, you can create a console.table(localStorage) watch:

console.table in watch pane

Or to execute an expression after DOM mutation, set a DOM mutation breakpoint (in the Element Inspector): DOM Mutation Breakpoint

And then add your watch expression, e.g. to record a snapshot of the DOM: (window.doms = window.doms || []).push(document.documentElement.outerHTML). Now, after any DOM subtree modification, the debugger will pause execution and the new DOM snapshot will be at the end of the window.doms array. (There is no way to create a DOM mutation breakpoint that doesn’t pause execution.)

Tracing Callstacks

Let’s say you have a function that shows a loading spinner and a function that hides it, but somewhere in your code you’re calling the show method without a matching hide call. How can you find the source of the unpaired show call? Use console.trace in a conditional breakpoint in the show method, run your code, find the last stack trace for the show method and click the caller to go to the code:

console.trace in conditional breakpoint

Changing Program Behavior

By using expressions that have side effects on program behavior, we can change program behavior on the fly, right in the browser.

For example, you can override the param to the getPerson function, id. Since id=1 evaluates to true, this conditional breakpoint would pause the debugger. To prevent that, append , false to the expression.

Conditional Breakpoint - parameter override

Quick and Dirty Performance Profiling

You shouldn’t muddy your performance profiling with things like conditional breakpoint evaluation time, but if you want a quick and dirty measurement of how long something takes to run, you can use the console timing API in conditional breakpoints. In your starting point set a breakpoint with the condition console.time('label') and at the end point set a breakpoint with the condition console.timeEnd('label'). Everytime the thing you’re measuring runs, the browser will log to the console how long it takes.

Conditional Breakpoint - performance profile

Using Function Arity

Break on Number of Arguments

Only pause when the current function is called with 3 arguments: arguments.callee.length === 3

Useful when you have an overloaded function that has optional parameters.

Conditional Breakpoint - argument length

Break on Function Arity Mismatch

Only pause when the current function is called with the wrong number of arguments: (arguments.callee.length) != arguments.length

Conditional Breakpoint - arity check

Useful when finding bugs in function call sites.

Using Time

Skip Page Load

Don’t pause until 5 seconds after page load: performance.now() > 5000

Useful when you want to set a breakpoint but you’re only interested in pausing execution after initial page load.

Skip N Seconds

Don’t pause execution if the breakpoint is hit in the next 5 seconds, but pause anytime after: window.baseline = window.baseline || Date.now(), (Date.now() - window.baseline) > 5000

Reset the counter from the console anytime you’d like: window.baseline = Date.now()

Using CSS

Pause based on computed CSS values, e.g. only pause execution when the document body has a red background color: window.getComputedStyle(document.body).backgroundColor === "rgb(255,0,0)"

Even Calls Only

Only pause every other time the line is executed: window.counter = (window.counter || 0) + 1, window.counter % 2 === 0

Break on Sample

Only break on a random sample of executions of the line, e.g. only break 1 out of every 10 times the line is executed: Math.random() < 0.1

Never Pause Here