
Playwright MCP over the Chrome extension for checking a frontend
Checking a frontend against a design with Claude Code, the claude-in-chrome extension kept handing back screenshots that looked broken when the build was fine, and verdicts that called an actually broken page fine. Moving the render-and-capture step to the Playwright MCP fixed both, and they turned out to be two unrelated bugs sharing one symptom.
Key takeaways
- The claude-in-chrome extension often leaves the tab backgrounded, freezing requestAnimationFrame so entrance animations stay stuck at opacity zero in screenshots.
- A frozen animation reads as missing content to Claude, producing a false broken verdict on a build that is actually fine.
- Even a clean capture gets rubber-stamped by a single-pass look-right check, since vision models are documented as biased toward passing.
- Playwright exposes controls the extension does not: disabled animations, reduced motion, a real ready signal instead of networkidle, and 2x-scale full-page capture.
- The durable fix is a reading discipline, describe first, checklist for breakage, cite evidence, cross-reference the DOM, now encoded by default in Flight Deck's design-fidelity skill.
Checking a frontend against a design with Claude Code means, at some point, taking a screenshot and asking whether it matches. I did that render-and-capture step through the claude-in-chrome extension for months, because it was already there and already connected to my Chrome session. Then I got tired of Claude calling a visibly broken or incomplete frontend fine, sometimes on the same page where I had already spotted the problem myself in the same tab. Moving that step to the Playwright MCP fixed it, but the more useful part is why, because the win is not the brand name, it is the mechanism.
Two bugs wearing one symptom
Every failed check looked the same from the outside: I ask Claude to verify a page, it comes back with a screenshot and a verdict, the verdict is wrong. But wrong in two directions that have nothing to do with each other. Sometimes the page was fine and Claude called it broken, because the capture itself was bad. Sometimes the page was actually broken and Claude called it fine, because the reading of a perfectly good capture was careless. Fixing one does nothing for the other, and for a while I was debugging both as if they were the same problem.
The false-broken read: a backgrounded tab
The first failure mode traces back to something this very portfolio's own CLAUDE.md already documents as a gotcha: the claude-in-chrome extension frequently leaves the tab it is driving in the background. A backgrounded tab means document.hidden is true, and Chromium throttles or fully pauses requestAnimationFrame for hidden tabs. Every scroll-in or mount entrance animation on this site, and on most sites built with Motion or a similar library, starts at opacity zero and animates in on a frame loop.
Freeze that loop before it runs and the screenshot captures the initial state forever: content that is present in the DOM and will render correctly for a real visitor, but reads as absent in the capture. Claude then reports the section as broken, I go check the live page myself, and it is fine. That is a screenshot lying about the actual state of the page, consistently, in one direction.
What Playwright gives you that the extension does not
Playwright's screenshot API has the levers to make a capture trustworthy instead of just convenient.
| Lever | Effect |
|---|---|
animations: 'disabled' on the screenshot call | Every CSS and Web Animations transition snaps to its end state |
reducedMotion: 'reduce' on the browser context | The same, at the OS-preference level |
| Page brought to front before capturing, not trusted to stay focused | Root fix for the backgrounded-tab problem, not a workaround |
A wait on document.fonts.ready | No flash of unstyled or fallback text gets caught |
| 2x device scale, full page, per breakpoint | Small type and border details stay legible |
Three of those carry more than a cell holds. Disabling animations is what keeps a mount animation from being caught mid-flight. Reduced motion also exercises the accessibility path the site should already support. And the details that would be illegible at 1x are exactly the ones a fidelity check needs to see.
The false-fine read: rubber-stamping a clean screenshot
The second failure mode is worse, because it survives a good capture. Hand Claude a correctly rendered screenshot and ask, in effect, whether it looks right, and a single pass through that question gets rubber-stamped more often than it should. Vision models are documented to be weak at absolute judgment on a single image with no reference to compare against, and biased toward passing rather than flagging something as wrong. So even once the capture problem was solved, I kept seeing Claude wave through pages with overflow, collapsed containers, or invisible text, because looking right was never actually checked against anything specific.
A reading protocol, not a tool
The fix here has nothing to do with Playwright; it is a discipline for how the analysis itself runs. Describe each region of the page literally before rendering any verdict, so the model commits to what is actually there instead of pattern-matching to a generically normal page.
Then run an explicit checklist of known breakage signatures instead of one open question:
- overflow
- a collapsed or zero-height container
- an unstyled flash
- text the same color as its background
- clipped or overlapping text
- a broken image
- a breakpoint's columns collapsing wrong
- an element sitting off-screen
- an unexplained empty gap
- console errors
Require a PASS to cite the specific evidence that earned it rather than accept a vibe. And cross-reference the accessibility snapshot against the screenshot, because that catches the one case a screenshot alone cannot: markup that genuinely exists in the DOM but never actually painted, present in the snapshot and absent in the pixels.
Not "Playwright good, Chrome bad"
I want to be honest about the actual claim here, because it is narrower than the headline sounds. The extension is still a reasonable fallback, and nothing about it makes the false-fine failure mode worse; that one lives entirely in the reading step, tool independent. The real gains came from capture discipline, disabled animations, a real ready signal, correct scale, and from a skeptical reading protocol: describe first, run the checklist, cite evidence, cross-reference the DOM. Playwright happens to expose the controls to do both properly, in a way the extension's screenshot tool does not. If a future version of the extension exposed the same controls, most of this post would stop being a reason to switch tools and start being a reason to configure the one already in hand.
Where this lives now
This stopped being something I re-derive by hand once I folded it into Flight Deck, the open source skill package I maintain. The design-fidelityskill renders through the Playwright MCP by default now, with the claude-in-chrome extension documented as a fallback rather than the default path. A follow-up change adds the capture protocol above, disabled animations, reduced motion, a real ready signal, 2x scale, full page and per breakpoint, plus the read-before-you-score analysis protocol, as the skill's actual verification gate rather than something merely described in a prompt. The repo is public at github.com/CaseReed/flight-deck, under MIT, and the Flight Deck page on this site has the fuller walkthrough.
The lesson generalizes past this one skill. When an agent's verdict does not match reality, check whether the input it saw was even true before assuming the reasoning on top of it is at fault. Half the time here, the reasoning was fine. The screenshot was lying.