{
  "schemaVersion": "1.0",
  "item": {
    "slug": "playwright-npx",
    "name": "Playwright (scripts) + npx",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/mahone-bot/playwright-npx",
    "canonicalUrl": "https://clawhub.ai/mahone-bot/playwright-npx",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/playwright-npx",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=playwright-npx",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md",
      "_meta.json",
      "examples/form-interaction.mjs",
      "examples/login-session.mjs",
      "examples/scrape.mjs",
      "examples/screenshot.mjs"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-30T16:55:25.780Z",
      "expiresAt": "2026-05-07T16:55:25.780Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
        "contentDisposition": "attachment; filename=\"network-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/playwright-npx"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/playwright-npx",
    "agentPageUrl": "https://openagent3.xyz/skills/playwright-npx/agent",
    "manifestUrl": "https://openagent3.xyz/skills/playwright-npx/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/playwright-npx/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Playwright Browser Automation",
        "body": "🤝 Developed together by Kuba + Mahone · Feb 2026\n\nCode-first browser automation with Playwright."
      },
      {
        "title": "When to Use",
        "body": "ToolUse Whenweb_fetchSimple pages, no JavaScript neededThis skillJavaScript-heavy sites, complex interactions, full controlstealth-browserBot detection / Cloudflare issuesbrowser toolVisual exploration, last resortplaywright-cliInteractive CLI without writing code"
      },
      {
        "title": "Setup",
        "body": "# One-time per project\nnpm init -y\nnpm install playwright\nnpx playwright install chromium\n\npackage.json example:\n\n{\n  \"name\": \"my-automation\",\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"playwright\": \"^1.40.0\"\n  }\n}"
      },
      {
        "title": "Minimal Example",
        "body": "// tmp/example.mjs\nimport { chromium } from 'playwright';\n\nconst browser = await chromium.launch();\nconst page = await browser.newPage();\n\nawait page.goto('https://example.com');\nconsole.log('Title:', await page.title());\n\nawait browser.close();\n\nnode tmp/example.mjs"
      },
      {
        "title": "Screenshot",
        "body": "import { chromium } from 'playwright';\nconst browser = await chromium.launch();\nconst page = await browser.newPage();\nawait page.setViewportSize({ width: 1280, height: 800 });\nawait page.goto('https://example.com');\nawait page.screenshot({ path: 'tmp/screenshot.png', fullPage: true });\nawait browser.close();"
      },
      {
        "title": "Scrape Data",
        "body": "import { chromium } from 'playwright';\nconst browser = await chromium.launch();\nconst page = await browser.newPage();\nawait page.goto('https://news.ycombinator.com');\nconst stories = await page.$$eval('.titleline > a', links => \n  links.slice(0, 5).map(a => ({ title: a.innerText, url: a.href }))\n);\nconsole.log(JSON.stringify(stories, null, 2));\nawait browser.close();"
      },
      {
        "title": "Form Interaction",
        "body": "await page.goto('https://example.com/login');\nawait page.fill('input[name=\"email\"]', 'user@example.com');\nawait page.fill('input[name=\"password\"]', 'password');\nawait page.click('button[type=\"submit\"]');"
      },
      {
        "title": "Wait for Dynamic Content",
        "body": "// Wait for network idle (SPA)\nawait page.goto(url, { waitUntil: 'networkidle' });\n\n// Wait for specific element\nawait page.waitForSelector('.results', { timeout: 10000 });\n\n// Wait for condition\nawait page.waitForFunction(() => \n  document.querySelectorAll('.item').length > 0\n);"
      },
      {
        "title": "Persistent Session",
        "body": "import fs from 'fs';\nconst SESSION_FILE = 'tmp/session.json';\n\nlet context;\nif (fs.existsSync(SESSION_FILE)) {\n  context = await browser.newContext({ storageState: SESSION_FILE });\n} else {\n  context = await browser.newContext();\n}\nconst page = await context.newPage();\n// ... login ...\nawait context.storageState({ path: SESSION_FILE });"
      },
      {
        "title": "Headless vs Headed",
        "body": "// Headless (default, fastest)\nawait chromium.launch({ headless: true });\n\n// Headed (see the browser)\nawait chromium.launch({ headless: false });\n\n// Slow motion (debugging)\nawait chromium.launch({ headless: false, slowMo: 100 });"
      },
      {
        "title": "Selectors Quick Reference",
        "body": "// CSS\nawait page.click('button.submit');\nawait page.fill('input#email', 'text');\n\n// Text content\nawait page.click('text=Submit');\nawait page.click('text=/log\\s*in/i');  // regex\n\n// XPath\nawait page.click('xpath=//button[@type=\"submit\"]');\n\n// ARIA role\nawait page.click('role=button[name=\"Submit\"]');\n\n// Test ID (most stable)\nawait page.click('[data-testid=\"submit-btn\"]');\n\n// Chain selectors\nawait page.click('nav >> text=Settings');\n\nSee references/selectors.md for complete selector guide."
      },
      {
        "title": "Error Handling",
        "body": "try {\n  await page.goto('https://example.com', { timeout: 30000 });\n  const hasResults = await page.locator('.results').isVisible().catch(() => false);\n  if (!hasResults) {\n    console.log('No results');\n    process.exit(0);\n  }\n} catch (error) {\n  console.error('Error:', error.message);\n  await page.screenshot({ path: 'tmp/error.png' });\n  process.exit(1);\n} finally {\n  await browser.close();\n}"
      },
      {
        "title": "Working Examples",
        "body": "examples/screenshot.mjs - Full-page screenshots\nexamples/scrape.mjs - Data extraction\nexamples/form-interaction.mjs - Form automation\nexamples/login-session.mjs - Persistent sessions"
      },
      {
        "title": "Reusable Templates",
        "body": "scripts/minimal-template.mjs - Clean starting point\nscripts/screenshot-template.mjs - Configurable screenshot\nscripts/scrape-template.mjs - Data scraping scaffold\n\nCopy templates:\n\ncp scripts/minimal-template.mjs tmp/my-task.mjs\n# Edit tmp/my-task.mjs, then run:\nnode tmp/my-task.mjs"
      },
      {
        "title": "Tooling Commands",
        "body": "# Record interactions to generate code\nnpx playwright codegen https://example.com\n\n# Debug selectors\nnpx playwright codegen --target javascript https://example.com\n\n# Show trace\nnpx playwright show-trace tmp/trace.zip"
      },
      {
        "title": "Deep References",
        "body": "references/selectors.md - Complete selector guide (CSS, text, XPath, ARIA, test-id)\nreferences/debugging.md - Debugging techniques (headless, slowMo, screenshots)\nreferences/troubleshooting.md - Common errors and solutions"
      },
      {
        "title": "Tips",
        "body": "Always put scripts in tmp/ — it's gitignored\nUse .mjs extension for ES modules (no type: module needed)\nAdd console.log() liberally for debugging\nUse page.screenshot() when things go wrong\nFor complex sites, add await page.waitForLoadState('networkidle')\nSee references/debugging.md for detailed debugging guide\nSee references/troubleshooting.md for common issues"
      }
    ],
    "body": "Playwright Browser Automation\n\n🤝 Developed together by Kuba + Mahone · Feb 2026\n\nCode-first browser automation with Playwright.\n\nWhen to Use\nTool\tUse When\nweb_fetch\tSimple pages, no JavaScript needed\nThis skill\tJavaScript-heavy sites, complex interactions, full control\nstealth-browser\tBot detection / Cloudflare issues\nbrowser tool\tVisual exploration, last resort\nplaywright-cli\tInteractive CLI without writing code\nSetup\n# One-time per project\nnpm init -y\nnpm install playwright\nnpx playwright install chromium\n\n\npackage.json example:\n\n{\n  \"name\": \"my-automation\",\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"playwright\": \"^1.40.0\"\n  }\n}\n\nMinimal Example\n// tmp/example.mjs\nimport { chromium } from 'playwright';\n\nconst browser = await chromium.launch();\nconst page = await browser.newPage();\n\nawait page.goto('https://example.com');\nconsole.log('Title:', await page.title());\n\nawait browser.close();\n\nnode tmp/example.mjs\n\nQuick Patterns\nScreenshot\nimport { chromium } from 'playwright';\nconst browser = await chromium.launch();\nconst page = await browser.newPage();\nawait page.setViewportSize({ width: 1280, height: 800 });\nawait page.goto('https://example.com');\nawait page.screenshot({ path: 'tmp/screenshot.png', fullPage: true });\nawait browser.close();\n\nScrape Data\nimport { chromium } from 'playwright';\nconst browser = await chromium.launch();\nconst page = await browser.newPage();\nawait page.goto('https://news.ycombinator.com');\nconst stories = await page.$$eval('.titleline > a', links => \n  links.slice(0, 5).map(a => ({ title: a.innerText, url: a.href }))\n);\nconsole.log(JSON.stringify(stories, null, 2));\nawait browser.close();\n\nForm Interaction\nawait page.goto('https://example.com/login');\nawait page.fill('input[name=\"email\"]', 'user@example.com');\nawait page.fill('input[name=\"password\"]', 'password');\nawait page.click('button[type=\"submit\"]');\n\nWait for Dynamic Content\n// Wait for network idle (SPA)\nawait page.goto(url, { waitUntil: 'networkidle' });\n\n// Wait for specific element\nawait page.waitForSelector('.results', { timeout: 10000 });\n\n// Wait for condition\nawait page.waitForFunction(() => \n  document.querySelectorAll('.item').length > 0\n);\n\nPersistent Session\nimport fs from 'fs';\nconst SESSION_FILE = 'tmp/session.json';\n\nlet context;\nif (fs.existsSync(SESSION_FILE)) {\n  context = await browser.newContext({ storageState: SESSION_FILE });\n} else {\n  context = await browser.newContext();\n}\nconst page = await context.newPage();\n// ... login ...\nawait context.storageState({ path: SESSION_FILE });\n\nHeadless vs Headed\n// Headless (default, fastest)\nawait chromium.launch({ headless: true });\n\n// Headed (see the browser)\nawait chromium.launch({ headless: false });\n\n// Slow motion (debugging)\nawait chromium.launch({ headless: false, slowMo: 100 });\n\nSelectors Quick Reference\n// CSS\nawait page.click('button.submit');\nawait page.fill('input#email', 'text');\n\n// Text content\nawait page.click('text=Submit');\nawait page.click('text=/log\\s*in/i');  // regex\n\n// XPath\nawait page.click('xpath=//button[@type=\"submit\"]');\n\n// ARIA role\nawait page.click('role=button[name=\"Submit\"]');\n\n// Test ID (most stable)\nawait page.click('[data-testid=\"submit-btn\"]');\n\n// Chain selectors\nawait page.click('nav >> text=Settings');\n\n\nSee references/selectors.md for complete selector guide.\n\nError Handling\ntry {\n  await page.goto('https://example.com', { timeout: 30000 });\n  const hasResults = await page.locator('.results').isVisible().catch(() => false);\n  if (!hasResults) {\n    console.log('No results');\n    process.exit(0);\n  }\n} catch (error) {\n  console.error('Error:', error.message);\n  await page.screenshot({ path: 'tmp/error.png' });\n  process.exit(1);\n} finally {\n  await browser.close();\n}\n\nExamples & Templates\nWorking Examples\nexamples/screenshot.mjs - Full-page screenshots\nexamples/scrape.mjs - Data extraction\nexamples/form-interaction.mjs - Form automation\nexamples/login-session.mjs - Persistent sessions\nReusable Templates\nscripts/minimal-template.mjs - Clean starting point\nscripts/screenshot-template.mjs - Configurable screenshot\nscripts/scrape-template.mjs - Data scraping scaffold\n\nCopy templates:\n\ncp scripts/minimal-template.mjs tmp/my-task.mjs\n# Edit tmp/my-task.mjs, then run:\nnode tmp/my-task.mjs\n\nTooling Commands\n# Record interactions to generate code\nnpx playwright codegen https://example.com\n\n# Debug selectors\nnpx playwright codegen --target javascript https://example.com\n\n# Show trace\nnpx playwright show-trace tmp/trace.zip\n\nDeep References\nreferences/selectors.md - Complete selector guide (CSS, text, XPath, ARIA, test-id)\nreferences/debugging.md - Debugging techniques (headless, slowMo, screenshots)\nreferences/troubleshooting.md - Common errors and solutions\nTips\nAlways put scripts in tmp/ — it's gitignored\nUse .mjs extension for ES modules (no type: module needed)\nAdd console.log() liberally for debugging\nUse page.screenshot() when things go wrong\nFor complex sites, add await page.waitForLoadState('networkidle')\nSee references/debugging.md for detailed debugging guide\nSee references/troubleshooting.md for common issues"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/mahone-bot/playwright-npx",
    "publisherUrl": "https://clawhub.ai/mahone-bot/playwright-npx",
    "owner": "mahone-bot",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/playwright-npx",
    "downloadUrl": "https://openagent3.xyz/downloads/playwright-npx",
    "agentUrl": "https://openagent3.xyz/skills/playwright-npx/agent",
    "manifestUrl": "https://openagent3.xyz/skills/playwright-npx/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/playwright-npx/agent.md"
  }
}