Not for: build/compile failures (no browser yet), pure logic bugs reproducible in a unit test, or backend-only errors. Route those to general root-cause debugging. This skill is browser-runtime UI only and uses the chrome-devtools MCP to inspect a live page.
-
Get a live page. list_pages to see open tabs; select_page the offending one, or new_page + navigate_page to the failing URL. Reproduce the exact state the bug needs (route, query params, logged-in session). If repro needs interaction, drive it: click / fill / press_key. Note: a fresh new_page has no auth cookies — reuse the existing tab when the bug is session-dependent.
-
Drain the console first. list_console_messages — read every error and warning, not just the top one. The first error is usually the root; later ones are fallout. Capture the full stack trace via get_console_message for the key error. Map minified frames back to source using the file:line in the trace (sourcemaps); if prod sourcemaps are absent, re-run the same flow against the dev/staging build to get readable frames.
-
Check failed network requests. list_network_requests, then get_network_request on anything non-2xx, pending, or that the failing component depends on. Inspect: status code, response body (real error message often lives here, not the console), request/response headers. For CORS: confirm the server returned Access-Control-Allow-Origin matching the page origin and, for preflight, that the OPTIONS request succeeded with the right Access-Control-Allow-Methods/Headers. CORS is a server-config fix — never "fix" it by disabling browser security or proxying around it silently.
-
Hydration mismatch (Next.js / React). The cause is server HTML ≠ first client render. Hunt for non-deterministic-in-render values: Date.now() / new Date() / Math.random(), window/localStorage/navigator read during render, typeof window !== 'undefined' branches, locale/timezone-dependent formatting, and invalid DOM nesting (<div> inside <p>, <p> inside <p>). Take take_snapshot to see the actual client DOM and compare against the SSR HTML (view the document response in get_network_request). Fix at source: gate client-only values behind useEffect/mounted-flag or next/dynamic({ ssr: false }). Use suppressHydrationWarning only for genuinely unavoidable per-render values (e.g. a timestamp) — it silences the warning, it does not fix a real divergence.
-
Layout / styling bug. take_screenshot for the visual, take_snapshot for the structured DOM + roles. evaluate_script to read computed styles on the culprit node (getComputedStyle(el)), bounding box, overflow, z-index, and whether the element is actually in the DOM vs display:none/zero-size. Distinguish "not rendered" (missing from snapshot) from "rendered but invisible" (present, hidden by CSS).
-
Broken interaction / event wiring. Confirm the handler is attached and the right element receives the event. evaluate_script to inspect listeners, check for an overlay intercepting clicks (document.elementFromPoint(x,y)), pointer-events:none, disabled state, or a stale closure capturing old state. Reproduce the click with click and re-read the console/network to see what (if anything) fired. For React state bugs, log or read the value at the moment of interaction rather than assuming.
-
Confirm root cause, fix at source. Tie the symptom to one concrete cause (a specific request, a specific render expression, a specific listener). Fix the source code — do not swallow the error with an empty catch, a blanket try/catch, or by hiding the failing UI.
-
Verify live. Reload via navigate_page (or reload), re-run the repro interaction, then re-check: list_console_messages clean of the original error, list_network_requests shows the request now 2xx, take_screenshot shows correct render. Show the before/after as evidence — do not declare fixed on code-read alone.