Chrome DevTools Cheatsheet - Front-end Debugging Reference
Console.log poking is a poor substitute for stepping through a live page. This reference covers Elements and DOM breakpoints, console tricks, Network waterfall and request replay, Performance flame charts, and Application storage. Use it when a page works on your laptop but misbehaves in production — isolate a layout bug, find a slow request, or trace a storage leak. After reading you inspect, measure and fix frontend problems from inside the browser instead of guessing.
Typical Use Case
For web developers and testers who need to pin down front-end problems precisely. Six panels form one investigation path: Console for logging, timing, counting and interactive element picking with $0; Elements for editing HTML, forcing pseudo-states, and breaking on DOM changes to find who changed a style; Network for filtering, throttling, replaying requests and copying a failed call as cURL; Performance for locating jank in the main thread and flame chart; Application for local storage, cookies, IndexedDB and service workers. The two highest-value habits are Ctrl+Shift+C followed by $0 to verify a change live, and turning a failed request into a cURL command you can rerun in a terminal.
Shortcuts 8
F12 or Cmd+Option+IF12 or Ctrl+Shift+ICmd+Option+JCmd+Option+ECmd+Shift+CCmd+Shift+PCmd+PCmd+Shift+MConsole Commands 12
console.log("message")console.table(array)console.time("label") / console.timeEnd("label")console.count("label")console.group("group") / console.groupEnd()console.assert(condition, "error")console.dir(element)copy(document.title)$0$("selector")$$("selector")monitorEvents(element, "click")Elements Debugging 9
Edit as HTMLToggle Edit as HTMLForce Element State (:hover, :active)Break on: subtree modificationsBreak on: attribute modificationsStore as global variableCopy selectorCopy XPathDelete nodeNetwork Analysis 10
Disable cacheThrottling: Slow 3GFilter: Doc, JS, CSS, Img, XHRFilter: -domain:example.comFilter: status-code:404Filter: is:from-cacheReplay XHRCopy as cURLSave as...Block request URLPerformance 7
RecordScreenshotsMemoryMain threadFlame ChartBottom-Up / Call TreeSummaryApplication Storage 8
Local StorageSession StorageCookiesIndexedDBCache StorageClear site dataService WorkersManifestParameter matrix
| Parameter | Effect | Example |
|---|---|---|
F12 / Cmd+Option+I | Open DevTools (macOS) | F12 |
F12 / Ctrl+Shift+I | Open DevTools (Win/Linux) | Ctrl + Shift + I |
Cmd+Option+J | Open Console (macOS) | Cmd + Option + J |
Cmd+Option+E | Open Elements (macOS) | Cmd + Option + E |
Cmd+Shift+C | Element selection mode | Cmd + Shift + C |
Cmd+Shift+P | Open the command menu | Cmd + Shift + P |
Cmd+P | Quickly open a file (Sources panel) | Cmd + P |
Cmd+Shift+M | Toggle device emulation | Cmd + Shift + M |
console.log("message") | Print a log message | console.log("message") |
console.table(array) | Print an array/object as a table | console.table(rows) |
console.time("label") / console.timeEnd("label") | Time an operation and print the elapsed time | console.time("render"); console.timeEnd("render"); |
console.count("label") | Count how many times the same log has appeared | console.count("render") |
console.group("group") / console.groupEnd() | Group log output | console.group("init"); console.groupEnd(); |
console.assert(condition, "error") | Print an assertion message when the condition is false | console.assert(el, "error") |
console.dir(element) | Expand and print a DOM object | console.dir($0) |
copy(document.title) | Copy the result to the clipboard | copy(document.title) |
$0 | Reference the currently selected DOM element | $0.style.color = "red"; |
$("selector") | Query a single element (similar to querySelector) | $(".card") |
$$("selector") | Query all matching elements | $$("li") |
monitorEvents(element, "click") | Monitor event triggers on the target element | monitorEvents($0, "click") |
Edit as HTML | Edit the element HTML directly | Right-click in Elements → Edit as HTML |
Force Element State (:hover, :active) | Force element state to debug interactive styles | Right-click node → Force Element State → :hover |
Break on: subtree modifications | Break when the DOM subtree changes | Right-click node → Break on → subtree modifications |
Break on: attribute modifications | Break when an attribute changes | Right-click node → Break on → attribute modifications |
Store as global variable | Store the node as a global variable for use in the Console | Right-click node → Store as global variable |
Copy selector / Copy XPath | Copy the selector or the XPath path | Right-click node → Copy selector |
Delete node | Delete that DOM node | Right-click node → Delete node |
Disable cache | Disable caching to ensure fresh resources every time | Check Disable cache in the Network panel |
Throttling: Slow 3G | Throttle the network to simulate a slow connection | Select Slow 3G under Throttling |
Filter: Doc, JS, CSS, Img, XHR | Filter requests by resource type | Type XHR in Filter |
Filter: -domain:example.com | Exclude requests by domain | Type -domain:example.com in Filter |
Filter: status-code:404 | Filter by status code | Type status-code:404 in Filter |
Filter: is:from-cache | Show only requests that hit the cache | Type is:from-cache in Filter |
Replay XHR | Replay the selected request | Right-click request → Replay XHR |
Copy as cURL | Copy as a cURL command to replay in the terminal | Right-click request → Copy as cURL |
Save as... | Save the response body to disk | Right-click request → Save as... |
Block request URL | Block requests matching a URL | Right-click request → Block request URL |
Record | Record performance data | Performance panel → Record |
Screenshots | Capture frame-by-frame screenshots during recording | Performance panel → Screenshots |
Memory | Memory analysis view | Performance panel → Memory |
Main thread | Main-thread tasks and timing analysis | Look at the Main thread track |
Flame Chart | Use the flame chart to locate time-consuming functions | Look at the Flame Chart |
Bottom-Up / Call Tree | Bottom-Up / Call Tree perspective | Look at the Call Tree |
Summary | Time distribution summary | Look at the Summary |
Local Storage / Session Storage | View local/session storage | Application → Local Storage |
Cookies | Manage cookies | Application → Cookies |
IndexedDB | View IndexedDB data | Application → IndexedDB |
Cache Storage | View the Service Worker cache | Application → Cache Storage |
Clear site data | Clear all local data for this site | Application → Clear site data |
Service Workers | Service Worker registration and status | Application → Service Workers |
Manifest | View the PWA Manifest | Application → Manifest |
Common pitfalls
SymptomAfter changing code and refreshing, the page still behaves the old way.
CauseThe resources were served from the browser cache, so the locally changed JS/CSS was not re-fetched.
FixOpen DevTools and check Disable cache in the Network panel, or verify again after a hard refresh with Ctrl+Shift+R.
SymptomStyles that only appear on hover are not visible in Elements, and the element cannot be picked either.
CauseThe hover state only takes effect when a real pointer hovers over it; a static DOM has no hover target to act on.
FixRight-click the node and use Force Element State to force :hover; or press Cmd+Shift+C to enter element selection mode and select it directly in Elements.
SymptomA selector in the Console returns null, even though the element clearly exists on the page.
CauseThe element is rendered asynchronously by a framework or hidden in shadow DOM, or the selector syntax is wrong; it may also be a different node with the same name.
FixFirst use $0 to point at the selected element and confirm its structure, then switch to $$("selector") to get the collection and check its length instead of guessing the selector.
SymptomThe Console reports that a variable is undefined, even though it was clearly defined before.
CauseThe context is recreated after a page refresh or navigation, so variables saved earlier with Store as global variable are invalidated along with the document.
FixAfter refreshing, save it again with Store as global variable, or re-reference the selected element directly with $0 in the Console.
SymptomThe API works on the page, but the Network panel shows a bunch of 404s or abnormal statuses.
CauseFilter conditions or cache state affected your observation, and the requests may actually come from a Service Worker rather than the network.
FixUse status-code:404 to filter and locate all failed requests, check Disable cache and replay; then go to Application → Service Workers to confirm whether a cache layer is intercepting them.
SymptomA large portion of the Performance recording is marked unknown, or the recording is very short.
CauseOther tabs were also active during the recording, or the recording window did not cover the operation that actually janks.
FixBefore recording, keep only the current tab visible, start recording from the step that triggers the problem, stop immediately when done, and locate the time-consuming function on the main thread in the Flame Chart.
SymptomAfter an element is removed by a script, the Styles panel still shows the styles it once had, leading you to think they are working.
CauseThe panel keeps the last state of the deleted node, but that node is no longer in the document, so the styles do not apply to any real element.
FixIn Elements, confirm whether the node still exists (if needed, Delete node and see whether it gets reinserted); for a removed node, its styles no longer represent the live behavior.
SymptomAfter editing Local Storage or Cookies, the page behavior does not change, as if nothing was saved.
CauseThe storage panel shows a snapshot of the current document state; writing must be triggered through the page code or manual editing, and some sites also validate same-origin and server-side state.
FixManually change the value, press Enter to write it back and refresh the page to confirm; if it still fails, run a write and then a read in the Console to tell whether the write failed or the logic simply does not read that key.
Troubleshooting
1Quickly find out "who really keeps changing the styles"
Cmd+Shift+C to select the element → right-click → Break on → attribute modifications → re-triggerThe breakpoint pauses when a script modifies that element's attributes, exposing the call stack of the change source directly. If the style comes from a CSS override, check the Styles panel for duplicate declarations with strikethrough or source links and disable them one by one to verify.
2Verify style hypotheses directly in the Console
$0.style.color = "red"; $$(".card").length; copy($0.outerHTML)$0 points at the currently selected element, so you can change styles and verify right away; $$ returns a collection where you can see the count; copy puts outerHTML on the clipboard for easy pasting into a search box or notes for comparison.
3A minimal loop for performance timing
console.time("render"); /* suspicious operation */ console.timeEnd("render");time/timeEnd prints the millisecond duration between matching labels. If the result is large, use console.count to count how many times that block ran—repeated triggering is often the real source of the performance problem.
4Find failed requests and reproduce them in the terminal
Type status-code:404 in Filter → right-click request → Copy as cURL → run in the terminalThe filter narrows down all failed requests first; the full command copied by Copy as cURL includes the method, headers, and credentials, so you can replay it directly in the terminal or turn it into a regression script—more reliable than assembling parameters by hand.
5Reproduce loading problems on a slow network
Check Disable cache → select Slow 3G under Throttling → refresh the pageThrottling combined with disabling the cache reliably reproduces "fine locally, timing out in production" issues. By watching which requests stay pending in the waterfall, you can tell whether the slowness is on the critical first-screen path or in some lazily loaded API.
6Record and analyze a real jank
Performance → Record → trigger the action → Stop → inspect Main thread / Flame Chart / Call TreeDo not switch tabs while recording to avoid noise. In the Flame Chart, find the widest block to identify the time-consuming function; the Call Tree confirms the call path from top to bottom; the Summary gives the overall time distribution. Reading the three views together quickly pinpoints the bottleneck.
7Troubleshoot leftover local state and cache
Application → Local Storage / Cookies / Cache Storage / Service Workers → Clear site data → refreshFirst check each of the four storage locations for stale data, then clear all site data at once and refresh. If the behavior returns to normal after clearing, the problem lies in local state or the Service Worker cache rather than the code itself.
Command Examples
Grab a direct reference to the selected element
Cmd+Shift+C
$0
$$("table tbody tr")
console.table($$("table tbody tr").map(r => r.cells[0].textContent))$0 is whichever node is currently highlighted in the Elements panel — use it as your entry point in the console. $$ returns an array, and pairing it with console.table flattens table data at once instead of expanding nodes one by one.
Copy as cURL to reproduce a request
Network panel → right-click request → Copy as cURLWhen a request fails intermittently, turn it into a command line: replay it outside the page, and drop one header at a time to find the culprit. Strip Cookie and Authorization before pasting anywhere.
Filter by status code to isolate failures
Filter: status-code:404
Filter: -domain:example.comA slow page is usually the sum of dozens of requests. Filtering by status code shows what is genuinely failing, and excluding third-party domains strips analytics and font noise so you see only your own traffic.
Time a block of code to find the synchronous block
console.time("parse");
// code under test
console.timeEnd("parse");Console timing is lighter than the Performance panel and suits bisecting: wrap chunks of a long routine and time each one — the offender is whichever blows past the others. Use the Performance panel only when you need flame charts and call trees.
Output
parse: 312.7ms
Catch third-party DOM mutations with a subtree breakpoint
Break on: subtree modificationsWhen a node vanishes for no visible reason, the Elements panel will not tell you who removed it. A subtree breakpoint pauses the moment a script mutates the structure, and the call stack names the script.
Common Pitfalls
- Leaving "Disable cache" checked makes you debug stale assets and chase a bug that no longer exists in your code.
- "Copy as cURL" embeds Cookie, Authorization, and CSRF tokens — pasting that into an issue, a chat, or a public repo hands over a live session.
- A throttling preset can outlive the DevTools window in some versions, so every later test runs slow for reasons unrelated to the code.
- "Edit as HTML" changes are temporary and vanish on reload. Never treat them as a fix — the real change belongs in the source file.
- "Clear site data" wipes local and session storage, cookies, and caches. Running it mid-investigation destroys the login state and the localStorage fixtures you were reproducing against.
- Force Element State (:hover/:active) is a visual simulation that fires no real JS events, so it cannot tell you whether click logic actually works.
Tips
- $0 in Console is the currently selected DOM element, directly operable.
- Right-click in the Network panel and Copy as cURL to replay a request in the terminal.
- When recording in the Performance panel, avoid other tabs open, which hurts accuracy.
FAQ
What are $0, $(...) and $$(...) in the Console, and how do they pair with Elements?
Once you select a node in the Elements panel, $0 refers to that element and you can operate on it directly: $0.style.color = "red" or $0.remove(). $("selector") is querySelector and returns one match; $$("selector") is querySelectorAll and returns a NodeList you can then .forEach over. To get a complicated selected element out of the panel, use Store as global variable to keep it as a global, or console.dir(element) to print the DOM object's properties — console.log alone only gives you an "[object HTMLDivElement]" summary.
How do I use Console timing to find out which part of a piece of code is slow?
Pair console.time("label") with console.timeEnd("label") using the same label; repeating a start warns and a missing end prints nothing. Wrap each suspicious stage — console.time("parse") around parsing, console.time("render") around rendering — and compare the two numbers in the Console, then subdivide whichever is larger. Alongside it, console.count("label") counts invocations and exposes redundant calls inside a loop, console.group / console.groupEnd collapse noisy output, and console.assert(condition, "error") checks an invariant.
How do I filter the Network panel down to the requests that actually misbehave?
The filter box combines conditions: narrow by type — Doc, JS, CSS, Img, XHR — to drop static-asset noise; -domain:example.com excludes a domain; status-code:404 pins every 404; is:from-cache surfaces cache hits. Pair it with Disable cache and reload to check whether caching is masking the problem, Throttling: Slow 3G to reproduce weak-network behaviour, and Block request URL to deliberately break a request and verify your fallback. Once you have the request, right-click Copy as cURL and replay it in the terminal.
How do I set things up to reproduce a bug that only shows on mobile?
Cmd + Shift + M toggles device emulation; once a device is selected you can edit the HTML directly in Elements, and Force Element State pins :hover / :active so interactive styles become inspectable. Cmd+Shift+C puts you in the element picker for clicking straight on the real page. When the bug involves storage, move to the Application panel to inspect Local Storage, Session Storage, Cookies, IndexedDB and Cache Storage, and use Clear site data to wipe state before reproducing so leftovers do not confuse you; Service Workers and Manifest panels cover PWA issues.
How do I read the flame chart produced by the Performance panel?
Hit Record to capture (and avoid touching other tabs while recording, or you pollute the data), then use Screenshots to grab the frame where the jank is visible. Bottom-Up sorts by Self Time, telling you directly which functions burn the most CPU; Call Tree expands the stack so you can find who called the slow code. Summary shows how time is distributed across phases, and the Memory panel alongside it reveals whether the JS heap keeps growing during the capture. The workflow is: locate the longest slice in Summary, then identify the culprit in Bottom-Up.
Official References
Each command links to its official documentation below, so you can verify the latest usage and read deeper.
Maintained by LaoHand
Publicly updated on Jul 21, 2026, continuously proofread against official docs.
Contact Us
Wrong command or description? Send us corrections, business inquiries or product feedback by email.
Contact Us