Advanced Browser DevTools Tips and Tricks
Go beyond console.log: Network throttling, Performance flame charts, Memory snapshots, CSS debugging, JavaScript profiling, and hidden DevTools features that save hours.
What you'll learn
- ✓Console methods beyond log: table, group, time, assert, and trace
- ✓Network tab tricks: throttling, blocking, replay, and HAR export
- ✓How to read Performance flame charts and find bottlenecks
- ✓How to use Memory snapshots to find leaks
- ✓CSS debugging tools: computed styles, animations panel, coverage
Prerequisites
- •Basic DevTools usage (inspect element, console)
Console: Beyond console.log
console.table
const users = [
{ name: 'Alice', role: 'admin', active: true },
{ name: 'Bob', role: 'editor', active: false },
{ name: 'Charlie', role: 'viewer', active: true },
];
// Displays a formatted table
console.table(users);
// Show only specific columns
console.table(users, ['name', 'role']);
console.group and console.groupCollapsed
console.group('User Authentication');
console.log('Checking session...');
console.log('Session valid');
console.group('Permissions');
console.log('Role: admin');
console.log('Scopes: read, write, delete');
console.groupEnd();
console.groupEnd();
// Collapsed by default (great for verbose logs)
console.groupCollapsed('API Response');
console.log(largeObject);
console.groupEnd();
console.time and console.timeEnd
console.time('data-fetch');
const data = await fetch('/api/data').then((r) => r.json());
console.timeEnd('data-fetch'); // data-fetch: 142.3ms
// For multiple measurements
console.time('total');
console.time('fetch');
const response = await fetch('/api/items');
console.timeEnd('fetch'); // fetch: 89ms
console.time('parse');
const items = await response.json();
console.timeEnd('parse'); // parse: 12ms
console.time('render');
renderItems(items);
console.timeEnd('render'); // render: 34ms
console.timeEnd('total'); // total: 135ms
console.assert
// Only logs when the condition is FALSE
const age = 15;
console.assert(age >= 18, 'User must be 18 or older, got:', age);
// Assertion failed: User must be 18 or older, got: 15
// Great for invariant checking during development
function processOrder(order: Order) {
console.assert(order.items.length > 0, 'Order has no items', order);
console.assert(order.total > 0, 'Order total is zero', order);
}
console.trace
function handleClick() {
processEvent();
}
function processEvent() {
updateState();
}
function updateState() {
console.trace('State update triggered');
// Shows the full call stack:
// updateState @ app.js:12
// processEvent @ app.js:8
// handleClick @ app.js:4
}
console.dir
// console.log shows the HTML representation of a DOM element
console.log(document.body); // Shows the HTML tree
// console.dir shows the JavaScript object properties
console.dir(document.body); // Shows properties: classList, children, style, etc.
Styled Console Output
console.log(
'%c WARNING %c This action is irreversible',
'background: #f59e0b; color: black; padding: 2px 6px; border-radius: 3px; font-weight: bold;',
'color: #f59e0b;',
);
Network Tab
Filtering Requests
Type these in the Network tab filter box:
method:POST # Only POST requests
status-code:404 # Only 404 responses
larger-than:100k # Responses larger than 100KB
domain:api.example.com # Only requests to a specific domain
-domain:fonts.googleapis.com # Exclude a domain
has-response-header:set-cookie # Requests that set cookies
mime-type:application/json # Only JSON responses
Block Specific Requests
Right-click on a request and select “Block request URL” or “Block request domain.” This is useful for testing:
- What happens when a third-party script fails to load?
- Does the page work without analytics?
- What does the site look like without web fonts?
Throttling
Use the Network throttle dropdown to simulate slow connections. Custom profiles:
- Click the throttle dropdown
- Select “Add…” to create a custom profile
- Set download/upload speed and latency
Useful presets:
- Slow 3G: 400 Kbps down, 400ms latency
- Fast 3G: 1.5 Mbps down, 150ms latency
- Offline: Test offline behavior
Copy as cURL/fetch
Right-click any request and select:
- Copy as cURL: Paste into terminal to replay the exact request
- Copy as fetch: Paste into console or code to replay with JavaScript
Override Responses
In the Sources tab, you can set up local overrides:
- Open Sources tab
- Go to the Overrides sub-tab
- Click “Select folder for overrides”
- Now right-click any network response and select “Override content”
- Edit the file to test changes without modifying the server
Performance Tab
Recording a Profile
- Open the Performance tab
- Click the record button (circle icon)
- Perform the action you want to profile
- Click stop
Reading the Flame Chart
The flame chart shows what the browser was doing on each millisecond:
- Blue (Loading): Network requests, HTML parsing
- Yellow (Scripting): JavaScript execution
- Purple (Rendering): Style calculation, layout
- Green (Painting): Paint and compositing
Look for:
- Long yellow bars: JavaScript blocking the main thread. Click to see the function name and source location.
- Forced reflow: Red triangles indicate layout thrashing. The browser had to recalculate layout synchronously.
- Long tasks: Any task over 50ms is flagged. These are your INP culprits.
Diagnosing Layout Thrashing
// BAD: reads then writes in a loop (forces layout on each read)
const elements = document.querySelectorAll('.item');
elements.forEach((el) => {
const height = el.offsetHeight; // READ (forces layout)
el.style.height = height * 2 + 'px'; // WRITE (invalidates layout)
});
// GOOD: batch reads then batch writes
const heights = Array.from(elements).map((el) => el.offsetHeight); // All reads
elements.forEach((el, i) => {
el.style.height = heights[i] * 2 + 'px'; // All writes
});
In the Performance tab, layout thrashing appears as alternating purple (layout) and yellow (scripting) bars, much slower than a single layout pass.
Performance Monitor (Real-Time)
Open the Command Menu (Ctrl+Shift+P / Cmd+Shift+P) and type “Performance Monitor.” This shows live graphs of:
- CPU usage
- JS heap size
- DOM nodes count
- Layouts/sec
- Style recalcs/sec
Watch the DOM nodes count. If it keeps growing, you have a memory leak.
Memory Tab
Taking a Heap Snapshot
- Open Memory tab
- Select “Heap snapshot”
- Click “Take snapshot”
- Perform the action that might leak
- Take another snapshot
- Select “Comparison” view between snapshots
Finding Leaks
Look for:
- Detached DOM trees: Elements removed from the DOM but still referenced by JavaScript. Filter for “Detached” in the snapshot.
- Growing arrays/maps: Data structures that grow without bounds.
- Event listeners: Listeners added but never removed.
// Common leak: event listeners not cleaned up
class Component {
private handler = () => this.update();
mount() {
window.addEventListener('resize', this.handler);
}
// MUST call this to prevent leaks
unmount() {
window.removeEventListener('resize', this.handler);
}
}
Allocation Timeline
- Select “Allocation instrumentation on timeline”
- Click start
- Interact with the page
- Click stop
- Blue bars show allocations that are still alive (potential leaks)
Elements Tab
Computed Styles
The Computed tab in the Styles pane shows the final computed value of every CSS property. Click the arrow next to any property to see the cascade: which rules set this value and which were overridden.
Force Element State
Right-click an element in the Elements panel and select “Force state” to toggle :hover, :active, :focus, :focus-within, and :visited states. This lets you inspect styles that only appear on interaction.
CSS Overview
Open Command Menu and type “CSS Overview.” Click “Capture overview” to get:
- Color palette used across the page
- Font statistics
- Unused declarations
- Media queries summary
- Contrast issues
Animations Panel
Open Command Menu and type “Animations.” This panel shows all running CSS and WAAPI animations with a timeline. You can:
- Slow down animations (25%, 10% speed)
- Pause all animations
- Scrub through the timeline
- Modify timing functions visually
Sources Tab
Conditional Breakpoints
Right-click a line number and select “Add conditional breakpoint”:
// Only break when userId equals 42
// Condition: userId === 42
Logpoints
Right-click a line number and select “Add logpoint.” This logs a message without pausing execution:
// Logpoint expression:
'User logged in:', userId, 'at', new Date().toISOString()
Logpoints are better than adding console.log to your source because they do not modify the code.
Blackbox Scripts
Right-click a file in the Sources tab and select “Add script to ignore list.” This tells the debugger to skip through library code (React internals, lodash, etc.) when stepping through.
Snippets
Sources > Snippets lets you save and run JavaScript snippets:
// Snippet: "Check Accessibility"
(async () => {
const script = document.createElement('script');
script.src = 'https://unpkg.com/axe-core/axe.min.js';
document.head.appendChild(script);
script.onload = async () => {
const results = await axe.run();
console.table(results.violations.map((v) => ({
impact: v.impact,
description: v.description,
nodes: v.nodes.length,
})));
};
})();
Coverage Tab
Open Command Menu and type “Coverage.” Click the reload button. This shows:
- How much CSS is unused on the current page (red = unused)
- How much JavaScript is unused (red = not executed)
This is essential for identifying code splitting opportunities. If 70% of your main CSS file is unused, it is time to extract critical CSS.
Quick Tips
-
$0in console: References the currently selected element in the Elements panel.$1is the previously selected. -
copy()in console:copy(someObject)copies the value to clipboard as a string. -
monitorEvents(element, 'click'): Logs all click events on an element. UseunmonitorEvents()to stop. -
getEventListeners($0): Shows all event listeners on the selected element. -
Design Mode: Type
document.designMode = 'on'in the console to edit any text on the page directly. -
Dark mode toggle:
Renderingtab > “Emulate CSS media feature prefers-color-scheme” to test dark mode without changing OS settings.
Summary
DevTools is a debugging and profiling powerhouse that most developers barely scratch the surface of. The console has methods for structured output, timing, and assertions. The Network tab lets you throttle, block, and override requests. The Performance tab reveals exactly where time is spent. The Memory tab finds leaks. And hidden features like Coverage, CSS Overview, and Logpoints save hours of debugging. Spend an afternoon exploring each tab — it pays for itself in the first week.
Related articles
- JavaScript How to Find and Fix JavaScript Memory Leaks
Learn how to detect, diagnose, and fix JavaScript memory leaks using Chrome DevTools heap snapshots, allocation timelines, and common leak patterns.
- Web The Web Animations API: CSS vs JavaScript Animations
A practical guide to the Web Animations API (WAAPI): creating animations in JavaScript, controlling playback, composing effects, performance tips, and when to use CSS vs JS.
- Web Measuring and Fixing Core Web Vitals
Hands-on techniques for measuring LCP, INP, and CLS with real code: the web-vitals library, Performance Observer, Chrome UX Report, and step-by-step fixes for each metric.
- Web Web Workers and Multithreading in the Browser
Move heavy computation off the main thread: dedicated Workers, SharedWorker, service workers, Comlink for ergonomic worker APIs, and patterns for CPU-intensive tasks.