Chrome DevTools Complete Guide
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:
- Conditional breakpoints - Right-click a line number, choose "Add conditional breakpoint", and enter a JavaScript expression. The breakpoint only triggers when the condition is true. Example:
user.id === 'abc123' - Logpoints - Right-click a line number, choose "Add logpoint". This logs a message to the Console when that line executes, without pausing. It's like adding a
console.log()without modifying your code. I use these constantly in production debugging. - DOM breakpoints - Set in the Elements panel but trigger in Sources. They pause when a specific DOM node is modified.
- XHR/Fetch breakpoints - In the Sources panel's right sidebar, under "XHR/Fetch Breakpoints", you can break when a request URL contains a specific string. Enter "api/users" to break whenever that endpoint is called.
- Event listener breakpoints - Also in the right sidebar. Expand categories and check specific events. I use "Script > Script First Statement" to break at the very start of any new script execution.
Debugging Workflow
When the debugger pauses at a breakpoint, here's what I look at:
- 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. - The Call Stack pane shows how you got here. Click any frame to see the calling code and its scope.
- Hover over any variable in the source code to see its current value.
- 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:
- Failed requests (red entries). Filter by clicking the "Has blocked cookies" or sort by status column.
- 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.
- 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:
- Long yellow blocks - JavaScript execution taking too long. Anything over 50ms on the main thread is a potential jank source.
- Purple blocks - Layout recalculations. If you see many of these in a row, you might have a "layout thrashing" problem where JavaScript reads layout properties and then writes style changes in a loop.
- Green blocks - Paint operations. Frequent, large paint areas indicate missing
will-changeortransformoptimizations. - Red triangles at the top of the timeline - Dropped frames. These are the moments users perceive as jank.
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:
- Opened Performance panel, started recording, scrolled the page.
- Stopped recording. Saw red triangles (dropped frames) throughout the scroll.
- Zoomed into a dropped frame. Found a wide purple "Recalculate Style" block.
- Clicked it. DevTools showed the element that triggered the recalculation - my floating panel.
- The panel was using
position: fixedwith a box shadow, causing a full-page repaint on every frame during scroll. - Fix: added
will-change: transformto 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:
- Local Storage - key-value pairs, editable inline
- Session Storage - same but session-scoped
- IndexedDB - structured data, expandable tree view
- Cookies - with all attributes (domain, path, expiry, SameSite, Secure, HttpOnly)
- Cache Storage - service worker caches, viewable by cache name
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:
- Force update a service worker
- Unregister it
- Simulate offline mode
- Trigger push events
- Inspect the service worker's console output
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:
- Images without explicit width/height (causes layout shift)
- Render-blocking resources that could be deferred
- Missing ARIA labels on interactive elements
- Text without sufficient contrast ratios
- JavaScript that takes too long to parse and execute
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:
- Take a heap snapshot (baseline).
- Perform the action you suspect is leaking (open a dialog, navigate, scroll, etc.).
- Undo the action (close the dialog, navigate back).
- Run garbage collection (click the trash can icon).
- Take another heap snapshot.
- 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:
- 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.
- 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
- Open Network panel. Reload the page with Cmd+Shift+R (hard reload). Look at the waterfall. Are requests queuing? Is one resource blocking everything?
- Check the "DOMContentLoaded" and "Load" times at the bottom of Network panel.
- Switch to Performance panel. Record a page load. Look for "Long Task" warnings (yellow blocks longer than 50ms).
- Run Lighthouse for specific recommendations.
- 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
- Open Network panel. Filter by
Fetch/XHR. - Find the failed request (red text or non-200 status).
- Click it. Check the Headers tab for the request URL, method, and headers.
- Check the Payload tab to see what was sent.
- Check the Response tab to see the error message from the server.
- Right-click > "Copy as fetch" to reproduce it in Console.
- If you need to modify and retry: paste in Console, edit the parameters, hit Enter.
Debugging CSS Layout Issues
- Select the problematic element in Elements panel.
- Check the Computed tab for unexpected values.
- Look for crossed-out styles in the Styles pane (overridden rules).
- Use the box model diagram to check for unexpected margins or padding.
- Toggle the Grid/Flexbox overlay to visualize the layout container.
- Check for
overflow: hiddenon 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:
- Open DevTools on the page where your content script runs.
- In Sources, look under "Content scripts" in the left sidebar. Your extension's content scripts appear there.
- Set breakpoints in your content script code.
- In Console, make sure the execution context dropdown shows your extension's context, not the page's main context.
- For service worker debugging, go to
chrome://extensionsand 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:
- Preferences > Sources > Enable CSS source maps and Enable JavaScript source maps - Both should be on. They let you debug your original source code instead of compiled/minified versions.
- Preferences > Elements > Show user agent shadow DOM - Turn this on to see the internal structure of built-in elements like
<video>,<input type="range">, etc. - Experiments > Protocol Monitor - Shows raw Chrome DevTools Protocol messages. Useful if you're building DevTools extensions or debugging remote inspection setups.
- Preferences > Network > Preserve log - Keeps network entries across page navigations. Essential when debugging redirect chains.
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.