{
  "schemaVersion": "1.0",
  "item": {
    "slug": "web-form-automation",
    "name": "Web Form Automation",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/flyingzl/web-form-automation",
    "canonicalUrl": "https://clawhub.ai/flyingzl/web-form-automation",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/web-form-automation",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=web-form-automation",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md",
      "scripts/form-submit.js",
      "scripts/webp-compress.sh"
    ],
    "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-05-07T17:22:31.273Z",
      "expiresAt": "2026-05-14T17:22:31.273Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=afrexai-annual-report",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=afrexai-annual-report",
        "contentDisposition": "attachment; filename=\"afrexai-annual-report-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/web-form-automation"
    },
    "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/web-form-automation",
    "agentPageUrl": "https://openagent3.xyz/skills/web-form-automation/agent",
    "manifestUrl": "https://openagent3.xyz/skills/web-form-automation/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/web-form-automation/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": "Web Form Automation",
        "body": "Automate web form interactions reliably using Playwright with best practices for session management, file uploads, and form submission."
      },
      {
        "title": "Quick Start",
        "body": "const { chromium } = require('playwright');\n\n// Basic form automation\nconst browser = await chromium.launch({ headless: true });\nconst page = await browser.newPage();\nawait page.goto('https://example.com/form');\n\n// Upload compressed images\nawait page.locator('input[type=\"file\"]').setInputFiles('/path/to/image.webp');\n\n// Type text (triggers events properly)\nawait page.locator('textarea').pressSequentially('Your text', { delay: 30 });\n\n// Submit form\nawait page.locator('button[type=\"submit\"]').click({ force: true });"
      },
      {
        "title": "Using Browser Session Data",
        "body": "When user provides a JSON file with session data:\n\nconst sessionData = JSON.parse(fs.readFileSync('session.json', 'utf8'));\n\n// Set cookies before navigating\nfor (const cookie of sessionData.cookies || []) {\n  await context.addCookies([cookie]);\n}\n\n// Set localStorage/sessionStorage\nawait page.evaluate((data) => {\n  for (const [k, v] of Object.entries(data.localStorage || {})) {\n    localStorage.setItem(k, v);\n  }\n}, sessionData);"
      },
      {
        "title": "Image Compression",
        "body": "Always compress images before upload for reliability:\n\n# Convert to webp for best compression\nconvert input.png output.webp\n\n# Or resize if needed\nconvert input.png -resize 1024x1024 output.webp\n\nSize comparison:\n\nOriginal PNG: ~4MB\nCompressed PNG: ~1MB\nWebP: ~30-50KB (99% smaller)"
      },
      {
        "title": "Upload Sequence",
        "body": "// 1. Find file inputs\nconst fileInputs = await page.locator('input[type=\"file\"]').all();\n\n// 2. Upload with waiting time\nawait fileInputs[0].setInputFiles('/path/to/start.webp');\nawait page.waitForTimeout(3000); // Wait for upload to process\n\nawait fileInputs[1].setInputFiles('/path/to/end.webp');\nawait page.waitForTimeout(3000);"
      },
      {
        "title": "Use pressSequentially, not fill()",
        "body": "❌ Don't use fill() - doesn't trigger input events:\n\nawait textInput.fill('text'); // May not activate submit button\n\n✅ Use pressSequentially() - simulates real typing:\n\nawait textInput.pressSequentially('text', { delay: 30 });"
      },
      {
        "title": "Trigger Events Manually (if needed)",
        "body": "await page.evaluate(() => {\n  const el = document.querySelector('textarea');\n  el.dispatchEvent(new Event('input', { bubbles: true }));\n  el.dispatchEvent(new Event('change', { bubbles: true }));\n});"
      },
      {
        "title": "Force Click When Disabled",
        "body": "If button appears disabled but should be clickable:\n\nawait button.click({ force: true });"
      },
      {
        "title": "Check Button State",
        "body": "const isEnabled = await button.isEnabled();\nconst isVisible = await button.isVisible();"
      },
      {
        "title": "Complete Example: Video Generation Form",
        "body": "const { chromium } = require('playwright');\nconst fs = require('fs');\n\nasync function submitVideoForm(sessionFile, startImage, endImage, prompt) {\n  const browser = await chromium.launch({ \n    headless: true, \n    args: ['--no-sandbox'] \n  });\n  const context = await browser.newContext();\n  const page = await context.newPage();\n  \n  // Load session if provided\n  if (fs.existsSync(sessionFile)) {\n    const session = JSON.parse(fs.readFileSync(sessionFile, 'utf8'));\n    // Set cookies, localStorage...\n  }\n  \n  // Navigate\n  await page.goto('https://example.com/video', { \n    waitUntil: 'domcontentloaded' \n  });\n  await page.waitForTimeout(3000);\n  \n  // Upload images (webp compressed)\n  const inputs = await page.locator('input[type=\"file\"]').all();\n  await inputs[0].setInputFiles(startImage);\n  await page.waitForTimeout(3000);\n  await inputs[1].setInputFiles(endImage);\n  await page.waitForTimeout(3000);\n  \n  // Select options\n  await page.click('text=Seedance 2.0 Fast');\n  await page.click('text=15s');\n  \n  // Type prompt\n  const textarea = page.locator('textarea').first();\n  await textarea.pressSequentially(prompt, { delay: 30 });\n  await page.waitForTimeout(2000);\n  \n  // Submit\n  await page.locator('button[class*=\"submit\"]').click({ force: true });\n  \n  // Wait and screenshot\n  await page.waitForTimeout(5000);\n  await page.screenshot({ path: 'result.png' });\n  \n  await browser.close();\n}"
      },
      {
        "title": "Scripts",
        "body": "The scripts/ directory contains reusable automation scripts:\n\nwebp-compress.sh - Convert images to webp format\nform-submit.js - Generic form submission template"
      },
      {
        "title": "Button stays gray/disabled",
        "body": "Wait longer after file upload (3+ seconds)\nEnsure text input triggers events (use pressSequentially)\nCheck if images are still uploading"
      },
      {
        "title": "Upload times out",
        "body": "Compress images to webp format first\nReduce image dimensions if very large"
      },
      {
        "title": "Form doesn't submit",
        "body": "Use force: true for click\nCheck button selector is correct\nVerify all required fields are filled"
      }
    ],
    "body": "Web Form Automation\n\nAutomate web form interactions reliably using Playwright with best practices for session management, file uploads, and form submission.\n\nQuick Start\nconst { chromium } = require('playwright');\n\n// Basic form automation\nconst browser = await chromium.launch({ headless: true });\nconst page = await browser.newPage();\nawait page.goto('https://example.com/form');\n\n// Upload compressed images\nawait page.locator('input[type=\"file\"]').setInputFiles('/path/to/image.webp');\n\n// Type text (triggers events properly)\nawait page.locator('textarea').pressSequentially('Your text', { delay: 30 });\n\n// Submit form\nawait page.locator('button[type=\"submit\"]').click({ force: true });\n\nSession Management\nUsing Browser Session Data\n\nWhen user provides a JSON file with session data:\n\nconst sessionData = JSON.parse(fs.readFileSync('session.json', 'utf8'));\n\n// Set cookies before navigating\nfor (const cookie of sessionData.cookies || []) {\n  await context.addCookies([cookie]);\n}\n\n// Set localStorage/sessionStorage\nawait page.evaluate((data) => {\n  for (const [k, v] of Object.entries(data.localStorage || {})) {\n    localStorage.setItem(k, v);\n  }\n}, sessionData);\n\nFile Upload Best Practices\nImage Compression\n\nAlways compress images before upload for reliability:\n\n# Convert to webp for best compression\nconvert input.png output.webp\n\n# Or resize if needed\nconvert input.png -resize 1024x1024 output.webp\n\n\nSize comparison:\n\nOriginal PNG: ~4MB\nCompressed PNG: ~1MB\nWebP: ~30-50KB (99% smaller)\nUpload Sequence\n// 1. Find file inputs\nconst fileInputs = await page.locator('input[type=\"file\"]').all();\n\n// 2. Upload with waiting time\nawait fileInputs[0].setInputFiles('/path/to/start.webp');\nawait page.waitForTimeout(3000); // Wait for upload to process\n\nawait fileInputs[1].setInputFiles('/path/to/end.webp');\nawait page.waitForTimeout(3000);\n\nText Input Best Practices\nUse pressSequentially, not fill()\n\n❌ Don't use fill() - doesn't trigger input events:\n\nawait textInput.fill('text'); // May not activate submit button\n\n\n✅ Use pressSequentially() - simulates real typing:\n\nawait textInput.pressSequentially('text', { delay: 30 });\n\nTrigger Events Manually (if needed)\nawait page.evaluate(() => {\n  const el = document.querySelector('textarea');\n  el.dispatchEvent(new Event('input', { bubbles: true }));\n  el.dispatchEvent(new Event('change', { bubbles: true }));\n});\n\nButton Clicking\nForce Click When Disabled\n\nIf button appears disabled but should be clickable:\n\nawait button.click({ force: true });\n\nCheck Button State\nconst isEnabled = await button.isEnabled();\nconst isVisible = await button.isVisible();\n\nComplete Example: Video Generation Form\nconst { chromium } = require('playwright');\nconst fs = require('fs');\n\nasync function submitVideoForm(sessionFile, startImage, endImage, prompt) {\n  const browser = await chromium.launch({ \n    headless: true, \n    args: ['--no-sandbox'] \n  });\n  const context = await browser.newContext();\n  const page = await context.newPage();\n  \n  // Load session if provided\n  if (fs.existsSync(sessionFile)) {\n    const session = JSON.parse(fs.readFileSync(sessionFile, 'utf8'));\n    // Set cookies, localStorage...\n  }\n  \n  // Navigate\n  await page.goto('https://example.com/video', { \n    waitUntil: 'domcontentloaded' \n  });\n  await page.waitForTimeout(3000);\n  \n  // Upload images (webp compressed)\n  const inputs = await page.locator('input[type=\"file\"]').all();\n  await inputs[0].setInputFiles(startImage);\n  await page.waitForTimeout(3000);\n  await inputs[1].setInputFiles(endImage);\n  await page.waitForTimeout(3000);\n  \n  // Select options\n  await page.click('text=Seedance 2.0 Fast');\n  await page.click('text=15s');\n  \n  // Type prompt\n  const textarea = page.locator('textarea').first();\n  await textarea.pressSequentially(prompt, { delay: 30 });\n  await page.waitForTimeout(2000);\n  \n  // Submit\n  await page.locator('button[class*=\"submit\"]').click({ force: true });\n  \n  // Wait and screenshot\n  await page.waitForTimeout(5000);\n  await page.screenshot({ path: 'result.png' });\n  \n  await browser.close();\n}\n\nScripts\n\nThe scripts/ directory contains reusable automation scripts:\n\nwebp-compress.sh - Convert images to webp format\nform-submit.js - Generic form submission template\nTroubleshooting\nButton stays gray/disabled\nWait longer after file upload (3+ seconds)\nEnsure text input triggers events (use pressSequentially)\nCheck if images are still uploading\nUpload times out\nCompress images to webp format first\nReduce image dimensions if very large\nForm doesn't submit\nUse force: true for click\nCheck button selector is correct\nVerify all required fields are filled"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/flyingzl/web-form-automation",
    "publisherUrl": "https://clawhub.ai/flyingzl/web-form-automation",
    "owner": "flyingzl",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/web-form-automation",
    "downloadUrl": "https://openagent3.xyz/downloads/web-form-automation",
    "agentUrl": "https://openagent3.xyz/skills/web-form-automation/agent",
    "manifestUrl": "https://openagent3.xyz/skills/web-form-automation/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/web-form-automation/agent.md"
  }
}