Chrome DevTools Complete Guide

By Michael Lip · March 18, 2026 · 22 min read

I open Chrome DevTools maybe 200 times a day. That's not an exaggeration. When you're building Chrome extensions, DevTools is where you live. It's where you debug content scripts, inspect service workers, monitor network requests, and figure out why your popup is 3 pixels off.

Most developers use about 20% of what DevTools offers. The Console and Elements panel, maybe the Network tab. That's a shame, because the other 80% is where the real power is. The Performance panel alone has saved me dozens of hours tracking down jank. The Application panel is essential for anyone working with service workers or storage APIs.

This is everything I actually use, organized by panel. No filler. Just the stuff that matters for real debugging work.

Opening DevTools

The basics, but I still see developers reaching for the menu bar.

Action Mac Windows/Linux
Open DevTools (last panel) Cmd+Option+I F12 or Ctrl+Shift+I
Open Elements panel Cmd+Option+C Ctrl+Shift+C
Open Console Cmd+Option+J Ctrl+Shift+J
Open Command Menu Cmd+Shift+P Ctrl+Shift+P
Toggle device toolbar Cmd+Shift+M Ctrl+Shift+M
Inspect element under cursor Cmd+Shift+C Ctrl+Shift+C

The Command Menu (Cmd+Shift+P) is the single most important shortcut. It's like Spotlight or VS Code's command palette but for DevTools. You can switch panels, toggle settings, take screenshots, enable experiments - all without touching a mouse. I use it constantly.

Elements Panel

The Elements panel shows you the live DOM tree and computed styles. "Live" is the key word. This isn't the static HTML source. It's the current state of the DOM, including everything JavaScript has added, removed, or modified.

What I Actually Use It For

Inspecting styles is obvious. But here are the things I do in Elements that most tutorials skip:

Force element state. Right-click any element, go to "Force state", and toggle :hover, :active, :focus, or :visited. This is invaluable when debugging hover states that disappear the moment you move your mouse to the DevTools window.

Edit the DOM directly. Double-click any element to edit its tag, attributes, or text content. You can also drag elements to reorder them. I use this when prototyping layout changes before touching the actual code.

Break on DOM changes. Right-click an element, choose "Break on", then select "subtree modifications", "attribute modifications", or "node removal". DevTools will pause JavaScript execution the next time that element is modified. This is how I track down which script is mutating a DOM node I care about.

// When you need to find what's changing an element:
// 1. Right-click the element in Elements panel
// 2. Break on > subtree modifications
// 3. The debugger pauses at the exact line of code
// that's modifying your element

Computed tab. The Computed tab shows every CSS property applied to an element, with the final computed value. When you're fighting specificity issues across multiple stylesheets, this tells you exactly which rule won and why. Click the arrow next to any property to jump to the source.

The Box Model Diagram

At the top of the Computed tab sits the box model visualization. Hover over any section (margin, border, padding, content) and it highlights on the page. I know this seems basic but I still catch myself manually calculating element sizes instead of just checking this diagram. Old habits.

CSS Grid and Flexbox Debugging

Chrome added overlay tools for Grid and Flexbox layouts. When you select an element with display: grid or display: flex, you get a badge next to it. Click the badge to toggle an overlay showing grid lines, track sizes, and area names.

For Grid specifically, the Layout pane (sidebar tab) lets you customize the overlay colors and toggle different aspects. I've found this more useful than any third-party grid debugging tool.

Console Panel

Everyone uses Console for console.log(). That's fine. But the Console is actually a full JavaScript REPL with access to the page's execution context.

Beyond console.log

// console.table() - formats arrays/objects as sortable tables
console.table(document.querySelectorAll('a'), ['href', 'textContent']);

// console.group() / console.groupEnd() - collapsible groups
console.group('API Response');
console.log('Status:', response.status);
console.log('Data:', response.data);
console.groupEnd();

// console.time() / console.timeEnd() - quick benchmarking
console.time('render');
renderComponent();
console.timeEnd('render'); // render: 14.32ms

// console.assert() - only logs when condition is false
console.assert(items.length > 0, 'Items array is empty!');

