Skip to content
Codeloom
Web

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.

·8 min read · By Codeloom
Intermediate 13 min read

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:

  1. Click the throttle dropdown
  2. Select “Add…” to create a custom profile
  3. 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:

  1. Open Sources tab
  2. Go to the Overrides sub-tab
  3. Click “Select folder for overrides”
  4. Now right-click any network response and select “Override content”
  5. Edit the file to test changes without modifying the server

Performance Tab

Recording a Profile

  1. Open the Performance tab
  2. Click the record button (circle icon)
  3. Perform the action you want to profile
  4. 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

  1. Open Memory tab
  2. Select “Heap snapshot”
  3. Click “Take snapshot”
  4. Perform the action that might leak
  5. Take another snapshot
  6. 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

  1. Select “Allocation instrumentation on timeline”
  2. Click start
  3. Interact with the page
  4. Click stop
  5. 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

  1. $0 in console: References the currently selected element in the Elements panel. $1 is the previously selected.

  2. copy() in console: copy(someObject) copies the value to clipboard as a string.

  3. monitorEvents(element, 'click'): Logs all click events on an element. Use unmonitorEvents() to stop.

  4. getEventListeners($0): Shows all event listeners on the selected element.

  5. Design Mode: Type document.designMode = 'on' in the console to edit any text on the page directly.

  6. Dark mode toggle: Rendering tab > “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.