Browser debugging techniques
Browser debugging is the set of tools built into DevTools that let you inspect variable values, pause code execution, examine the DOM and CSS, and analyse network requests, performance and memory. Chrome, Firefox and Edge offer roughly the same capabilities: from the simplest console.log() all the way to profiling and remote debugging a phone from your computer.
Theory
TL;DR
console.*is the fastest way to look at a value:log,error,warn,table,time,group.debugger;in the code pauses execution on that line, as long as DevTools is open.- Breakpoints in the Sources tab do the same without touching the code, plus give you stepping, Call Stack, Scope and Watch.
- Event Listener Breakpoints pause the code at the moment an event fires:
click,keydown,setTimeout, a DOM change. - Elements debugs markup and styles, Network shows requests (
fetch, XHR, WebSocket, GraphQL). - Performance and Memory hunt for bottlenecks and leaks, and remote debugging gives you access to a mobile browser from the desktop.
Quick example
function calculate(a, b) {
debugger; // execution pauses here when DevTools is open
return a + b;
}
console.group('calculate');
console.time('calc');
console.table([{ a: 2, b: 3 }]);
console.log('result =', calculate(2, 3));
console.timeEnd('calc');
console.groupEnd();The console and the debugger keyword
console is the simplest and most popular approach. It is used for a quick check of values, logic and program state.
| Method | Purpose | Example |
|---|---|---|
console.log() | Prints text and values | console.log("x =", x) |
console.error() | Shows an error in red | console.error("Request failed") |
console.warn() | A warning, in yellow | console.warn("Deprecated API") |
console.table() | Tabular output for arrays and objects | console.table(users) |
console.time() / console.timeEnd() | Measures how long a block takes | console.time("load") |
console.group() / console.groupEnd() | Groups logs into a collapsible block | console.group("init") |
It is fast and convenient, but it only suits simple cases: logs show you a slice of a value, not the whole execution context.
The next step up is the debugger; keyword. Add it to the code and the browser will stop execution exactly on that line, provided DevTools is open.
function calculate(a, b) {
debugger; // <-- execution will stop here
return a + b;
}
calculate(2, 3);Once paused you can inspect variable values, step through lines, and see the call stack and execution context. If DevTools is closed, the line is simply ignored.
Breakpoints and stepping through code
Breakpoints are one of the most convenient techniques: you pause the program exactly where you need it without changing the code.
How to set a breakpoint:
- Open DevTools, the Sources tab.
- Find the JS file you need in the tree on the left.
- Click to the left of the line number, a marker appears.
- Re-run the code, and execution will stop on that line.
From there you get:
- Scope: local variables, closures and global values at the moment of the pause.
- Call Stack: the chain of function calls that led to this point.
- Stepping:
Step over(skip past a call),Step into(go inside a function),Step out(leave the current function),Resume(continue to the next pause). - Watch Expressions: the panel on the right where you add expressions and variables to observe how their values change while you step.
There are also conditional breakpoints: right click a line number to set a condition, and the code stops only when it is true. That is a lifesaver inside loops with thousands of iterations.
Event breakpoints and asynchronous code
The DevTools -> Sources -> Event Listener Breakpoints section lets you pause execution the moment an event fires, even when you do not know which handler serves it.
Examples:
- Stop when a
clickhappens on the page. - When the browser runs
setTimeout(). - When the DOM changes (
DOM Mutation), for example a node is removed or an attribute is added.
This is extremely useful when debugging events and UI logic.
Modern browsers support an async call stack: if an error happened inside await or a promise, the stack shows the path through the asynchronous functions instead of cutting off at engine internals. So you can:
- set breakpoints inside
asyncfunctions, - see the full
awaitchains, - track
Promisestates in the Sources panel.
DOM, CSS and network requests
Elements covers markup and styles:
- viewing and editing HTML in real time,
- inspecting and editing CSS,
- tracking which rule actually won and where it came from,
- the
Computedtab with the final computed styles.
Styles can be changed right in the browser so you can test a design without rebuilding the project.
Network shows every request the page made, along with its parameters:
- URL and method (
GET,POSTand so on), - headers (
Headers), including authorization tokens, - the response body (
Response) and the request body (Payload), - status code (
Status), - load time and a waterfall of timings.
This is also where you debug fetch, XHR, REST, GraphQL and WebSocket: sockets have a dedicated WS filter listing every frame that went in either direction. It is the main tool when you need to work out who is at fault, the frontend or the backend.
Console, besides logs, shows the call stack of an error with file names and line numbers, and the link on the right of a message opens the exact place in the code. On top of that the console runs arbitrary JS in the page context, so you can reach variables, call functions and test hypotheses.
Performance, memory, Live Edit and mobile devices
Performance records an execution profile: how much time went into scripts, styles, layout and painting, where the fps dropped, and which functions hold the main thread. Ideal for optimising complex UI and animations.
Memory hunts for leaks: heap snapshots show which objects the garbage collector does not reclaim and what exactly still references them.
Live Edit: in Sources you can edit a JS file right in the browser and save it with Ctrl+S, and the browser will run the modified version without reloading the page. Great for quick experiments while debugging.
Remote debugging: Chrome DevTools can connect to a phone over USB, open the page running on the device and debug it from the desktop, elements, JS and network included.
Summary table:
| Technique | Where it is used | What it does |
|---|---|---|
console.log() | In the code | Quick check of values |
debugger | In the code | Pauses execution on a line |
| Breakpoints | DevTools -> Sources | Pause on a chosen line without editing code |
| Event Breakpoints | DevTools -> Sources | Pause at the moment of an event |
| Network | DevTools | Debugging API requests |
| Elements | DevTools | Changing DOM and CSS |
| Performance | DevTools | Speed analysis |
| Memory | DevTools | Finding memory leaks |
| Watch / Scope | DevTools | Observing variables |
| Console | DevTools | Logs, errors, running code |
| Remote debugging | Chrome and a phone | Debugging mobile pages |
Common mistakes
- Leaving
console.log()anddebugger;in a production build. Logs clutter the user's console and can leak data, whiledebugger;freezes the page for everyone who has DevTools open. Strip them with a linter or a bundler setting. - Debugging minified code without source maps. Without them you stare at one long unreadable line; enable source maps and check that they ship with the build.
- Logging an object and trusting what you see. The console shows a live reference, so an object expanded later may already hold different fields. For a snapshot use
console.log(structuredClone(obj))orconsole.table(). - Chasing a bug with logs where a breakpoint is needed. A dozen
console.log()calls are replaced by one conditional breakpoint that shows the whole Scope and Call Stack at once. - Forgetting about filters in Network and Console. When a request "is not being sent", it is often just filtered out, or
Hide network messagesis on. - Ignoring
Preserve log. On navigation or a redirect the logs and requests are cleared and the error disappears with them; thePreserve logcheckbox keeps them.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.