// console.trace() - prints a stack trace
console.trace('Called from here');

console.table() is probably my most-used variant after plain log(). When you're working with arrays of objects, a formatted table is infinitely easier to scan than nested object output.

Console Utilities

The Console has built-in utility functions that only work in the Console context (not in your actual code):

// $0 - references the currently selected element in Elements panel
$0.style.border = '2px solid red';

// $() - shorthand for document.querySelector()
$('.nav-item')

// $$() - shorthand for document.querySelectorAll() (returns array, not NodeList)
$$('img').map(img => img.src)

// $_ - references the return value of the last expression
2 + 2;
$_ * 10; // 40

// copy() - copies any value to clipboard as a string
copy($$('a').map(a => a.href).join('\n'));

// monitor(fn) - logs every call to a function with arguments
monitor(myFunction);

// monitorEvents(element, events) - logs DOM events
monitorEvents($0, 'click');

That copy() function is gold. I use it constantly to extract data from pages. Need all the links on a page? All the image URLs? All the class names on a particular component? One line in the Console.

Console Filtering

When a page is noisy with console output (third-party scripts love to spam warnings), use the filter bar. You can filter by text, regex, or message type (errors, warnings, info). You can also filter by source URL to only see messages from your own code.

The "Selected context only" dropdown at the top lets you switch between execution contexts - the main page, iframes, web workers, and (critically for extension developers) content script contexts. If you're debugging a Chrome extension, you need to select the right context or your code won't have access to the right variables.

Sources Panel

Sources is DevTools' built-in code editor and debugger. It's where you set breakpoints, step through code, and inspect variable values during execution.

Setting Breakpoints

Click any line number in a source file to set a breakpoint. But that's the simplest form. Here are the breakpoint types I use regularly:

Debugging Workflow

When the debugger pauses at a breakpoint, here's what I look at:

  1. The Scope pane shows all variables in the current scope (Local, Closure, Global). This is faster than adding console.log() for every variable you want to inspect.
  2. The Call Stack pane shows how you got here. Click any frame to see the calling code and its scope.
  3. Hover over any variable in the source code to see its current value.
  4. Use the Console while paused to evaluate expressions in the current scope.

Stepping controls:

Action Shortcut What It Does
Resume F8 Continue until next breakpoint
Step Over F10 Execute current line, move to next
Step Into F11 Enter the function being called
Step Out Shift+F11 Finish current function, return to caller

Workspaces

You can connect a local folder to DevTools Sources so that edits you make in DevTools are saved directly to your source files. This is genuinely useful for CSS tweaking. Edit styles in Elements, see the changes live, and have them automatically persisted.

Go to Sources > Filesystem > Add folder to workspace. Chrome will ask for permission to read and write to that folder. Once connected, source files show a green dot indicating they're linked to your local files.

Snippets

Sources > Snippets lets you save and run small JavaScript files. I keep a collection of utility snippets:

// Snippet: List all event listeners on the page
const allElements = document.querySelectorAll('*');
const listeners = [];
allElements.forEach(el => {
 const evts = getEventListeners(el);
 if (Object.keys(evts).length > 0) {
 listeners.push({
 element: el,
 tagName: el.tagName,
 id: el.id,
 events: Object.keys(evts)
 });
 }
});
console.table(listeners);

Run any snippet with Cmd+Enter (Mac) or Ctrl+Enter (Windows). Snippets persist across browser sessions.

Network Panel

The Network panel records every HTTP request the page makes. This includes document loads, scripts, stylesheets, images, XHR/Fetch calls, WebSocket messages, and more.

What I Look At First

When I open Network for debugging, I check three things immediately:

  1. Failed requests (red entries). Filter by clicking the "Has blocked cookies" or sort by status column.
  2. Request timing. Click any request, go to the Timing tab. If "Waiting for server response" (TTFB) is high, the problem is server-side. If "Content Download" is high, the response is too large.
  3. Waterfall. The waterfall chart on the right shows request timing visually. Long vertical gray bars mean the browser is waiting for a connection. Requests stacked up vertically mean they're queued behind other requests.

