The page with the game is already written and opens fine in the browser: the board renders, the pieces move, the "New game" button is right where it should be. Except the agent itself has never seen this page. It worked with the text of the files, while you were the one who started the browser, looked at it, and told it what happened. Playwright closes exactly that gap: the agent opens the same page, finds the element it needs, clicks it, and reads what changed afterward.

Below, let's walk through this cycle step by step on a chess page: open, look, pick an element, act, read the new state. We won't repeat the setup and server connection here - if you haven't connected Playwright yet, the instructions live in the project's README.

Open the page you need

What does the "Connected" label actually prove?
Exactly one thing: Claude Code connected to the Playwright server and got a list of tools from it. No page has been opened yet, and the browser may not even be running. Connected is about the connection, not about your game working and the agent seeing it.

You can check the current status with the /mcp command: it lists the connected servers and what each one can do. The real work starts after that, and the first thing it needs is the page's address.

A local game lives either as a file on disk or on a local server, and the server's port isn't the same in every case. 5173, 8000, 3000 - it depends on how you started it. Take the address from where it's actually printed: the output of the start command, or the address bar of the browser where you just looked at the game. A guessed port gives you either a blank page or someone else's project entirely, and the tool's response doesn't always make that obvious.

Opening the page itself is a separate call, browser_navigate, with one parameter: url. The instruction you give the agent can be plain language:

Open http://localhost:5173/ through Playwright
and show me the title of the page that opened.

