{
  "version": "riddle-proof.profile-result.v1",
  "profile_name": "riddle-site-v397-sitemap-docs-route-coverage",
  "runner": "riddle",
  "status": "product_regression",
  "baseline_policy": "invariant_only",
  "route": {
    "requested": "https://riddledc.com/docs/",
    "observed": "/docs/",
    "expected_path": "/docs/",
    "matched": true,
    "http_status": 200
  },
  "artifacts": {
    "screenshots": [
      "riddle-site-v397-sitemap-docs-route-coverage-desktop",
      "riddle-site-v397-sitemap-docs-route-coverage-phone",
      "riddle-site-v397-sitemap-docs-route-coverage-ipad-mini",
      "riddle-site-v397-sitemap-docs-route-coverage-ipad"
    ],
    "console": "console.json",
    "proof_json": "proof.json",
    "dom_summary": "dom-summary.json",
    "riddle_artifacts": [
      {
        "name": "proof.json",
        "url": "https://cdn.riddledc.com/scripts/job_f39d58a4/proof.json.json",
        "source": "artifacts"
      },
      {
        "name": "console.json",
        "url": "https://cdn.riddledc.com/scripts/job_f39d58a4/console.json.json",
        "source": "artifacts"
      },
      {
        "name": "dom-summary.json",
        "url": "https://cdn.riddledc.com/scripts/job_f39d58a4/dom-summary.json.json",
        "source": "artifacts"
      },
      {
        "name": "riddle-site-v397-sitemap-docs-route-coverage-desktop.png",
        "url": "https://cdn.riddledc.com/scripts/job_f39d58a4/riddle-site-v397-sitemap-docs-route-coverage-desktop.png",
        "source": "artifacts"
      },
      {
        "name": "riddle-site-v397-sitemap-docs-route-coverage-phone.png",
        "url": "https://cdn.riddledc.com/scripts/job_f39d58a4/riddle-site-v397-sitemap-docs-route-coverage-phone.png",
        "source": "artifacts"
      },
      {
        "name": "riddle-site-v397-sitemap-docs-route-coverage-ipad-mini.png",
        "url": "https://cdn.riddledc.com/scripts/job_f39d58a4/riddle-site-v397-sitemap-docs-route-coverage-ipad-mini.png",
        "source": "artifacts"
      },
      {
        "name": "riddle-site-v397-sitemap-docs-route-coverage-ipad.png",
        "url": "https://cdn.riddledc.com/scripts/job_f39d58a4/riddle-site-v397-sitemap-docs-route-coverage-ipad.png",
        "source": "artifacts"
      }
    ]
  },
  "checks": [
    {
      "type": "route_loaded",
      "label": "route_loaded",
      "status": "passed",
      "evidence": {
        "expected_path": "/docs/",
        "observed_paths": [
          "/docs/",
          "/docs/",
          "/docs/",
          "/docs/"
        ],
        "http_statuses": [
          200,
          200,
          200,
          200
        ]
      }
    },
    {
      "type": "selector_visible",
      "label": "selector_visible",
      "status": "passed",
      "evidence": {
        "selector": ".docs-page",
        "visible_counts": [
          1,
          1,
          1,
          1
        ]
      }
    },
    {
      "type": "text_visible",
      "label": "text_visible",
      "status": "passed",
      "evidence": {
        "text": "Tools",
        "matches": [
          true,
          true,
          true,
          true
        ]
      }
    },
    {
      "type": "http_status",
      "label": "public sitemap docs route coverage",
      "status": "failed",
      "evidence": {
        "url": "https://riddledc.com/sitemap.xml",
        "method": "GET",
        "allowed_statuses": [
          200
        ],
        "require_nonzero_bytes": false,
        "min_bytes": 1000,
        "allowed_content_types": [
          "text/xml",
          "application/xml"
        ],
        "viewports": [
          {
            "viewport": "desktop",
            "key": "GET https://riddledc.com/sitemap.xml",
            "url": "https://riddledc.com/sitemap.xml",
            "method": "GET",
            "status": 200,
            "status_text": "OK",
            "ok": false,
            "error": null,
            "content_type": "text/xml",
            "content_length": null,
            "bytes": 2901,
            "body_contains": {
              "<loc>https://riddledc.com/docs/scrape/</loc>": false,
              "<loc>https://riddledc.com/docs/map/</loc>": false,
              "<loc>https://riddledc.com/docs/crawl/</loc>": false,
              "<loc>https://riddledc.com/docs/visual-diff/</loc>": false,
              "<loc>https://riddledc.com/mcp/</loc>": false
            },
            "body_contains_missing": [
              "<loc>https://riddledc.com/docs/scrape/</loc>",
              "<loc>https://riddledc.com/docs/map/</loc>",
              "<loc>https://riddledc.com/docs/crawl/</loc>",
              "<loc>https://riddledc.com/docs/visual-diff/</loc>",
              "<loc>https://riddledc.com/mcp/</loc>"
            ],
            "body_sample": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n  <url>\n    <loc>https://riddledc.com/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>1.0</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/pricing/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.9</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/docs/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.9</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/docs/riddle-proof/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.8</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/examples/riddle-proof/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.7</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/docs/preview/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.8</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/faq/</loc>\n    <changefreq>monthly</changefreq>\n    <priority>0.7</priority>\n  </u",
            "failures": [
              {
                "code": "http_status_failed",
                "url": "https://riddledc.com/sitemap.xml",
                "status": 200,
                "method": "GET",
                "error": null,
                "content_type": "text/xml",
                "bytes": 2901,
                "allowed_statuses": [
                  200
                ],
                "min_bytes": 1000,
                "allowed_content_types": [
                  "text/xml",
                  "application/xml"
                ],
                "body_contains": [
                  "<loc>https://riddledc.com/docs/scrape/</loc>",
                  "<loc>https://riddledc.com/docs/map/</loc>",
                  "<loc>https://riddledc.com/docs/crawl/</loc>",
                  "<loc>https://riddledc.com/docs/visual-diff/</loc>",
                  "<loc>https://riddledc.com/mcp/</loc>"
                ],
                "body_contains_missing": [
                  "<loc>https://riddledc.com/docs/scrape/</loc>",
                  "<loc>https://riddledc.com/docs/map/</loc>",
                  "<loc>https://riddledc.com/docs/crawl/</loc>",
                  "<loc>https://riddledc.com/docs/visual-diff/</loc>",
                  "<loc>https://riddledc.com/mcp/</loc>"
                ],
                "body_sample": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n  <url>\n    <loc>https://riddledc.com/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>1.0</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/pricing/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.9</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/docs/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.9</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/docs/riddle-proof/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.8</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/examples/riddle-proof/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.7</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/docs/preview/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.8</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/faq/</loc>\n    <changefreq>monthly</changefreq>\n    <priority>0.7</priority>\n  </u"
              }
            ]
          }
        ],
        "failures": [
          {
            "viewport": "desktop",
            "failure": {
              "code": "http_status_failed",
              "url": "https://riddledc.com/sitemap.xml",
              "status": 200,
              "method": "GET",
              "error": null,
              "content_type": "text/xml",
              "bytes": 2901,
              "allowed_statuses": [
                200
              ],
              "min_bytes": 1000,
              "allowed_content_types": [
                "text/xml",
                "application/xml"
              ],
              "body_contains": [
                "<loc>https://riddledc.com/docs/scrape/</loc>",
                "<loc>https://riddledc.com/docs/map/</loc>",
                "<loc>https://riddledc.com/docs/crawl/</loc>",
                "<loc>https://riddledc.com/docs/visual-diff/</loc>",
                "<loc>https://riddledc.com/mcp/</loc>"
              ],
              "body_contains_missing": [
                "<loc>https://riddledc.com/docs/scrape/</loc>",
                "<loc>https://riddledc.com/docs/map/</loc>",
                "<loc>https://riddledc.com/docs/crawl/</loc>",
                "<loc>https://riddledc.com/docs/visual-diff/</loc>",
                "<loc>https://riddledc.com/mcp/</loc>"
              ],
              "body_sample": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n  <url>\n    <loc>https://riddledc.com/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>1.0</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/pricing/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.9</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/docs/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.9</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/docs/riddle-proof/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.8</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/examples/riddle-proof/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.7</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/docs/preview/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.8</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/faq/</loc>\n    <changefreq>monthly</changefreq>\n    <priority>0.7</priority>\n  </u"
            }
          }
        ]
      },
      "message": "HTTP status failed in 1 viewport(s)."
    },
    {
      "type": "no_horizontal_overflow",
      "label": "no_horizontal_overflow",
      "status": "passed",
      "evidence": {
        "max_overflow_px": 1,
        "overflow_px": [
          0,
          0,
          0,
          0
        ],
        "bounds_overflow_px": [
          0,
          0,
          0,
          0
        ],
        "overflow_offender_counts": [
          0,
          0,
          0,
          0
        ],
        "viewports": [
          "desktop",
          "phone",
          "ipad-mini",
          "ipad"
        ]
      }
    },
    {
      "type": "no_fatal_console_errors",
      "label": "no_fatal_console_errors",
      "status": "passed",
      "evidence": {
        "console_fatal_count": 0,
        "page_error_count": 0,
        "total_console_fatal_count": 0,
        "total_page_error_count": 0,
        "allowed_console_fatal_count": 0,
        "explicitly_allowed_console_fatal_count": 0,
        "allowed_expected_network_mock_console_count": 0,
        "allowed_expected_network_mock_console_events": [],
        "allowed_page_error_count": 0,
        "allowed_console_texts": [],
        "allowed_console_patterns": [],
        "allowed_page_error_texts": [],
        "allowed_page_error_patterns": []
      }
    }
  ],
  "summary": "riddle-site-v397-sitemap-docs-route-coverage failed 1 product invariant(s) across 4 viewport(s).",
  "captured_at": "2026-05-16T14:10:54.444Z",
  "evidence": {
    "version": "riddle-proof.profile-evidence.v1",
    "profile_name": "riddle-site-v397-sitemap-docs-route-coverage",
    "target_url": "https://riddledc.com/docs/",
    "baseline_policy": "invariant_only",
    "captured_at": "2026-05-16T14:10:54.444Z",
    "viewports": [
      {
        "name": "desktop",
        "width": 1280,
        "height": 900,
        "url": "https://riddledc.com/docs/",
        "route": {
          "requested": "https://riddledc.com/docs/",
          "observed": "/docs/",
          "expected_path": "/docs/",
          "matched": true,
          "http_status": 200
        },
        "title": "API Documentation - Riddle Distributed Computing",
        "body_text_length": 16754,
        "body_text_sample": "Skip to main content Riddle Docs Proof MCP Pricing Blog Playground Sign Up Log In DOCUMENTATION Quick Start Authentication Input Modes Steps Reference Screenshot Options Response & Debugging Webhooks Recipes API Reference Error Codes Guides Tools GUIDES Riddle Proof Preview Modes TOOLS Scrape Map Crawl Visual Diff Preview Server Preview Build Preview Try the Playground New to Riddle? Start with Script Mode — write Playwright, send it to our API, get results. For simpler jobs, use URL mode or Steps mode. API Documentation One endpoint: /v1/run. Send Playwright scripts or JSON, get screenshots. Sync by default. GPT Actions OpenAPI:/riddledc-actions-openapi.yaml(JSON,.well-known) Quick Start Your First Screenshot curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{\"url\": \"https://example.com\"}' \\\\ -o screenshot.png Get your API key from your dashboard. PNG bytes returned directly. 1 Create Account Sign up 2 Get API Key Dashboard 3 Make Request See examples below Authentication Two options: API keys (recommended) or JWT tokens. Using MCP? See Riddle MCP modes and setup. API Keys (Recommended) Create from your Dashboard or via API: # Create an API key curl -X POST \"https://api.riddledc.com/billing/api-keys\" \\\\ -H \"Authorization: Bearer $JWT_TOKEN\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{\"name\": \"Production Key\"}' # Response { \"apiKey\": \"rdc_live_abc123********************xyz789\", \"keyId\": \"key_0844fb72799dd7b3\", \"warning\": \"Save this key now - you will not be able to see it again!\" } Use in the Authorization header: Authorization: Bearer rdc_live_abc123********************xyz789 JWT Tokens (Alternative) Authenticate via AWS Cognito for short-lived tokens: curl -X POST \"https://cognito-idp.us-east-1.amazonaws.com/\" \\\\ -H \"Content-Type: application/x-amz-json-1.1\" \\\\ -H \"X-Amz-Target: AWSCognitoIdentityProviderService.InitiateAuth\" \\\\ -d '{ \"AuthFlow\": \"USER_PASSWORD_AUTH\", \"ClientId\": \"7u1bt3r20v613j7eaki9dkbhve\", \"AuthParameters\": { \"USERNAME\": \"your-email@example.com\", \"PASSWORD\": \"your-password\" } }' # Use the IdToken from the response When to use which: API keys for production (never expire, can rotate). JWT for quick testing (expires in 1 hour). Input Modes Four ways to use /v1/run. Pick based on complexity. MODE USE CASE EXAMPLE url Single screenshot { \"url\": \"https://example.com\" } urls Batch screenshots { \"urls\": [\"https://a.com\", \"https://b.com\"] } script Full Playwright (recommended) { \"script\": \"await page.goto(...)\" } steps JSON workflows (simple automation) { \"steps\": [{ \"goto\": \"...\" }, { \"click\": \"...\" }] } URL Mode Simplest option. Returns PNG directly. curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{\"url\": \"https://example.com\"}' -o screenshot.png Batch Mode Multiple URLs in one job. More cost-efficient. curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{ \"urls\": [ \"https://example.com\", \"https://example.com/pricing\", \"https://example.com/docs\" ] }' Script Mode (Recommended) Full Playwright API. Write the same code you'd write locally—we run it on our infrastructure. curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{ \"script\": \"await page.goto('\\\\''https://example.com'\\\\''); const title = await page.title(); console.log('\\\\''Title:'\\\\''', title); await saveScreenshot('\\\\''homepage'\\\\''');\" }' Script Helpers Scripts can wait on window hooks and emit structured JSON artifacts. await waitForWindow(\"appReady\", 30000); const data = await page.evaluate(() => window.appState); await saveJson(\"state\", data); To return a JSON value directly in the response, set options.returnResult: true in the request. Steps Mode JSON-based workflows. Good for simple automation—no code generation needed. curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{ \"steps\": [ { \"goto\": \"https://example.com/login\" }, { \"fill\": { \"selector\": \"#email\", \"value\": \"user@example.com\" } }, { \"fill\": { \"selector\": \"#password\", \"value\": \"secret\" } }, { \"click\": \"button[type=submit]\" }, { \"waitForUrl\": \"**/dashboard**\" }, { \"screenshot\": \"dashboard\" } ] }' Common Options These work with any input mode: { \"url\": \"https://example.com\", \"timeout_sec\": 60, \"options\": { \"viewport\": { \"width\": 1920, \"height\": 1080 }, \"fullPage\": true, \"cookies\": [{ \"name\": \"session\", \"value\": \"abc\", \"domain\": \"example.com\" }], \"headers\": { \"Authorization\": \"Bearer APP_TOKEN\" }, \"localStorage\": { \"token\": \"xyz\" } } } Stealth Mode Enable stealth mode to use the Patchright engine, which bypasses common bot detection systems including Cloudflare, Vercel, and Datadome. Available on any tool — just add \"stealth\": true. Trade-off: stealth mode disables console capture, so you won't get browser console logs in the response. curl -X POST \"https://api.riddledc.com/v1/run\" \\ -H \"Authorization: Bearer YOUR_API_KEY\" \\ -H \"Content-Type: application/json\" \\ -d '{ \"url\": \"https://protected-site.com\", \"stealth\": true, \"options\": { \"fullPage\": true } }' Steps Reference All available step types for steps mode. STEP DESCRIPTION EXAMPLE goto Navigate to URL { \"goto\": \"https://example.com\" } screenshot Capture screenshot { \"screenshot\": \"step1\" } click Click element { \"click\": \"button.submit\" } fill Fill input field { \"fill\": { \"selector\": \"#email\", \"value\": \"test@example.com\" } } type Type key-by-key { \"type\": { \"selector\": \"#search\", \"text\": \"query\" } } select Select dropdown { \"select\": { \"selector\": \"select#country\", \"value\": \"US\" } } check Check checkbox { \"check\": \"#agree\" } uncheck Uncheck checkbox { \"uncheck\": \"#newsletter\" } hover Hover element { \"hover\": \".dropdown\" } press Press key { \"press\": \"Enter\" } waitFor Wait for selector { \"waitFor\": \".loaded\" } waitForUrl Wait for URL match { \"waitForUrl\": \"**/success**\" } waitForTimeout Wait milliseconds { \"waitForTimeout\": 2000 } waitForLoadState Wait for load state { \"waitForLoadState\": \"networkidle\" } assert Assert conditions { \"assert\": [{ \"selectorExists\": \".success\" }] } saveHtml Save page HTML { \"saveHtml\": \"page\" } log Log message { \"log\": \"Starting flow\" } eval Run Playwright code { \"eval\": \"await page.evaluate(() => localStorage.clear())\" } Assertions Check page state without screenshotting. Abort early on failure. { \"steps\": [ { \"goto\": \"https://example.com/checkout\" }, { \"assert\": [{ \"selectorExists\": \".checkout-form\" }], \"onFail\": [\"screenshot\", \"abort\"] }, { \"fill\": { \"selector\": \"#card\", \"value\": \"4242424242424242\" } }, { \"click\": \"button.pay\" }, { \"assert\": [{ \"urlIncludes\": \"/confirmation\" }], \"onFail\": [\"screenshot\", \"abort\"] }, { \"screenshot\": \"confirmation\" } ] } // Assertion types: selectorExists, selectorMissing, urlIncludes, urlExcludes, textContains Eval Context The eval step runs in Node.js with Playwright's page object. Browser code is auto-wrapped: // Both work - browser code auto-wrapped: { \"eval\": \"document.title\" } { \"eval\": \"await page.evaluate(() => document.title)\" } // Playwright APIs work directly: { \"eval\": \"await page.click('.submit')\" } Screenshot Options Control what and how you capture. Simple (Full Page) { \"screenshot\": \"homepage\" } Element Screenshot Capture just a specific element: { \"screenshot\": { \"label\": \"navbar\", \"selector\": \"nav.main-nav\" } } Clipped Region { \"screenshot\": { \"label\": \"hero\", \"clip\": { \"x\": 0, \"y\": 0, \"width\": 1200, \"height\": 600 } } } Viewport Only { \"screenshot\": { \"label\": \"above-fold\", \"fullPage\": false } } Format Options // JPEG with quality { \"screenshot\": { \"label\": \"compressed\", \"type\": \"jpeg\", \"quality\": 75 } } // Retina scale { \"screenshot\": { \"label\": \"retina\", \"scale\": \"device\" } } // Transparent background { \"screenshot\": { \"label\": \"transparent\", \"omitBackground\":",
        "scroll_width": 1280,
        "client_width": 1280,
        "overflow_px": 0,
        "bounds_overflow_px": 0,
        "overflow_offenders": [],
        "selectors": {
          ".docs-page": {
            "count": 1,
            "visible_count": 1
          }
        },
        "frames": {},
        "text_sequences": {},
        "text_matches": {
          "text:Tools": true
        },
        "http_statuses": {
          "GET https://riddledc.com/sitemap.xml": {
            "version": "riddle-proof.http-status.v1",
            "url": "https://riddledc.com/sitemap.xml",
            "method": "GET",
            "status": 200,
            "ok": false,
            "error": null,
            "request_body_bytes": 0,
            "allowed_statuses": [
              200
            ],
            "require_nonzero_bytes": false,
            "min_bytes": 1000,
            "allowed_content_types": [
              "text/xml",
              "application/xml"
            ],
            "redirected": false,
            "final_url": "https://riddledc.com/sitemap.xml",
            "content_type": "text/xml",
            "content_length": null,
            "status_text": "OK",
            "bytes": 2901,
            "body_sample": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n  <url>\n    <loc>https://riddledc.com/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>1.0</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/pricing/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.9</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/docs/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.9</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/docs/riddle-proof/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.8</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/examples/riddle-proof/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.7</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/docs/preview/</loc>\n    <changefreq>weekly</changefreq>\n    <priority>0.8</priority>\n  </url>\n  <url>\n    <loc>https://riddledc.com/faq/</loc>\n    <changefreq>monthly</changefreq>\n    <priority>0.7</priority>\n  </u",
            "body_contains": {
              "<loc>https://riddledc.com/docs/scrape/</loc>": false,
              "<loc>https://riddledc.com/docs/map/</loc>": false,
              "<loc>https://riddledc.com/docs/crawl/</loc>": false,
              "<loc>https://riddledc.com/docs/visual-diff/</loc>": false,
              "<loc>https://riddledc.com/mcp/</loc>": false
            }
          }
        },
        "link_statuses": {},
        "setup_action_results": [],
        "screenshot_label": "riddle-site-v397-sitemap-docs-route-coverage-desktop"
      },
      {
        "name": "phone",
        "width": 390,
        "height": 844,
        "url": "https://riddledc.com/docs/",
        "route": {
          "requested": "https://riddledc.com/docs/",
          "observed": "/docs/",
          "expected_path": "/docs/",
          "matched": true,
          "http_status": 200
        },
        "title": "API Documentation - Riddle Distributed Computing",
        "body_text_length": 16681,
        "body_text_sample": "Skip to main content Riddle DOCUMENTATION Quick Start Authentication Input Modes Steps Reference Screenshot Options Response & Debugging Webhooks Recipes API Reference Error Codes Guides Tools GUIDES Riddle Proof Preview Modes TOOLS Scrape Map Crawl Visual Diff Preview Server Preview Build Preview New to Riddle? Start with Script Mode — write Playwright, send it to our API, get results. For simpler jobs, use URL mode or Steps mode. API Documentation One endpoint: /v1/run. Send Playwright scripts or JSON, get screenshots. Sync by default. GPT Actions OpenAPI:/riddledc-actions-openapi.yaml(JSON,.well-known) Quick Start Your First Screenshot curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{\"url\": \"https://example.com\"}' \\\\ -o screenshot.png Get your API key from your dashboard. PNG bytes returned directly. 1 Create Account Sign up 2 Get API Key Dashboard 3 Make Request See examples below Authentication Two options: API keys (recommended) or JWT tokens. Using MCP? See Riddle MCP modes and setup. API Keys (Recommended) Create from your Dashboard or via API: # Create an API key curl -X POST \"https://api.riddledc.com/billing/api-keys\" \\\\ -H \"Authorization: Bearer $JWT_TOKEN\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{\"name\": \"Production Key\"}' # Response { \"apiKey\": \"rdc_live_abc123********************xyz789\", \"keyId\": \"key_0844fb72799dd7b3\", \"warning\": \"Save this key now - you will not be able to see it again!\" } Use in the Authorization header: Authorization: Bearer rdc_live_abc123********************xyz789 JWT Tokens (Alternative) Authenticate via AWS Cognito for short-lived tokens: curl -X POST \"https://cognito-idp.us-east-1.amazonaws.com/\" \\\\ -H \"Content-Type: application/x-amz-json-1.1\" \\\\ -H \"X-Amz-Target: AWSCognitoIdentityProviderService.InitiateAuth\" \\\\ -d '{ \"AuthFlow\": \"USER_PASSWORD_AUTH\", \"ClientId\": \"7u1bt3r20v613j7eaki9dkbhve\", \"AuthParameters\": { \"USERNAME\": \"your-email@example.com\", \"PASSWORD\": \"your-password\" } }' # Use the IdToken from the response When to use which: API keys for production (never expire, can rotate). JWT for quick testing (expires in 1 hour). Input Modes Four ways to use /v1/run. Pick based on complexity. MODE USE CASE EXAMPLE url Single screenshot { \"url\": \"https://example.com\" } urls Batch screenshots { \"urls\": [\"https://a.com\", \"https://b.com\"] } script Full Playwright (recommended) { \"script\": \"await page.goto(...)\" } steps JSON workflows (simple automation) { \"steps\": [{ \"goto\": \"...\" }, { \"click\": \"...\" }] } URL Mode Simplest option. Returns PNG directly. curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{\"url\": \"https://example.com\"}' -o screenshot.png Batch Mode Multiple URLs in one job. More cost-efficient. curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{ \"urls\": [ \"https://example.com\", \"https://example.com/pricing\", \"https://example.com/docs\" ] }' Script Mode (Recommended) Full Playwright API. Write the same code you'd write locally—we run it on our infrastructure. curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{ \"script\": \"await page.goto('\\\\''https://example.com'\\\\''); const title = await page.title(); console.log('\\\\''Title:'\\\\''', title); await saveScreenshot('\\\\''homepage'\\\\''');\" }' Script Helpers Scripts can wait on window hooks and emit structured JSON artifacts. await waitForWindow(\"appReady\", 30000); const data = await page.evaluate(() => window.appState); await saveJson(\"state\", data); To return a JSON value directly in the response, set options.returnResult: true in the request. Steps Mode JSON-based workflows. Good for simple automation—no code generation needed. curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{ \"steps\": [ { \"goto\": \"https://example.com/login\" }, { \"fill\": { \"selector\": \"#email\", \"value\": \"user@example.com\" } }, { \"fill\": { \"selector\": \"#password\", \"value\": \"secret\" } }, { \"click\": \"button[type=submit]\" }, { \"waitForUrl\": \"**/dashboard**\" }, { \"screenshot\": \"dashboard\" } ] }' Common Options These work with any input mode: { \"url\": \"https://example.com\", \"timeout_sec\": 60, \"options\": { \"viewport\": { \"width\": 1920, \"height\": 1080 }, \"fullPage\": true, \"cookies\": [{ \"name\": \"session\", \"value\": \"abc\", \"domain\": \"example.com\" }], \"headers\": { \"Authorization\": \"Bearer APP_TOKEN\" }, \"localStorage\": { \"token\": \"xyz\" } } } Stealth Mode Enable stealth mode to use the Patchright engine, which bypasses common bot detection systems including Cloudflare, Vercel, and Datadome. Available on any tool — just add \"stealth\": true. Trade-off: stealth mode disables console capture, so you won't get browser console logs in the response. curl -X POST \"https://api.riddledc.com/v1/run\" \\ -H \"Authorization: Bearer YOUR_API_KEY\" \\ -H \"Content-Type: application/json\" \\ -d '{ \"url\": \"https://protected-site.com\", \"stealth\": true, \"options\": { \"fullPage\": true } }' Steps Reference All available step types for steps mode. STEP DESCRIPTION EXAMPLE goto Navigate to URL { \"goto\": \"https://example.com\" } screenshot Capture screenshot { \"screenshot\": \"step1\" } click Click element { \"click\": \"button.submit\" } fill Fill input field { \"fill\": { \"selector\": \"#email\", \"value\": \"test@example.com\" } } type Type key-by-key { \"type\": { \"selector\": \"#search\", \"text\": \"query\" } } select Select dropdown { \"select\": { \"selector\": \"select#country\", \"value\": \"US\" } } check Check checkbox { \"check\": \"#agree\" } uncheck Uncheck checkbox { \"uncheck\": \"#newsletter\" } hover Hover element { \"hover\": \".dropdown\" } press Press key { \"press\": \"Enter\" } waitFor Wait for selector { \"waitFor\": \".loaded\" } waitForUrl Wait for URL match { \"waitForUrl\": \"**/success**\" } waitForTimeout Wait milliseconds { \"waitForTimeout\": 2000 } waitForLoadState Wait for load state { \"waitForLoadState\": \"networkidle\" } assert Assert conditions { \"assert\": [{ \"selectorExists\": \".success\" }] } saveHtml Save page HTML { \"saveHtml\": \"page\" } log Log message { \"log\": \"Starting flow\" } eval Run Playwright code { \"eval\": \"await page.evaluate(() => localStorage.clear())\" } Assertions Check page state without screenshotting. Abort early on failure. { \"steps\": [ { \"goto\": \"https://example.com/checkout\" }, { \"assert\": [{ \"selectorExists\": \".checkout-form\" }], \"onFail\": [\"screenshot\", \"abort\"] }, { \"fill\": { \"selector\": \"#card\", \"value\": \"4242424242424242\" } }, { \"click\": \"button.pay\" }, { \"assert\": [{ \"urlIncludes\": \"/confirmation\" }], \"onFail\": [\"screenshot\", \"abort\"] }, { \"screenshot\": \"confirmation\" } ] } // Assertion types: selectorExists, selectorMissing, urlIncludes, urlExcludes, textContains Eval Context The eval step runs in Node.js with Playwright's page object. Browser code is auto-wrapped: // Both work - browser code auto-wrapped: { \"eval\": \"document.title\" } { \"eval\": \"await page.evaluate(() => document.title)\" } // Playwright APIs work directly: { \"eval\": \"await page.click('.submit')\" } Screenshot Options Control what and how you capture. Simple (Full Page) { \"screenshot\": \"homepage\" } Element Screenshot Capture just a specific element: { \"screenshot\": { \"label\": \"navbar\", \"selector\": \"nav.main-nav\" } } Clipped Region { \"screenshot\": { \"label\": \"hero\", \"clip\": { \"x\": 0, \"y\": 0, \"width\": 1200, \"height\": 600 } } } Viewport Only { \"screenshot\": { \"label\": \"above-fold\", \"fullPage\": false } } Format Options // JPEG with quality { \"screenshot\": { \"label\": \"compressed\", \"type\": \"jpeg\", \"quality\": 75 } } // Retina scale { \"screenshot\": { \"label\": \"retina\", \"scale\": \"device\" } } // Transparent background { \"screenshot\": { \"label\": \"transparent\", \"omitBackground\": true } } All Options OPTION TYPE DESCRIPTION label string Filename for s",
        "scroll_width": 390,
        "client_width": 390,
        "overflow_px": 0,
        "bounds_overflow_px": 0,
        "overflow_offenders": [],
        "selectors": {
          ".docs-page": {
            "count": 1,
            "visible_count": 1
          }
        },
        "frames": {},
        "text_sequences": {},
        "text_matches": {
          "text:Tools": true
        },
        "http_statuses": {},
        "link_statuses": {},
        "setup_action_results": [],
        "screenshot_label": "riddle-site-v397-sitemap-docs-route-coverage-phone"
      },
      {
        "name": "ipad-mini",
        "width": 768,
        "height": 1024,
        "url": "https://riddledc.com/docs/",
        "route": {
          "requested": "https://riddledc.com/docs/",
          "observed": "/docs/",
          "expected_path": "/docs/",
          "matched": true,
          "http_status": 200
        },
        "title": "API Documentation - Riddle Distributed Computing",
        "body_text_length": 16681,
        "body_text_sample": "Skip to main content Riddle DOCUMENTATION Quick Start Authentication Input Modes Steps Reference Screenshot Options Response & Debugging Webhooks Recipes API Reference Error Codes Guides Tools GUIDES Riddle Proof Preview Modes TOOLS Scrape Map Crawl Visual Diff Preview Server Preview Build Preview New to Riddle? Start with Script Mode — write Playwright, send it to our API, get results. For simpler jobs, use URL mode or Steps mode. API Documentation One endpoint: /v1/run. Send Playwright scripts or JSON, get screenshots. Sync by default. GPT Actions OpenAPI:/riddledc-actions-openapi.yaml(JSON,.well-known) Quick Start Your First Screenshot curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{\"url\": \"https://example.com\"}' \\\\ -o screenshot.png Get your API key from your dashboard. PNG bytes returned directly. 1 Create Account Sign up 2 Get API Key Dashboard 3 Make Request See examples below Authentication Two options: API keys (recommended) or JWT tokens. Using MCP? See Riddle MCP modes and setup. API Keys (Recommended) Create from your Dashboard or via API: # Create an API key curl -X POST \"https://api.riddledc.com/billing/api-keys\" \\\\ -H \"Authorization: Bearer $JWT_TOKEN\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{\"name\": \"Production Key\"}' # Response { \"apiKey\": \"rdc_live_abc123********************xyz789\", \"keyId\": \"key_0844fb72799dd7b3\", \"warning\": \"Save this key now - you will not be able to see it again!\" } Use in the Authorization header: Authorization: Bearer rdc_live_abc123********************xyz789 JWT Tokens (Alternative) Authenticate via AWS Cognito for short-lived tokens: curl -X POST \"https://cognito-idp.us-east-1.amazonaws.com/\" \\\\ -H \"Content-Type: application/x-amz-json-1.1\" \\\\ -H \"X-Amz-Target: AWSCognitoIdentityProviderService.InitiateAuth\" \\\\ -d '{ \"AuthFlow\": \"USER_PASSWORD_AUTH\", \"ClientId\": \"7u1bt3r20v613j7eaki9dkbhve\", \"AuthParameters\": { \"USERNAME\": \"your-email@example.com\", \"PASSWORD\": \"your-password\" } }' # Use the IdToken from the response When to use which: API keys for production (never expire, can rotate). JWT for quick testing (expires in 1 hour). Input Modes Four ways to use /v1/run. Pick based on complexity. MODE USE CASE EXAMPLE url Single screenshot { \"url\": \"https://example.com\" } urls Batch screenshots { \"urls\": [\"https://a.com\", \"https://b.com\"] } script Full Playwright (recommended) { \"script\": \"await page.goto(...)\" } steps JSON workflows (simple automation) { \"steps\": [{ \"goto\": \"...\" }, { \"click\": \"...\" }] } URL Mode Simplest option. Returns PNG directly. curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{\"url\": \"https://example.com\"}' -o screenshot.png Batch Mode Multiple URLs in one job. More cost-efficient. curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{ \"urls\": [ \"https://example.com\", \"https://example.com/pricing\", \"https://example.com/docs\" ] }' Script Mode (Recommended) Full Playwright API. Write the same code you'd write locally—we run it on our infrastructure. curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{ \"script\": \"await page.goto('\\\\''https://example.com'\\\\''); const title = await page.title(); console.log('\\\\''Title:'\\\\''', title); await saveScreenshot('\\\\''homepage'\\\\''');\" }' Script Helpers Scripts can wait on window hooks and emit structured JSON artifacts. await waitForWindow(\"appReady\", 30000); const data = await page.evaluate(() => window.appState); await saveJson(\"state\", data); To return a JSON value directly in the response, set options.returnResult: true in the request. Steps Mode JSON-based workflows. Good for simple automation—no code generation needed. curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{ \"steps\": [ { \"goto\": \"https://example.com/login\" }, { \"fill\": { \"selector\": \"#email\", \"value\": \"user@example.com\" } }, { \"fill\": { \"selector\": \"#password\", \"value\": \"secret\" } }, { \"click\": \"button[type=submit]\" }, { \"waitForUrl\": \"**/dashboard**\" }, { \"screenshot\": \"dashboard\" } ] }' Common Options These work with any input mode: { \"url\": \"https://example.com\", \"timeout_sec\": 60, \"options\": { \"viewport\": { \"width\": 1920, \"height\": 1080 }, \"fullPage\": true, \"cookies\": [{ \"name\": \"session\", \"value\": \"abc\", \"domain\": \"example.com\" }], \"headers\": { \"Authorization\": \"Bearer APP_TOKEN\" }, \"localStorage\": { \"token\": \"xyz\" } } } Stealth Mode Enable stealth mode to use the Patchright engine, which bypasses common bot detection systems including Cloudflare, Vercel, and Datadome. Available on any tool — just add \"stealth\": true. Trade-off: stealth mode disables console capture, so you won't get browser console logs in the response. curl -X POST \"https://api.riddledc.com/v1/run\" \\ -H \"Authorization: Bearer YOUR_API_KEY\" \\ -H \"Content-Type: application/json\" \\ -d '{ \"url\": \"https://protected-site.com\", \"stealth\": true, \"options\": { \"fullPage\": true } }' Steps Reference All available step types for steps mode. STEP DESCRIPTION EXAMPLE goto Navigate to URL { \"goto\": \"https://example.com\" } screenshot Capture screenshot { \"screenshot\": \"step1\" } click Click element { \"click\": \"button.submit\" } fill Fill input field { \"fill\": { \"selector\": \"#email\", \"value\": \"test@example.com\" } } type Type key-by-key { \"type\": { \"selector\": \"#search\", \"text\": \"query\" } } select Select dropdown { \"select\": { \"selector\": \"select#country\", \"value\": \"US\" } } check Check checkbox { \"check\": \"#agree\" } uncheck Uncheck checkbox { \"uncheck\": \"#newsletter\" } hover Hover element { \"hover\": \".dropdown\" } press Press key { \"press\": \"Enter\" } waitFor Wait for selector { \"waitFor\": \".loaded\" } waitForUrl Wait for URL match { \"waitForUrl\": \"**/success**\" } waitForTimeout Wait milliseconds { \"waitForTimeout\": 2000 } waitForLoadState Wait for load state { \"waitForLoadState\": \"networkidle\" } assert Assert conditions { \"assert\": [{ \"selectorExists\": \".success\" }] } saveHtml Save page HTML { \"saveHtml\": \"page\" } log Log message { \"log\": \"Starting flow\" } eval Run Playwright code { \"eval\": \"await page.evaluate(() => localStorage.clear())\" } Assertions Check page state without screenshotting. Abort early on failure. { \"steps\": [ { \"goto\": \"https://example.com/checkout\" }, { \"assert\": [{ \"selectorExists\": \".checkout-form\" }], \"onFail\": [\"screenshot\", \"abort\"] }, { \"fill\": { \"selector\": \"#card\", \"value\": \"4242424242424242\" } }, { \"click\": \"button.pay\" }, { \"assert\": [{ \"urlIncludes\": \"/confirmation\" }], \"onFail\": [\"screenshot\", \"abort\"] }, { \"screenshot\": \"confirmation\" } ] } // Assertion types: selectorExists, selectorMissing, urlIncludes, urlExcludes, textContains Eval Context The eval step runs in Node.js with Playwright's page object. Browser code is auto-wrapped: // Both work - browser code auto-wrapped: { \"eval\": \"document.title\" } { \"eval\": \"await page.evaluate(() => document.title)\" } // Playwright APIs work directly: { \"eval\": \"await page.click('.submit')\" } Screenshot Options Control what and how you capture. Simple (Full Page) { \"screenshot\": \"homepage\" } Element Screenshot Capture just a specific element: { \"screenshot\": { \"label\": \"navbar\", \"selector\": \"nav.main-nav\" } } Clipped Region { \"screenshot\": { \"label\": \"hero\", \"clip\": { \"x\": 0, \"y\": 0, \"width\": 1200, \"height\": 600 } } } Viewport Only { \"screenshot\": { \"label\": \"above-fold\", \"fullPage\": false } } Format Options // JPEG with quality { \"screenshot\": { \"label\": \"compressed\", \"type\": \"jpeg\", \"quality\": 75 } } // Retina scale { \"screenshot\": { \"label\": \"retina\", \"scale\": \"device\" } } // Transparent background { \"screenshot\": { \"label\": \"transparent\", \"omitBackground\": true } } All Options OPTION TYPE DESCRIPTION label string Filename for s",
        "scroll_width": 768,
        "client_width": 768,
        "overflow_px": 0,
        "bounds_overflow_px": 0,
        "overflow_offenders": [],
        "selectors": {
          ".docs-page": {
            "count": 1,
            "visible_count": 1
          }
        },
        "frames": {},
        "text_sequences": {},
        "text_matches": {
          "text:Tools": true
        },
        "http_statuses": {},
        "link_statuses": {},
        "setup_action_results": [],
        "screenshot_label": "riddle-site-v397-sitemap-docs-route-coverage-ipad-mini"
      },
      {
        "name": "ipad",
        "width": 820,
        "height": 1180,
        "url": "https://riddledc.com/docs/",
        "route": {
          "requested": "https://riddledc.com/docs/",
          "observed": "/docs/",
          "expected_path": "/docs/",
          "matched": true,
          "http_status": 200
        },
        "title": "API Documentation - Riddle Distributed Computing",
        "body_text_length": 16700,
        "body_text_sample": "Skip to main content Riddle DOCUMENTATION Quick Start Authentication Input Modes Steps Reference Screenshot Options Response & Debugging Webhooks Recipes API Reference Error Codes Guides Tools GUIDES Riddle Proof Preview Modes TOOLS Scrape Map Crawl Visual Diff Preview Server Preview Build Preview Try the Playground New to Riddle? Start with Script Mode — write Playwright, send it to our API, get results. For simpler jobs, use URL mode or Steps mode. API Documentation One endpoint: /v1/run. Send Playwright scripts or JSON, get screenshots. Sync by default. GPT Actions OpenAPI:/riddledc-actions-openapi.yaml(JSON,.well-known) Quick Start Your First Screenshot curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{\"url\": \"https://example.com\"}' \\\\ -o screenshot.png Get your API key from your dashboard. PNG bytes returned directly. 1 Create Account Sign up 2 Get API Key Dashboard 3 Make Request See examples below Authentication Two options: API keys (recommended) or JWT tokens. Using MCP? See Riddle MCP modes and setup. API Keys (Recommended) Create from your Dashboard or via API: # Create an API key curl -X POST \"https://api.riddledc.com/billing/api-keys\" \\\\ -H \"Authorization: Bearer $JWT_TOKEN\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{\"name\": \"Production Key\"}' # Response { \"apiKey\": \"rdc_live_abc123********************xyz789\", \"keyId\": \"key_0844fb72799dd7b3\", \"warning\": \"Save this key now - you will not be able to see it again!\" } Use in the Authorization header: Authorization: Bearer rdc_live_abc123********************xyz789 JWT Tokens (Alternative) Authenticate via AWS Cognito for short-lived tokens: curl -X POST \"https://cognito-idp.us-east-1.amazonaws.com/\" \\\\ -H \"Content-Type: application/x-amz-json-1.1\" \\\\ -H \"X-Amz-Target: AWSCognitoIdentityProviderService.InitiateAuth\" \\\\ -d '{ \"AuthFlow\": \"USER_PASSWORD_AUTH\", \"ClientId\": \"7u1bt3r20v613j7eaki9dkbhve\", \"AuthParameters\": { \"USERNAME\": \"your-email@example.com\", \"PASSWORD\": \"your-password\" } }' # Use the IdToken from the response When to use which: API keys for production (never expire, can rotate). JWT for quick testing (expires in 1 hour). Input Modes Four ways to use /v1/run. Pick based on complexity. MODE USE CASE EXAMPLE url Single screenshot { \"url\": \"https://example.com\" } urls Batch screenshots { \"urls\": [\"https://a.com\", \"https://b.com\"] } script Full Playwright (recommended) { \"script\": \"await page.goto(...)\" } steps JSON workflows (simple automation) { \"steps\": [{ \"goto\": \"...\" }, { \"click\": \"...\" }] } URL Mode Simplest option. Returns PNG directly. curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{\"url\": \"https://example.com\"}' -o screenshot.png Batch Mode Multiple URLs in one job. More cost-efficient. curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{ \"urls\": [ \"https://example.com\", \"https://example.com/pricing\", \"https://example.com/docs\" ] }' Script Mode (Recommended) Full Playwright API. Write the same code you'd write locally—we run it on our infrastructure. curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{ \"script\": \"await page.goto('\\\\''https://example.com'\\\\''); const title = await page.title(); console.log('\\\\''Title:'\\\\''', title); await saveScreenshot('\\\\''homepage'\\\\''');\" }' Script Helpers Scripts can wait on window hooks and emit structured JSON artifacts. await waitForWindow(\"appReady\", 30000); const data = await page.evaluate(() => window.appState); await saveJson(\"state\", data); To return a JSON value directly in the response, set options.returnResult: true in the request. Steps Mode JSON-based workflows. Good for simple automation—no code generation needed. curl -X POST \"https://api.riddledc.com/v1/run\" \\\\ -H \"Authorization: Bearer YOUR_API_KEY\" \\\\ -H \"Content-Type: application/json\" \\\\ -d '{ \"steps\": [ { \"goto\": \"https://example.com/login\" }, { \"fill\": { \"selector\": \"#email\", \"value\": \"user@example.com\" } }, { \"fill\": { \"selector\": \"#password\", \"value\": \"secret\" } }, { \"click\": \"button[type=submit]\" }, { \"waitForUrl\": \"**/dashboard**\" }, { \"screenshot\": \"dashboard\" } ] }' Common Options These work with any input mode: { \"url\": \"https://example.com\", \"timeout_sec\": 60, \"options\": { \"viewport\": { \"width\": 1920, \"height\": 1080 }, \"fullPage\": true, \"cookies\": [{ \"name\": \"session\", \"value\": \"abc\", \"domain\": \"example.com\" }], \"headers\": { \"Authorization\": \"Bearer APP_TOKEN\" }, \"localStorage\": { \"token\": \"xyz\" } } } Stealth Mode Enable stealth mode to use the Patchright engine, which bypasses common bot detection systems including Cloudflare, Vercel, and Datadome. Available on any tool — just add \"stealth\": true. Trade-off: stealth mode disables console capture, so you won't get browser console logs in the response. curl -X POST \"https://api.riddledc.com/v1/run\" \\ -H \"Authorization: Bearer YOUR_API_KEY\" \\ -H \"Content-Type: application/json\" \\ -d '{ \"url\": \"https://protected-site.com\", \"stealth\": true, \"options\": { \"fullPage\": true } }' Steps Reference All available step types for steps mode. STEP DESCRIPTION EXAMPLE goto Navigate to URL { \"goto\": \"https://example.com\" } screenshot Capture screenshot { \"screenshot\": \"step1\" } click Click element { \"click\": \"button.submit\" } fill Fill input field { \"fill\": { \"selector\": \"#email\", \"value\": \"test@example.com\" } } type Type key-by-key { \"type\": { \"selector\": \"#search\", \"text\": \"query\" } } select Select dropdown { \"select\": { \"selector\": \"select#country\", \"value\": \"US\" } } check Check checkbox { \"check\": \"#agree\" } uncheck Uncheck checkbox { \"uncheck\": \"#newsletter\" } hover Hover element { \"hover\": \".dropdown\" } press Press key { \"press\": \"Enter\" } waitFor Wait for selector { \"waitFor\": \".loaded\" } waitForUrl Wait for URL match { \"waitForUrl\": \"**/success**\" } waitForTimeout Wait milliseconds { \"waitForTimeout\": 2000 } waitForLoadState Wait for load state { \"waitForLoadState\": \"networkidle\" } assert Assert conditions { \"assert\": [{ \"selectorExists\": \".success\" }] } saveHtml Save page HTML { \"saveHtml\": \"page\" } log Log message { \"log\": \"Starting flow\" } eval Run Playwright code { \"eval\": \"await page.evaluate(() => localStorage.clear())\" } Assertions Check page state without screenshotting. Abort early on failure. { \"steps\": [ { \"goto\": \"https://example.com/checkout\" }, { \"assert\": [{ \"selectorExists\": \".checkout-form\" }], \"onFail\": [\"screenshot\", \"abort\"] }, { \"fill\": { \"selector\": \"#card\", \"value\": \"4242424242424242\" } }, { \"click\": \"button.pay\" }, { \"assert\": [{ \"urlIncludes\": \"/confirmation\" }], \"onFail\": [\"screenshot\", \"abort\"] }, { \"screenshot\": \"confirmation\" } ] } // Assertion types: selectorExists, selectorMissing, urlIncludes, urlExcludes, textContains Eval Context The eval step runs in Node.js with Playwright's page object. Browser code is auto-wrapped: // Both work - browser code auto-wrapped: { \"eval\": \"document.title\" } { \"eval\": \"await page.evaluate(() => document.title)\" } // Playwright APIs work directly: { \"eval\": \"await page.click('.submit')\" } Screenshot Options Control what and how you capture. Simple (Full Page) { \"screenshot\": \"homepage\" } Element Screenshot Capture just a specific element: { \"screenshot\": { \"label\": \"navbar\", \"selector\": \"nav.main-nav\" } } Clipped Region { \"screenshot\": { \"label\": \"hero\", \"clip\": { \"x\": 0, \"y\": 0, \"width\": 1200, \"height\": 600 } } } Viewport Only { \"screenshot\": { \"label\": \"above-fold\", \"fullPage\": false } } Format Options // JPEG with quality { \"screenshot\": { \"label\": \"compressed\", \"type\": \"jpeg\", \"quality\": 75 } } // Retina scale { \"screenshot\": { \"label\": \"retina\", \"scale\": \"device\" } } // Transparent background { \"screenshot\": { \"label\": \"transparent\", \"omitBackground\": true } } All Options OPTION TYPE DESCRIPTION label st",
        "scroll_width": 820,
        "client_width": 820,
        "overflow_px": 0,
        "bounds_overflow_px": 0,
        "overflow_offenders": [],
        "selectors": {
          ".docs-page": {
            "count": 1,
            "visible_count": 1
          }
        },
        "frames": {},
        "text_sequences": {},
        "text_matches": {
          "text:Tools": true
        },
        "http_statuses": {},
        "link_statuses": {},
        "setup_action_results": [],
        "screenshot_label": "riddle-site-v397-sitemap-docs-route-coverage-ipad"
      }
    ],
    "console": {
      "events": [],
      "fatal_count": 0
    },
    "page_errors": [],
    "dialogs": [],
    "network_mocks": [],
    "dom_summary": {
      "expected_viewport_count": 4,
      "viewport_count": 4,
      "partial": false,
      "routes": [
        {
          "requested": "https://riddledc.com/docs/",
          "observed": "/docs/",
          "expected_path": "/docs/",
          "matched": true,
          "http_status": 200
        },
        {
          "requested": "https://riddledc.com/docs/",
          "observed": "/docs/",
          "expected_path": "/docs/",
          "matched": true,
          "http_status": 200
        },
        {
          "requested": "https://riddledc.com/docs/",
          "observed": "/docs/",
          "expected_path": "/docs/",
          "matched": true,
          "http_status": 200
        },
        {
          "requested": "https://riddledc.com/docs/",
          "observed": "/docs/",
          "expected_path": "/docs/",
          "matched": true,
          "http_status": 200
        }
      ],
      "titles": [
        "API Documentation - Riddle Distributed Computing",
        "API Documentation - Riddle Distributed Computing",
        "API Documentation - Riddle Distributed Computing",
        "API Documentation - Riddle Distributed Computing"
      ],
      "overflow_px": [
        0,
        0,
        0,
        0
      ],
      "bounds_overflow_px": [
        0,
        0,
        0,
        0
      ],
      "overflow_offender_counts": [
        0,
        0,
        0,
        0
      ],
      "frames": [
        {
          "viewport": "desktop",
          "selectors": []
        },
        {
          "viewport": "phone",
          "selectors": []
        },
        {
          "viewport": "ipad-mini",
          "selectors": []
        },
        {
          "viewport": "ipad",
          "selectors": []
        }
      ],
      "http_status": [
        {
          "viewport": "desktop",
          "requests": [
            {
              "key": "GET https://riddledc.com/sitemap.xml",
              "url": "https://riddledc.com/sitemap.xml",
              "method": "GET",
              "status": 200,
              "ok": false,
              "error": null
            }
          ]
        }
      ],
      "link_status": [],
      "route_inventory": [],
      "network_mock_count": 0,
      "network_mock_hit_count": 0,
      "dialog_count": 0,
      "dialog_accept_count": 0,
      "dialog_dismiss_count": 0
    }
  },
  "riddle": {
    "job_id": "job_f39d58a4",
    "status": "completed",
    "terminal": true
  }
}
