{
  "openapi": "3.0.1",
  "info": {
    "title": "Python Web Scraper — Playwright, Any Website",
    "description": "Returns url, title, text and textTruncated for every page — or exactly the fields your own Python function returns. Real Chromium through Playwright, so JavaScript-rendered pages behave like static ones. Crawls whole sections, respects robots.txt, retries failures. Empty runs cost nothing.",
    "version": "0.2",
    "x-build-id": "aWwpqbyQxL3oqbLvp"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/eszetael_lab~reliable-playwright-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-eszetael_lab-reliable-playwright-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/eszetael_lab~reliable-playwright-scraper/runs": {
      "post": {
        "operationId": "runs-sync-eszetael_lab-reliable-playwright-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/eszetael_lab~reliable-playwright-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-eszetael_lab-reliable-playwright-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "required": [
          "startUrls"
        ],
        "properties": {
          "startUrls": {
            "title": "Start URLs",
            "minItems": 1,
            "type": "array",
            "description": "URLs to start crawling from.",
            "items": {
              "type": "object",
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "title": "URL of a web page",
                  "format": "uri"
                }
              }
            }
          },
          "pageFunction": {
            "title": "Page function",
            "type": "string",
            "description": "Async Python run on each page. Signature: async def page_function(page, context, request). `page` is a Playwright Page, `request.url` is the current URL. Return a dict or list of dicts to save to the dataset (or None to skip). The prefilled function works on ANY site: it returns the page URL, title, the first 5000 characters of visible text, and `textTruncated` — a flag telling you whether the page had more text than that, so a truncated record never looks like a complete one. Change only the start URL and you still get data. Write your own selectors when you want specific fields; the README has a worked example.",
            "default": "async def page_function(page, context, request):\n    body = await page.inner_text('body')\n    return {\n        'url': request.url,\n        'title': await page.title(),\n        'text': body[:5000],\n        'textTruncated': len(body) > 5000,\n    }"
          },
          "linkSelector": {
            "title": "Link selector",
            "type": "string",
            "description": "CSS selector for links to enqueue and follow (e.g. a[href]). Empty = scrape only the start URLs."
          },
          "includeGlobs": {
            "title": "Include globs",
            "type": "array",
            "description": "Only enqueue URLs matching these glob patterns, e.g. https://example.com/product/*. Both shapes are accepted: a plain string, or the {\"glob\": \"...\"} object the Console editor writes.",
            "items": {
              "type": "object",
              "required": [
                "glob"
              ],
              "properties": {
                "glob": {
                  "type": "string",
                  "title": "Glob of a web page"
                }
              }
            }
          },
          "maxRequestsPerCrawl": {
            "title": "Max pages to crawl",
            "type": "integer",
            "description": "Hard limit on pages fetched in the whole run. A crawled page usually yields one record and you are billed per record ($0.003), so this doubles as a cost ceiling: 200 pages is about $0.60. It also bounds how long the run takes — measured on a real site, a heavy page costs roughly 12 seconds of run time, so 200 pages is around 10 minutes.",
            "default": 100
          },
          "maxConcurrency": {
            "title": "Max concurrency",
            "type": "integer",
            "description": "Maximum pages loaded in parallel.",
            "default": 5
          },
          "requestTimeoutSecs": {
            "title": "Request timeout (seconds)",
            "type": "integer",
            "description": "Total budget for one page: waiting for waitUntil, plus extraction and your page function. Measured 11-08 on a documentation site: at 45s every page ran out of time before reaching 'load', so every record was flagged as possibly incomplete; at a larger budget none did — and the crawl finished FASTER. Raise it for heavy sites; the run status tells you when pages ran out of time.",
            "default": 90
          },
          "waitUntil": {
            "title": "Wait until",
            "enum": [
              "load",
              "domcontentloaded",
              "networkidle"
            ],
            "type": "string",
            "description": "Which page state to wait for before extracting. Navigation always finishes at 'domcontentloaded'; this setting is then reached on a bounded budget derived from requestTimeoutSecs. A page that does not get there in time is still extracted, and the run status says how many pages that happened to — so incomplete content is never silent.",
            "default": "load"
          },
          "respectRobotsTxt": {
            "title": "Respect robots.txt",
            "type": "boolean",
            "description": "Skip URLs disallowed by the site's robots.txt or TDM reservation. Keep on unless you own the target site.",
            "default": true
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Proxy for the requests. Datacenter is fine for most sites; use RESIDENTIAL for heavily protected ones.",
            "default": {
              "useApifyProxy": true
            }
          },
          "blockResources": {
            "title": "Block images, fonts and media",
            "type": "boolean",
            "description": "Stop the browser downloading images, fonts, media and stylesheets. The HTML, the DOM and every URL in it are unchanged — you still get image src attributes, you just do not pay to fetch the bytes. On residential proxy (billed per gigabyte) this is usually the single largest saving available, and pages load faster. Turn it off if your page function takes screenshots or needs rendered layout.",
            "default": true
          },
          "sessionMode": {
            "title": "Session handling",
            "enum": [
              "auto",
              "sticky",
              "off"
            ],
            "type": "string",
            "description": "How browser sessions (cookies, storage, proxy exit node) are reused across pages. 'auto' rotates them, which is right for crawling public pages at scale. 'sticky' keeps ONE session for the whole run — use it when your page function logs in, because a rotating session drops the cookie the site just issued and you end up in a login loop. 'off' disables session handling entirely.",
            "default": "auto"
          },
          "maxItems": {
            "title": "Max items",
            "type": "integer",
            "description": "Hard cap on delivered records. You are billed per delivered record ($0.003), so this is also your cost ceiling: the default of 100 caps a run at $0.30. Set 0 for no cap (up to the safety limit of 50000, i.e. $150).",
            "default": 100
          },
          "deliverEmptyRecords": {
            "title": "Deliver records from pages that returned nothing",
            "type": "boolean",
            "description": "A page that did not open — a bot wall, a timeout mid-render — still produces a record, usually {\"url\": ..., \"title\": \"\", \"text\": \"\"}. You are charged per delivered record, so those would cost you full price for nothing. By default they are neither delivered nor charged, and the run log says how many there were. Turn this on if you want a row for every page attempted, including the ones that came back empty. Responses that are not a document (PDF, video, archive) or that declare a size above 25 MB are dropped the same way. Note the limit of that check: a server that does not send Content-Length cannot be judged before its body is downloaded, so an undeclared huge response still reaches the browser. The previous name of this field, skipEmptyRecords, still works and means the opposite.",
            "default": false
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}