After opening, check two things: the address the agent actually went to, and the page title. It takes a second and saves you a whole series of actions performed in the wrong place. Especially if you have a couple of local projects running side by side (happens more than you'd think), and one of them answers on localhost too.

This isn't your browser window

Playwright launches its own browser. Your tabs, extensions, and any accounts you're already logged into don't come along: by default it's a separate profile, isolated from your regular browser. For a local game that changes nothing, but the expectation "it'll open the site where I'm logged in" won't hold by default.

What the agent sees on the page

You can look at an open page in three different ways, and they give you very different things:

What you wantToolWhat comes back
See what it looks likebrowser_take_screenshotan image of the page
Learn what it's made ofbrowser_snapshota text tree of elements: roles, names, references to elements
Read a specific valuebrowser_evaluatethe result of a small expression evaluated right on the page
One page gives you three different kinds of data: an image, a description of elements, and an attribute valuePagechess gameScreenshot → appearancebrowser_take_screenshotWhat does the board look like?Snapshot → elementsbrowser_snapshotWhere's the "New game" button?Expression → valuebrowser_evaluateWhat's stored in data-turn?
Choose how to observe based on the question you have about the page

All three branches start from the same page, but they return different data. The snapshot helps you find the button, while the data-turn value has to be read separately. An image of the board doesn't by itself reveal its HTML attributes.

A screenshot is a picture. It answers "what does this look like" and "what's located where" perfectly well, but it doesn't give you a reference to an element for browser_click. In Playwright MCP's main mode, actions use the accessibility snapshot. Coordinate-based clicks are available separately, if the corresponding tools are enabled.

The accessibility snapshot is exactly that: a description of elements. Not a picture but text - a list of what the page is made of, with roles (button, link, input field), names, and references you can later use to reach the element. This is what the agent actually relies on when it clicks something. Schematically, one button looks roughly like this in a snapshot:

- button "New game" [ref=e12]
- button "Undo move" [ref=e13]

This is a sketch to show the shape, not the tool's actual output: the exact format depends on the server version, and we won't run it just for this article. What matters here isn't the punctuation but the fact itself - the button reaches the agent as a line with a role, a name, and a reference, not as a rectangle with text on it.

And now the spot where people most often trip up. The data-turn label, which shows whose move it is in our game, doesn't make it into the accessibility snapshot: the snapshot is built from roles, names, states, and references to elements, not from the page's markup. An arbitrary data attribute isn't on that list. The label's value can still show up in the snapshot separately - if the page also prints it as visible text. But that's text on the page, not an attribute the agent read, and the two shouldn't be confused.

Values like that are read with a separate operation, the browser_evaluate tool. It runs a short expression in the page's context and returns the result - this is already running code on the page rather than just reading it, so the agent sometimes asks for permission before doing it. The agent writes the expression itself, but it looks roughly like this:

// find the element with the move label and return its value
() => document.querySelector('[data-turn]')?.getAttribute('data-turn') ?? null
A snapshot and the markup aren't the same thing

The accessibility snapshot is a distillation, not a full copy of the page's markup. It has what you need to identify and click an element, but not everything else. So "the agent took a snapshot" and "the agent read every attribute" are different claims, and the second doesn't follow from the first.

How the agent picks an element

Why does a click by coordinates eventually miss the button?
Because coordinates describe a point on the screen, not the button. You resized the window, collapsed a sidebar, changed the font scale, or the page grew one extra line at the top - and the point stayed where it was while the button moved. The click still fires just fine: right onto empty space.

So the main way of picking an element is different. The browser_click tool has two fields that matter here: element - a human-readable description like "New game button" that tells you what the agent is about to click, and target - a reference to an element from the snapshot or a unique selector. Let's look at picking by a snapshot reference. The reference is tied to the snapshot it was taken from, and the click lands exactly on it. Typing text works the same way, except the tool is called browser_type and the text itself is passed along with the element's description.

What's stable here isn't the reference itself but the way of finding it. Role plus name is a fairly durable pair: the "New game" button stays the "New game" button even after a designer moves it to the other side of the screen. Using this pair, the agent finds the right element again in any new snapshot and takes a fresh reference from it - which is exactly why the rule "look again after every action" keeps coming up later in this article.

A board square is trickier: there are 64 of them, and they all have the same role. This is where a label from the app itself helps. If a square has its own name, e2 or e4, you can hit it precisely; if every square in the snapshot is nameless, picking the right one by role and name alone won't work. In that case, check whether the square has some other unambiguous marker in the markup, or use the coordinate-based tools if they're available.

Playwright MCP does have coordinate-based tools, but in the standard build they're turned off and have to be enabled separately - for cases where there's no other way to reach an element, on a canvas, for example. And since they're off by default, there's genuinely no way to act from a single picture: that's exactly the warning about screenshots from the start of this section.

Action and the new state

The work cycle: a fresh snapshot, picking an element, acting, reading the new state, and returning to a snapshot before the next action1. Fresh snapshotWhat's on the page?2. Pick an elementRole + name → referencefrom that snapshot3. ActionClick or type text4. New stateSnapshot and, if needed,reading an attributeThe next action relies on the new data
After an action, the cycle returns to observation

The arrow on the left closes the cycle: before the next action, the agent uses an up-to-date description of the page. If the response to the previous action already contains a fresh snapshot, you can rely on that. The mere fact that a click executed doesn't yet confirm the change you wanted.

Let's put it all together into a single route you can hand off in one go. Five steps, and after each one it's clear what should become visible. The route assumes the squares on our board are labeled - the same e2 and e4 from the previous section; without labels, step 4 needs a different way to pick squares unambiguously.

StepWhat the agent doesWhat becomes visible
1opens the game's addresspage title, board in place
2clicks the "New game" buttonpieces in the starting position
3reads data-turnwhite
4makes the move e2-e4 through the page's interfacethe pawn moved two squares
5reads data-turn and what's on e4black, a white pawn on e4
Checking the move e2-e4: before the move data-turn equals white and there's a pawn on e2; after the move we expect black, an empty e2, and a white pawn on e4; the conclusion comes only after reading againBefore the movedata-turn: whitee2: white pawne4: emptyExpected afterdata-turn: blacke2: emptye4: white pawne2-e4Read again and compareDoes the data match the expectation?
Checking the change of turn and the pawn's position

The left side shows the starting state, the right side the expected result of the move - the plan, roughly speaking. The block below ties them together with a check: the agent reads the turn label and the pieces' position again, then compares the values. For a fuller check of the move, it's also worth confirming that the original square e2 became empty. A single change from white to black still doesn't confirm the pawn actually ended up on e4.

It's worth being direct about data-turn: it's a convention of this particular app. The page's author decided to set a label like this, which is why it can be read. Playwright doesn't create it or make it up - it can only fetch what's already on the page. On someone else's page, where no such label exists, this trick won't work, and you'll have to rely on what's visible to the eye.

And the main rule after any action: you read the state again. A snapshot taken before a click describes the page before the click, no matter how fresh it still looks. The references to elements in it may lead nowhere once the board redraws, and a data-turn value read separately before the click may have already changed too. You acted - look again.

No label - say so plainly

If the app didn't return the value you needed, the correct answer from the agent is "couldn't read it, there's no such attribute on the page." A plausible black, inferred from the fact that a move was apparently made, looks exactly like a genuinely read value, but it proves absolutely nothing. Ask the agent to show the values it actually read, not a summary.

When an action doesn't work

The most common failure sounds like "element not found." You work through it with a short, unglamorous chain:

  1. check that the right page is open. Address and title - the same two things as at the very start;
  2. make sure the page is ready. The game might not have finished loading yet, and the button could appear a second after the request;
  3. take a fresh snapshot. Not the one already sitting in the conversation - a new one;
  4. pick the element again, using the current description from that snapshot, and repeat the action.

One of the possible causes turns up at the third step: the element is still on the page, but the reference to it is stale.

A screenshot is useful here too, but not as a universal tool. It answers "what does the page look like and what's located where" - for instance, it shows that the board rendered empty or that a modal window is hanging over it. If whose turn it is appears as text on the page, you can see that in a screenshot too. But only reading the data-turn attribute confirms its exact value. Two different questions, two different tools; mixing them up means staring at a picture and arguing about data.

How this changes the way you work

An instruction to the agent stops being a list of clicks and becomes a route with checkpoints. Here's the same thing we just walked through, as one piece of text:

Open http://localhost:5173/ through Playwright.
1) click "New game";
2) read data-turn and show me the value;
3) make the move e2-e4 through the page's interface;
4) read data-turn and what's on e4 again.
If any of these values isn't on the page, say so
and don't fill it in yourself.

Here's what's worth keeping in mind:

  • the address is always the real one, taken from the start output, not a guess;
  • the instruction includes "read and show me" lines - without them you're left with just an account of the result;
  • states are shown in pairs, before and after the action. One value at the end proves nothing, because you don't know what it was at the start;
  • a snapshot, a screenshot, and reading an attribute answer different questions, and you should choose between them based on the question, not out of habit;
  • one example route is enough. One successful e2-e4 move doesn't mean the rest of the game will follow the rules on its own - that's a separate, much more serious check.

The simplest way to remember it: the browser gives the agent hands and eyes, but not ready-made conclusions. It can open a page, click, and read a value on its own; deciding what that value means is still up to you.


Tool names and their parameters were checked against the Playwright MCP README on September 19, 2026, and may change from version to version. The general order - open, look, pick an element, act, read again - stays the same.