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 | Render an array of objects as an aligned table instead of a collapsed tree. | F12 |
F12 / Ctrl+Shift+I | Reference the element currently selected in the Elements panel without querying for it again. | Ctrl + Shift + I |
Cmd+Option+J | Query a single element or every matching element, returning real DOM nodes rather than a static list. | Cmd + Option + J |
Cmd+Option+E | Log every event of a type that an object receives, including the ones fired before you attached the listener. | Cmd + Option + E |
Cmd+Shift+C | Turn a captured request into a runnable curl command so you can reproduce it outside the browser. | Cmd + Shift + C |
Cmd+Shift+P | Negative-filter the request list so third-party traffic stops hiding the requests you care about. | Cmd + Shift + P |
Cmd+P | Re-issue a captured XHR/fetch request against the running server to see whether a bug is client-side or server-side. | Cmd + P |
Cmd+Shift+M | Bypass the HTTP cache for every subsequent request so a stale bundle cannot mask your changes. | Cmd + Shift + M |
console.log("message") | Pause execution whenever the DOM under the selected node changes, which catches code rewriting markup indirectly. | console.log("message") |
console.table(array) | Produce a selector for the inspected element, which you can paste into a test or a query. | console.table(rows) |
console.time("label") / console.timeEnd("label") | Capture a trace of the main thread and the compositor, from which the flame chart and layout-shift metrics are derived. | console.time("render"); console.timeEnd("render"); |
console.count("label") | Pin an inspected element or object to a global name so it survives across console evaluations. | console.count("render") |
console.group("group") / console.groupEnd() | 成组输出日志 | console.group("init"); console.groupEnd(); |
console.assert(condition, "error") | 条件不成立时输出断言信息 | console.assert(el, "error") |
console.dir(element) | 展开打印 DOM 对象 | console.dir($0) |
copy(document.title) | 把结果复制到剪贴板 | copy(document.title) |
$0 | 引用当前选中的 DOM 元素 | $0.style.color = "red"; |
$("selector") | 查询单个元素(类似 querySelector) | $(".card") |
$$("selector") | 查询所有匹配元素 | $$("li") |
monitorEvents(element, "click") | 监控目标元素上的事件触发 | monitorEvents($0, "click") |
Edit as HTML | 直接编辑元素 HTML | 在 Elements 中右键 → Edit as HTML |
Force Element State (:hover, :active) | 强制元素状态以便调试交互样式 | 右键节点 → Force Element State → :hover |
Break on: subtree modifications | DOM 子树变化时断下 | 右键节点 → Break on → subtree modifications |
Break on: attribute modifications | 属性变化时断下 | 右键节点 → Break on → attribute modifications |
Store as global variable | 把节点存为全局变量供 Console 使用 | 右键节点 → Store as global variable |
Copy selector / Copy XPath | 复制选择器或 XPath 路径 | 右键节点 → Copy selector |
Delete node | 删除该 DOM 节点 | 右键节点 → Delete node |
Disable cache | 禁用缓存,确保每次都是新资源 | Network 面板勾选 Disable cache |
Throttling: Slow 3G | 网络限速模拟弱网 | Throttling 选 Slow 3G |
Filter: Doc, JS, CSS, Img, XHR | 按资源类型过滤请求 | Filter 输入 XHR |
Filter: -domain:example.com | 按域名排除请求 | Filter 输入 -domain:example.com |
Filter: status-code:404 | 按状态码过滤 | Filter 输入 status-code:404 |
Filter: is:from-cache | 只看缓存命中的请求 | Filter 输入 is:from-cache |
Replay XHR | 重放选中的请求 | 右键请求 → Replay XHR |
Copy as cURL | 复制为 cURL 命令到终端重放 | 右键请求 → Copy as cURL |
Save as... | 把响应体保存到本地 | 右键请求 → Save as... |
Block request URL | 拦截匹配 URL 的请求 | 右键请求 → Block request URL |
Record | 录制性能数据 | Performance 面板 → Record |
Screenshots | 录制期间逐帧截图 | Performance 面板 → Screenshots |
Memory | 内存分析视图 | Performance 面板 → Memory |
Main thread | 主线程任务与耗时分析 | 查看 Main thread 轨道 |
Flame Chart | 火焰图定位耗时函数 | 查看 Flame Chart |
Bottom-Up / Call Tree | 自底向上 / 调用树视角 | 查看 Call Tree |
Summary | 时间分布汇总 | 查看 Summary |
Local Storage / Session Storage | 查看本地/会话存储 | Application → Local Storage |
Cookies | Cookie 管理 | Application → Cookies |
IndexedDB | 查看 IndexedDB 数据 | Application → IndexedDB |
Cache Storage | 查看 Service Worker 缓存 | Application → Cache Storage |
Clear site data | 清除该站点的所有本地数据 | Application → Clear site data |
Service Workers | Service Worker 注册与状态 | Application → Service Workers |
Manifest | 查看 PWA Manifest | Application → Manifest |
Common pitfalls
SymptomA local edit never reaches the browser and the old code keeps running.
CauseDevTools is open with Disable cache enabled but the page was loaded from the HTTP cache, or a service worker is serving a stale precached bundle.
FixHard-reload with Ctrl+Shift+R, then check Application > Service Workers for an active worker and unregister it if it owns the scope.
SymptomLocal file edits made in DevTools disappear on reload.
CauseEdit as HTML only patches the live DOM; it never writes to disk.
FixUse it to find the right markup, then reproduce the change in your source file and let Live Reload push it back.
SymptomA breakpoint never hits even though the code obviously runs.
CauseThe bound file is a different copy of the source than the one running — a source map points at the original file, or a bundled/minified build is loaded instead.
FixSet the breakpoint in the file the Sources panel shows, and verify the mapping under DevTools > Settings > Debugger > Source Maps.
SymptomBreakpoints pause in a loop inside library code instead of in application code.
CauseBlackboxing is off, so the debugger enters node_modules or framework internals that also match your XHR/fetch break conditions.
FixRight-click the frame you do not care about and choose Blackbox script content, or use a conditional breakpoint on your own function.
SymptomThe Network panel shows nothing even though requests are clearly being made.
CauseRecording was off, or the requests are issued inside a Web Worker / Service Worker whose own network traffic is filtered out.
FixTurn recording on and reload; enable the service worker frames filter in the panel options, or check the worker console separately.
SymptomEditing Local Storage does not survive a page reload.
CauseThe page writes the same key back into Local Storage on every load, overwriting the value you just set.
FixSet a breakpoint on the assignment, or change the value while a debugger pause holds the write path, then resume.
SymptomA throttled CPU profile shows 100% busy while the page feels perfectly responsive.
CauseCPU throttling simulates a slow device for the tab being profiled; a long task inside a worker or a synchronous timer can still keep the main thread at 100%.
FixRead the flame chart by "Main thread" and the Bottom-Up tab to find the self-time hot spots instead of trusting the busy percentage alone.
Symptom改 Local Storage 或 Cookie 后页面行为没变化,像是没保存上
Cause存储面板显示的是当前文档状态的快照;写入需要通过页面自身代码或手动编辑触发,部分站点还有同源与服务端状态校验。
Fix手动改值后回车写回并刷新页面确认;若仍无效,用 Console 执行一次写入再读取校验,区分是存储没写成功还是逻辑不读该键。
Troubleshooting
1Start from the console, where the error names the line
Cmd+Shift+C 选中元素 → 右键 → Break on → attribute modifications → 重新触发Anything the page did to the DOM can be checked here; if it returns null, the selector or the render is the problem, not your code.
2Reproduce a request as a shell command
$0.style.color = "red"; $$(".card").length; copy($0.outerHTML)Copy as cURL from the Network panel gives you the exact headers and body, so you can tell a server bug from a client bug.
3Find the handler that owns a click
console.time("render"); /* 可疑操作 */ console.timeEnd("render");Attach this to the selected element to see the event and which listeners Chrome has bound to it.
4Test the DOM for stale mutations
Filter 输入 status-code:404 → 右键请求 → Copy as cURL → 终端执行Dumping the markup shows whether a framework actually rendered what you expected or the node is still empty.
5Break on the moment the value changes
勾选 Disable cache → Throttling 选 Slow 3G → 刷新页面Chrome exposes bound listeners on the element, which tells you whether the click handler was ever attached.
6录制并分析一次真实卡顿
Performance → Record → 触发操作 → Stop → 查看 Main thread / Flame Chart / Call Tree录制时不要切换标签页以免噪声。Flame Chart 里找最宽的调用块确定耗时函数,Call Tree 从上往下确认调用路径,Summary 给出整体时间分布,三视图合看能快速锁定瓶颈。
7排查本地状态与缓存残留
Application → Local Storage / Cookies / Cache Storage / Service Workers → Clear site data → 刷新先分别检查四个存储位置有无陈旧数据,再统一清除站点数据并刷新。若清除后行为恢复正常,说明问题出在本地状态或 Service Worker 缓存而非代码本身。
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 面板 → 右键请求 → 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");
// 待测代码
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