Filtering Requests

The filter bar supports text search, regex, and type filters. But it also supports special commands:

// Filter by type
method:POST
status-code:404
domain:api.example.com
has-response-header:set-cookie
larger-than:1M
mime-type:application/json

// Combine filters
method:POST domain:api.example.com
status-code:200 larger-than:100k

// Negative filters (prefix with -)
-domain:google-analytics.com

I use -domain:google-analytics.com -domain:googletagmanager.com on almost every site to filter out analytics noise.

Throttling

The throttle dropdown (default: "No throttling") lets you simulate slow connections. "Slow 3G" and "Fast 3G" presets are built in, or you can create custom profiles. I test every extension I build on "Slow 3G" to make sure the UI doesn't break when requests take seconds instead of milliseconds.

You can also right-click a request and select "Replay XHR" to re-send it. Or "Copy as fetch" to get the JavaScript code to reproduce the request in the Console.

Block Requests

Right-click any request and choose "Block request URL" or "Block request domain". This is incredibly useful for testing how your page handles failed resource loads. What happens if the CDN is down? What if a third-party script fails to load? Block it and find out.

You can also use the Network request blocking pane (accessible from the drawer or Command Menu) to set up URL patterns to block. I use this when testing ad blocker resistance or testing my extensions' behavior when certain APIs are unavailable.

Performance Panel

This is the panel most developers avoid because it looks intimidating. And I get it - the flame chart is dense. But once you know what to look for, Performance becomes the most powerful debugging tool in DevTools.

Recording a Trace

Click the record button or press Cmd+E, interact with the page, then stop recording. DevTools captures everything: JavaScript execution, layout calculations, paint operations, compositing, garbage collection.

For page load analysis, use the reload button (circular arrow) instead. It starts recording, refreshes the page, and stops after load completes.

Reading the Flame Chart

The flame chart shows function calls stacked vertically (caller on top, callee below) and spread horizontally across time. Width equals duration. So a wide block means a long-running function.

What I look for:

Real Debugging Example

I was working on an extension that injected a floating panel into web pages. Users reported that scrolling became choppy on some sites. Here's how I diagnosed it:

  1. Opened Performance panel, started recording, scrolled the page.
  2. Stopped recording. Saw red triangles (dropped frames) throughout the scroll.
  3. Zoomed into a dropped frame. Found a wide purple "Recalculate Style" block.
  4. Clicked it. DevTools showed the element that triggered the recalculation - my floating panel.
  5. The panel was using position: fixed with a box shadow, causing a full-page repaint on every frame during scroll.
  6. Fix: added will-change: transform to the panel, which promoted it to its own compositor layer. Scroll was smooth after that.

Total debugging time: about 4 minutes. Without the Performance panel, I would have been guessing for hours.

Application Panel

The Application panel is where you inspect storage, service workers, and the manifest. For Chrome extension developers, this panel is essential.

Storage

You can view and edit:

For Chrome extensions, the storage here is the webpage's storage, not your extension's storage. To inspect extension storage, you need to open DevTools on the extension's own pages (popup, options page) or the service worker. Go to chrome://extensions, find your extension, and click "Inspect views: service worker".

// Quick way to dump all extension storage from Console
// (run in extension's DevTools context)
chrome.storage.local.get(null, data => console.log('Local:', data));
chrome.storage.sync.get(null, data => console.log('Sync:', data));
chrome.storage.session.get(null, data => console.log('Session:', data));

Service Workers

The Service Workers section shows registered service workers for the current origin. You can:

For extension development, the service worker view is critical for debugging MV3 extensions. The service worker can become inactive when idle, and bugs often surface in the lifecycle transitions. I always keep the "Update on reload" checkbox checked during development.

Manifest

For Progressive Web Apps, the Manifest section parses and displays the web app manifest. It shows icons, display mode, start URL, and any manifest errors. Useful for PWA development but not something I use daily.

Lighthouse Panel

Lighthouse runs automated audits against the current page and generates a report with scores for Performance, Accessibility, Best Practices, SEO, and Progressive Web App compliance.

