Public
Likeplaywright-selector-gen
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Viewing readonly version of main branch: v4View latest version
Endpoint: https://playwright.val.run
Fetches any URL's DOM and generates unique, production-grade selectors for Playwright TypeScript tests. Every CSS selector returned is verified to match exactly one element in the document.
curl -X POST https://playwright.val.run \ -H "Content-Type: application/json" \ -d '{"url": "https://example.com"}'
curl -X POST https://playwright.val.run \ -H "Content-Type: application/json" \ -d '{"url": "https://example.com", "filter": ["a", "button", "input"]}'
Health check. Returns:
{ "status": "ok", "service": "playwright-selector-gen" }
| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Page URL to crawl |
filter | string[] | No | Only return elements matching these tag names |
{ "url": "https://example.com", "totalElements": 5, "selectorsGenerated": 4, "elements": [ { "tag": "h1", "text": "Example Domain", "selectors": { "css_first_child": "h1:first-child", "css_nth_child": "h1:nth-child(1)", "css_child_combinator": "html > body > div > h1", "css_nested_div_path": "div > h1", "xpath_absolute": "/html/body/div/h1", "xpath_optimised": "//h1[normalize-space()='Example Domain']", "xpath_first": "(//h1)[1]" } } ] }
| Key | Style | Example |
|---|---|---|
xpath_absolute | Full path with indexes | /html/body/div[2]/form/input[3] |
xpath_optimised | Shortest unique (id/name/text/aria) | //input[@name='email'] |
xpath_first | first() positional | (//input)[1] |
| Key | Style | Example |
|---|---|---|
css_nth_child | Index among all siblings | input:nth-child(3) |
css_nth_of_type | Index among same-tag siblings | div:nth-of-type(2) |
css_first_child | First child | li:first-child |
css_last_child | Last child | li:last-child |
css_child_combinator | Full parent > child chain | html > body > div:nth-of-type(2) > form > input |
css_nested_div_path | Div-only ancestor chain | div:nth-of-type(2) > div > input |
| Key | Attribute used | Example |
|---|---|---|
css_id | id | #login-btn |
css_name | name | input[name="email"] |
css_testid | data-testid | [data-testid="submit"] |
css_aria_label | aria-label | button[aria-label="Close"] |
css_role | role | div[role="dialog"] |
css_type | type | input[type="password"] |
css_href | href | a[href="/about"] |
css_placeholder | placeholder | input[placeholder="Search…"] |
css_title | title | img[title="Logo"] |
css_class | class (first 3) | div.container.main.wrapper |
- CSS selectors are tested against the parsed DOM — only selectors resolving to exactly 1 element are included.
- XPath selectors are structurally unique by construction (absolute paths with sibling indexes).
import { test, expect } from '@playwright/test';
test('login form', async ({ page }) => {
await page.goto('https://myapp.com/login');
// CSS child combinator
await page.locator('html > body > div > form > input:nth-of-type(1)').fill('user@test.com');
// XPath optimised
await page.locator("//input[@name='password']").fill('secret');
// CSS nth-child
await page.locator('button:nth-child(2)').click();
// XPath first()
await expect(page.locator("(//h1)[1]")).toHaveText('Dashboard');
});
Interactive and structural tags are scanned: a, button, input, select, textarea, form, label, img, h1–h6, nav, header, footer, main, section, article, table, tr, th, td, ul, ol, li, details, summary, dialog, iframe, video, audio, svg, span, p, div.
Elements with role, data-testid, aria-label, onclick, or tabindex attributes are also included regardless of tag.
Results are capped at 500 elements per request.
Provider : Anthropic
Model : anthropic/claude-opus-4-20250514
URL : https://api.z.ai/api/anthropic
API Key : your_zai_api_key
| Status | Meaning |
|---|---|
400 | Missing url in request body |
405 | Method not allowed (use POST) |
502 | Target URL could not be fetched |
500 | Internal parsing error |