Every browser node (Click, Type, Extract, Wait for element, Fill a form, Scroll…) has an Element or Selector field that tells it what to act on. If you pick the right element, your flow works on any website. This guide shows how to find a good selector with Chrome, how to check it before you run, and what to do when a page changes.
In short: right-click the element in Chrome › Inspect, look for a stable id, name, data-… or aria-label, write a short selector from it, and check it in the Console with document.querySelectorAll("…").length.
What you can type in the field
Browser nodes use Playwright selectors. You'll mostly use three kinds:
| Kind | Example | Finds |
|---|---|---|
| CSS | #username, button[type=submit], .titleline > a | Elements by id, tag, class or attribute |
| Text | text=Sign in | An element whose visible text is "Sign in" |
| Role | role=button[name="Sign in"] | A button (or link, textbox…) by its accessible name |
When several elements match, the node uses the first one. Match number (on Click) picks another: 0 is the first, 1 the second, and so on.
Step 1: Inspect the element
- Open the website in Chrome.
- Right-click the thing you want (a button, a field, a headline) and pick Inspect.
- DevTools opens with that element highlighted in the Elements panel.
For a sign-in button you might see:
<button type="submit" class="btn btn-primary" data-testid="login-submit">Sign in</button>
Step 2: Pick something stable
Websites change their look often, but some attributes rarely change. Pick from the top of this list:
| Prefer | Selector | Why |
|---|---|---|
| A test id | [data-testid="login-submit"] | Made for automation, rarely changes |
| An id | #username | Unique on the page |
| A form name | input[name="email"] | Tied to how the form sends data |
| An accessible name | role=button[name="Sign in"] or [aria-label="Search"] | Tied to what screen readers say |
| Visible text | text=Sign in | Easy to read. It breaks if the site changes its wording or language |
| A class | .btn-primary | Last choice. Classes change with redesigns, and long generated names like css-1x2y3z change on every release |
Avoid Copy › Copy selector from DevTools when it gives you a long path like #root > div:nth-child(3) > div > button. One layout change and it breaks.
Step 3: Check it in the Console
- In DevTools, open the Console tab.
- Type
document.querySelectorAll('button[type=submit]').lengthand press Enter.
| Result | Meaning |
|---|---|
1 | Exactly one match. That's what you want. |
0 | No match. Check the spelling, or the element may be inside an iframe or not loaded yet. |
2 or more | Too broad. Add something to narrow it, like form#login button[type=submit], or use Match number. |
text= and role= selectors only work in Mooflair, not in the Console. Check those with Step 4.
Step 4: Check it in Mooflair
You don't need to run the whole flow to try a selector:
- Hover the node and press the window icon (Open browser). The flow's browser opens in the Preview window, without a run.
- Go to the page there if it's not open yet.
- Right-click the node › Run this step. Only that node runs, in that browser.
- Watch the result: Next means found, Not found means it wasn't there within the timeout.
Lists: one selector for the rows, short ones inside
Extract in List of items mode takes two levels:
- Element: what each row is, like
tr.athingorarticle. - List fields: for each field, a Name, a Selector inside the row (empty means the row itself) and, if you want an attribute instead of text, an Attribute like
href.
Element: article.product
List fields: name → h2 (text)
price → .price (text)
link → a attribute: href
id → (empty) attribute: data-id
Links (href) come back as full addresses, and duplicate rows are dropped. Guide 3, , uses this on a real page.
Pages that load as you go
Many sites draw their content a moment after the page opens, or as you scroll:
| The page | Add |
|---|---|
| Shows content after a moment | Wait for element with that element's selector, State Visible, before the node that uses it |
| Loads more as you scroll | Scroll with Mode Until enough elements, Count elements set to the row selector and Until count set to how many you want |
| Changes address after a click | Wait for URL with part of the new address, like /dashboard |
| Sometimes shows a pop-up (cookies, newsletter) | Click on its close button, with both Next and Not found connected to the next node, so the flow goes on either way |
When a selector stops working
Sites change. When a node that used to work goes out through Not found:
- Open the Preview and look at the page. Is the element still there? Is a pop-up covering it?
- Inspect it again in Chrome (Step 1), and pick a new stable attribute.
- Update the field and Run this step to check.
Set the node's On error (Settings tab) to Ask a human. The run then waits for you instead of failing, so you can fix it in the Preview and press Retry.
FAQ
Should I use a CSS selector or text=?
Use CSS when the element has a stable id, name or test id. Use text= or role= when it doesn't. They read well and survive redesigns, but they break when the wording changes, for example on a site in another language.
Why does my selector work in the Console but the node says Not found?
Usually the element isn't on the page yet when the node runs. Add Wait for element before it, or raise its Timeout (ms). It can also be a different page: check the Preview to see where the browser really is.
The element is inside an iframe. What do I do?
document.querySelectorAll in the Console can't see into iframes either. Try a text= or role= selector, or open the iframe's own address with Open URL and work on it there.
How do I click the third button of the same kind?
Use Click with Match number 2. Counting starts at 0.