How I Use It

I don't use Lighthouse for its scores. Chasing a perfect 100 on every metric is a waste of time. I use it for the specific, actionable recommendations it generates.

Run an audit. Ignore the top-level numbers. Scroll down to the "Opportunities" and "Diagnostics" sections. These tell you exactly what to fix and how much improvement to expect. Things like:

The accessibility audit alone is worth running on every project. It catches things that are easy to fix but hard to notice manually, like missing alt text, improper heading hierarchy, and insufficient touch target sizes.

Running from Command Line

You can also run Lighthouse from the terminal, which is useful for CI/CD pipelines:

# Install globally
npm install -g lighthouse

# Run an audit
lighthouse https://example.com --output=html --output-path=./report.html

# Run specific categories only
lighthouse https://example.com --only-categories=performance,accessibility

# Output as JSON for programmatic processing
lighthouse https://example.com --output=json --output-path=./report.json

I run Lighthouse in CI for the sites I maintain. Not for score thresholds (those are fragile), but to catch regressions. If accessibility score drops more than 5 points, the build fails.

Memory Panel

Memory leaks are among the hardest bugs to diagnose. The Memory panel gives you three tools to find them.

Heap Snapshots

A heap snapshot captures every object in JavaScript memory at a point in time. The workflow for finding leaks:

  1. Take a heap snapshot (baseline).
  2. Perform the action you suspect is leaking (open a dialog, navigate, scroll, etc.).
  3. Undo the action (close the dialog, navigate back).
  4. Run garbage collection (click the trash can icon).
  5. Take another heap snapshot.
  6. In the second snapshot, select "Comparison" view and compare with snapshot 1.

Objects that exist in snapshot 2 but not in snapshot 1 are potential leaks. Sort by "Size Delta" to find the biggest offenders.

Allocation Timeline

The allocation timeline records memory allocations over time. Blue bars show allocations that are still alive. Gray bars show allocations that were garbage collected. If you see a pattern of blue bars growing steadily, you have a leak.

I used this to find a memory leak in one of my extensions where I was adding event listeners to page elements in a content script but never removing them when the extension's UI was closed. Each time the user opened and closed the panel, new listeners accumulated. The allocation timeline showed a clear staircase pattern of growing DOM node references.

Allocation Sampling

Allocation sampling is lighter-weight than the timeline. It periodically samples the heap and builds a flame chart of allocation call stacks. Good for profiling memory-intensive operations without the overhead of recording every single allocation.

Recorder Panel

The Recorder panel lets you record and replay user interactions. Think of it as a lightweight Selenium built into the browser. You can record a workflow (click here, type there, navigate here), then replay it automatically.

I use it for two things:

  1. Bug reproduction. Record the steps to reproduce a bug, then replay to verify the fix. You can share the recording as a JSON file with other developers.
  2. Performance testing. Record a user flow, then replay it while the Performance panel is recording. This gives you consistent, reproducible performance measurements.

You can export recordings as Puppeteer scripts, which is handy for converting manual test cases into automated tests.

Essential Keyboard Shortcuts

Shortcut (Mac) Shortcut (Win/Linux) Action
Cmd+Shift+P Ctrl+Shift+P Command Menu (the most useful shortcut)
Cmd+P Ctrl+P Open file by name in Sources
Cmd+Shift+F Ctrl+Shift+F Search across all sources
Cmd+D Ctrl+D Select next occurrence (in Sources editor)
Cmd+[ / Cmd+] Ctrl+[ / Ctrl+] Switch panels left/right
Esc Esc Toggle Console drawer
Cmd+K Ctrl+L Clear Console
H H Hide selected element (in Elements panel)

The H key in Elements is underrated. Select any element and press H to toggle its visibility. It adds visibility: hidden which hides the element but preserves its layout space. Great for quickly checking what's behind an overlay without disrupting the page layout.

Debugging Workflows I Use Daily

