• Blog
  • Docs
  • Pricing
  • We’re hiring!
Log inSign up
khawjaahmad

khawjaahmad

playwright-selector-gen

MCP: Fetch URL DOM and generate unique Playwright selectors
Public
Like
playwright-selector-gen
Home
Code
2
README.md
H
main.ts
Environment variables
5
Branches
1
Pull requests
Remixes
History
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.
Sign up now
Code
/
README.md
Code
/
README.md
Search
…
Viewing readonly version of main branch: v9
View latest version
README.md

Playwright Selector Generator

Endpoint: https://playwright.val.run

AI-powered service that fetches any URL's DOM and generates Playwright-native locators. The AI model does all selector generation — there is zero algorithmic/semantic logic in the code itself. The code only fetches HTML, extracts raw DOM context, and passes it to the model.


Authentication

Every POST request requires the X-Api-Key header matching the X_API_KEY environment variable set on the val.

curl -X POST https://playwright.val.run \ -H "Content-Type: application/json" \ -H "X-Api-Key: your_endpoint_key" \ -d '{"url": "https://example.com"}'

Requests without a valid key receive 401 Unauthorized.


Environment Variables

Set these on the val (all required):

Env VarPurpose
X_API_KEYProtects the endpoint from unauthorized access
ANTHROPIC_API_KEYZ.AI / Anthropic API key for the model
ANTHROPIC_URLAPI endpoint (default: https://api.z.ai/api/anthropic/v1/messages)
ANTHROPIC_MODELModel identifier (default: anthropic/claude-sonnet-4-20250514)

API

GET /

Health check.

{ "status": "ok", "service": "playwright-selector-gen" }

POST /

Headers:

HeaderRequiredDescription
X-Api-KeyYesEndpoint access key
Content-TypeYesapplication/json

Body:

FieldTypeRequiredDescription
urlstringYesPage URL to analyze
filterstring[]NoOnly return elements matching these tags

Response

{ "url": "https://example.com", "totalElements": 5, "elements": [ { "index": 0, "tag": "h1", "locators": [ { "method": "getByRole", "playwrightCode": "page.getByRole('heading', { name: 'Example Domain' })", "confidence": "high" }, { "method": "getByText", "playwrightCode": "page.getByText('Example Domain', { exact: true })", "confidence": "medium" } ] }, { "index": 1, "tag": "a", "locators": [ { "method": "getByRole", "playwrightCode": "page.getByRole('link', { name: 'Learn more' })", "confidence": "high" }, { "method": "getByText", "playwrightCode": "page.getByText('Learn more', { exact: true })", "confidence": "medium" }, { "method": "locator:css", "playwrightCode": "page.locator('a[href=\"https://iana.org/domains/example\"]')", "confidence": "medium" } ] } ] }

Locator Priority

The AI model follows the official Playwright locator recommendation:

RankMethodUsed For
1getByRole()ARIA role + accessible name
2getByLabel()Form fields with associated <label>
3getByPlaceholder()Inputs with placeholder text
4getByText()Visible text content
5getByAltText()Images with alt attribute
6getByTitle()Elements with title attribute
7getByTestId()data-testid / data-cy
8locator() CSSShort CSS only — absolute last resort
9locator() XPathOnly for truly complex DOM traversal

Deep nested selectors are never generated. Each element gets up to 3 locators ranked best → fallback.


Architecture

POST { url } + X-Api-Key
        │
        ▼
┌─ Fetch target URL HTML ─┐
│                          │
├─ Parse DOM (deno_dom)    │
│                          │
├─ Extract raw elements:   │
│   tag, attributes,       │
│   outerHTML snippet,     │
│   text content           │
│                          │
│   (NO selector logic)    │
└──────────┬───────────────┘
           │
           ▼
┌─ AI Model (Z.AI) ───────┐
│                          │
│  Receives raw DOM data.  │
│  Generates ALL locators. │
│  Ranks by Playwright     │
│  priority. Returns JSON. │
│                          │
└──────────┬───────────────┘
           │
           ▼
     JSON response

The code contains no selector generation logic whatsoever. It extracts raw DOM context (tag names, attributes, outer HTML snippets, text content) and sends it to the AI model. The model produces every locator.


Elements Scanned

Interactive: a, button, input, select, textarea, form, label, details, summary, dialog

Landmarks: nav, header, footer, main, aside, section, article

Content: img, h1–h6, table, th, td, tr, ul, ol, li, span, p, div

By attribute: Any element with role, data-testid, data-test-id, data-cy, aria-label, tabindex, or contenteditable

Capped at 300 elements per request. Elements are batched in groups of 30 for the AI call.


Error Responses

StatusMeaning
401Missing or invalid X-Api-Key header
400Missing url in request body
405Method not allowed (use POST)
500ANTHROPIC_API_KEY not configured / AI error
502Target URL could not be fetched
FeaturesVersion controlCode intelligenceCLIMCP
Use cases
TeamsAI agentsSlackGTM
DocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareers
We’re hiring!
Brandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Open Source Pledge
Terms of usePrivacy policyAbuse contact
© 2026 Val Town, Inc.