Finding Why a Page Is Slow

  1. Open Network panel. Reload the page with Cmd+Shift+R (hard reload). Look at the waterfall. Are requests queuing? Is one resource blocking everything?
  2. Check the "DOMContentLoaded" and "Load" times at the bottom of Network panel.
  3. Switch to Performance panel. Record a page load. Look for "Long Task" warnings (yellow blocks longer than 50ms).
  4. Run Lighthouse for specific recommendations.
  5. Check the Coverage tab (Cmd+Shift+P > "Show Coverage"). It shows how much of each JavaScript and CSS file is actually used. Red bars mean unused code.

Debugging a Failed API Call

  1. Open Network panel. Filter by Fetch/XHR.
  2. Find the failed request (red text or non-200 status).
  3. Click it. Check the Headers tab for the request URL, method, and headers.
  4. Check the Payload tab to see what was sent.
  5. Check the Response tab to see the error message from the server.
  6. Right-click > "Copy as fetch" to reproduce it in Console.
  7. If you need to modify and retry: paste in Console, edit the parameters, hit Enter.

Debugging CSS Layout Issues

  1. Select the problematic element in Elements panel.
  2. Check the Computed tab for unexpected values.
  3. Look for crossed-out styles in the Styles pane (overridden rules).
  4. Use the box model diagram to check for unexpected margins or padding.
  5. Toggle the Grid/Flexbox overlay to visualize the layout container.
  6. Check for overflow: hidden on parent elements that might be clipping content.

Debugging Extension Content Scripts

This is specific to Chrome extension development, but it's relevant if you're building extensions:

  1. Open DevTools on the page where your content script runs.
  2. In Sources, look under "Content scripts" in the left sidebar. Your extension's content scripts appear there.
  3. Set breakpoints in your content script code.
  4. In Console, make sure the execution context dropdown shows your extension's context, not the page's main context.
  5. For service worker debugging, go to chrome://extensions and click "Inspect views: service worker".

Hidden Features Worth Knowing

CSS Overview

Open Command Menu, type "CSS Overview". This generates a summary of all CSS on the page: color palette, font usage, unused declarations, and media queries. I use it when inheriting a project to quickly understand the design system.

Rendering Tab

Open from the drawer (Esc to toggle drawer, then three-dot menu > Rendering). Turn on "Paint flashing" to see green rectangles wherever Chrome is repainting. Turn on "Layout Shift Regions" to see blue highlights when layout shifts happen. These visual debugging tools make performance issues immediately visible.

Override Network Responses

In the Sources panel > Overrides, you can map network URLs to local files. This lets you serve a modified version of any file without touching the server. I use this to test fixes on production sites before deploying - override the JavaScript file, make the fix locally, refresh, and verify.

Animations Panel

Open from the drawer. It captures and lets you scrub through CSS animations and transitions. You can slow them down, replay them, and inspect the timing curves. When an animation doesn't feel right, being able to scrub through it at 10% speed makes the problem obvious.

Changes Tab

Open from the drawer. Shows a diff of every CSS and JavaScript change you've made in DevTools during the current session. Before you close DevTools, check Changes to make sure you transfer all your tweaks back to your source code. I've lost an hour of CSS work more than once by forgetting to do this.

Settings Worth Changing

Open DevTools settings with F1 or the gear icon. Here are the settings I change on every fresh Chrome install:

Wrapping Up

DevTools is one of those tools where the time you invest learning it pays back immediately. Every trick in this guide has saved me real time on real projects. The Performance panel alone is responsible for at least a dozen performance fixes in my extensions that I would have found much later (or never) without it.

My suggestion: pick one panel you don't know well and spend an hour exploring it on a real project. Don't just read about it. Open it. Click things. Break things. That's how I learned most of what's in this guide.

And if you're building Chrome extensions, DevTools isn't optional. It's your primary development environment. Get comfortable with every panel. Your debugging sessions will go from "Why isn't this working?" to "Found it" in minutes instead of hours.

ML
Michael Lip
Chrome extension engineer. Built 16 extensions with 4,700+ users. Top Rated Plus on Upwork with $400K+ earned across 47 contracts. All extensions are free, open source, and collect zero data.
zovo.one GitHub