Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

If Chrome DevTools Protocol says Page.captureScreenshot wasn’t found, first check that you connected to a page target and that the running browser’s /json/protocol actually lists the command. Then verify the method’s exact capitalization, the raw JSON request, and whether your client’s generated protocol types match that browser. The method is documented in CDP’s Page domain, but CDP revisions can differ.

What the error means

Page.captureScreenshot is the CDP command for capturing a page screenshot. It belongs to the Page domain, accepts optional capture settings, and returns image data encoded as base64 in the response’s result.data field. If a server or wrapper says the method wasn’t found, it is not recognizing that exact command at the endpoint or session you are using.

That does not by itself prove the browser cannot take screenshots. The common possibilities are that the connection is aimed at a browser-scoped WebSocket rather than a page target, the selected target is not a page, the running browser does not expose that command in its protocol, the client’s generated bindings were made for a different CDP revision, or the raw request was serialized incorrectly. Check those possibilities in that order instead of changing the method name at random.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Diagnose the browser, protocol and target

Use the same host and port as the running browser’s remote-debugging endpoint. Replace HOST and PORT below with the actual values. These requests inspect the browser that is running your job, rather than relying on an online protocol definition that may describe a different revision.

1. Identify the browser endpoint

curl -sS http://HOST:PORT/json/version

Record the Browser, Protocol-Version and webSocketDebuggerUrl values in the response. The endpoint exposed in /json/version is browser-scoped: it is useful for browser metadata and browser-level commands, but it is not the endpoint to assume for a command in the Page domain.

2. Check whether this browser lists the command

curl -sS http://HOST:PORT/json/protocol | jq '.domains[] | select(.domain == "Page") | .commands[] | select(.name == "captureScreenshot")'

This uses jq to search the protocol JSON returned by the running browser. If the output contains the command object, the browser’s advertised protocol includes Page.captureScreenshot. If there is no output, confirm that the response came from the intended browser and that it is valid protocol JSON. If the command is genuinely absent, use a Chrome or Chromium build that exposes it, or choose a capability supported by that build; changing capitalization in your client will not add a missing command.

3. Select a page target, not the browser target

curl -sS http://HOST:PORT/json | jq '.[] | select(.type == "page") | {title, url, webSocketDebuggerUrl}'

Choose a target whose type is page, then connect to that target’s own webSocketDebuggerUrl. A page-domain command sent to the browser-scoped endpoint may fail because that endpoint is for browser-scoped commands. If /json returns no page target, there is no page target in that listing to capture; open or create the page through the setup you use for that browser, then inspect the listing again.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

4. Compare the client with the running protocol

Call Browser.getVersion and inspect its product, protocolVersion, revision, userAgent and jsVersion fields. Compare the returned protocol and browser revision with the version your client binding or wrapper was generated for. CDP’s tip-of-tree definition changes frequently, and backward compatibility is not guaranteed. A client that compiles successfully can still lack types or method mappings for the browser it connects to.

Send the method exactly as CDP expects

The raw method string is case-sensitive in practice: use Page.captureScreenshot, with an uppercase P for the domain and lowercase c in captureScreenshot. Do not send page.captureScreenshot, Page.captureScreenshot(), or a wrapper-specific alias as the raw CDP method.

Start with the smallest valid request:

{"id":1,"method":"Page.captureScreenshot"}

Or ask for a PNG and capture beyond the viewport:

{"id":2,"method":"Page.captureScreenshot","params":{"format":"png","captureBeyondViewport":true}}

The response is shaped like this, with the image bytes encoded as base64:

{"id":2,"result":{"data":"<base64 image data>"}}

Match the response to the request by its id. When using a raw WebSocket client, read incoming messages until the response with the ID you sent arrives; do not mistake an intervening event for the command result. If the minimal request works but an option-bearing request does not, remove optional parameters and add them back one at a time to identify the problematic field or value.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Capture parameters you can add

The Page command documents these optional fields:

  • clip: restricts the captured area to a specified clip.
  • format: selects the image format.
  • quality: supplies an image quality setting where applicable.
  • captureBeyondViewport: controls capture beyond the viewport.
  • fromSurface: controls whether capture is from the surface.
  • optimizeForSpeed: requests optimization for speed.

Begin without options when diagnosing method resolution. Once that succeeds, add only the settings your use case needs. A failure with a parameter-bearing request is a different clue from a failure on the bare method: check the parameter names and values against the protocol exposed by that browser.

When to enable the Page domain

Some client wrappers require an explicit Page.enable call as part of session setup, especially when they manage page events. Follow the wrapper’s setup sequence if it requires that step, but keep the screenshot method string exactly Page.captureScreenshot. Do not treat Page.enable as a substitute for using a page-target connection or a compatible protocol binding.

Runnable Python example: discover a page and save its screenshot

This example uses websocket-client to inspect the target list, connect to the first page target, send the raw command, and decode the returned image. Install the dependency with python -m pip install websocket-client. Set CDP_BASE to the browser’s HTTP debugging address, including its port.

import base64
import json
import os
import urllib.request

from websocket import create_connection

CDP_BASE = os.environ.get("CDP_BASE", "http://127.0.0.1:9222")

with urllib.request.urlopen(f"{CDP_BASE}/json/version", timeout=10) as response:
    version = json.load(response)
print("Browser:", version.get("Browser"))
print("Protocol-Version:", version.get("Protocol-Version"))

with urllib.request.urlopen(f"{CDP_BASE}/json", timeout=10) as response:
    targets = json.load(response)
page = next((target for target in targets if target.get("type") == "page"), None)
if page is None:
    raise RuntimeError("No page target found at /json")

ws = create_connection(page["webSocketDebuggerUrl"], timeout=30)
try:
    # Some wrappers require Page.enable as session setup; the screenshot
    # method itself remains Page.captureScreenshot.
    ws.send(json.dumps({"id": 1, "method": "Page.enable"}))
    while True:
        message = json.loads(ws.recv())
        if message.get("id") == 1:
            if "error" in message:
                raise RuntimeError(f"Page.enable failed: {message['error']}")
            break

    ws.send(json.dumps({
        "id": 2,
        "method": "Page.captureScreenshot",
        "params": {"format": "png", "captureBeyondViewport": True}
    }))
    while True:
        message = json.loads(ws.recv())
        if message.get("id") == 2:
            if "error" in message:
                raise RuntimeError(f"Screenshot failed: {message['error']}")
            image_data = base64.b64decode(message["result"]["data"])
            with open("screenshot.png", "wb") as image_file:
                image_file.write(image_data)
            print("Saved screenshot.png")
            break
finally:
    ws.close()

If your wrapper does not require Page.enable, the screenshot request can be sent directly after connecting. If this example reports that no page exists, inspect /json and the browser launch/session setup before debugging the screenshot method. If the command is rejected despite selecting a page target, compare the browser’s /json/protocol with the client version and test the minimal request without parameters.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Fixes by symptom

What you observe Likely cause What to do
The raw command is rejected as unknown, and the command is absent from /json/protocol. The running browser does not advertise this Page command in its protocol. Use a Chrome or Chromium build that exposes Page.captureScreenshot, or use a screenshot capability that the current build supports.
The protocol lists the command, but a raw call to the browser WebSocket fails. The connection is browser-scoped rather than attached to a page target. Choose a target of type page from /json and connect to its webSocketDebuggerUrl.
The command works through one client but the wrapper claims it is missing. The wrapper’s generated types or mappings may be for another CDP revision. Update the wrapper or regenerate its protocol types for the connected browser revision; verify the raw method string remains unchanged.
A request fails only after adding options. The issue may be a parameter or value rather than method resolution. Retry the bare method, then add documented options individually and check them against the running browser’s protocol.
The request appears to receive no result, or the client reports an unexpected response. The client may not be correlating messages with request IDs, or may be treating an event as the result. Send an integer id, then read until a response with that same ID arrives. Inspect the matching response’s result or error field.
The screenshot data is received but cannot be written as an image. The data value is base64 text, not raw PNG bytes. Base64-decode result.data before writing the bytes to a file, as in the Python example.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Keep protocol compatibility and capture behavior predictable

For repeatable automation, record the browser product and protocol version alongside the client version in your deployment notes. Test against the browser build that will run in production, and pin or update browser and client bindings deliberately rather than assuming tip-of-tree documentation matches every installed browser. The live /json/protocol response is the relevant check when a method’s availability is in question.

For a first successful capture, use one page target, the bare method or a minimal PNG request, and a fresh request ID. Only then add clipping or other capture settings. This isolates endpoint and compatibility faults from capture configuration. If you maintain a wrapper, ensure its generated command types reflect the browser revision you actually support; the Go CDP binding’s CaptureScreenshot() method is one example of a client abstraction over the command, but a wrapper still needs to communicate with a compatible endpoint.

Or skip the browser setup

If your goal is simply to obtain a website screenshot—not to debug a CDP integration—you can use ScreenshotNeo, a screenshot API and MCP server from Yorker Media. It avoids managing the browser WebSocket and target selection yourself.

One GET request returns an image or PDF; for example, save the response as WebP:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request details. Before capture, it accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be turned off. Bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and the response identifies page verdict and billing status in headers. An MCP server provides take_screenshot, get_page_info and capture_pdf tools for AI agents and MCP clients such as Claude and Cursor. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.

Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.

FAQ

Will retrying the same request usually fix a “wasn’t found” error?

A retry alone does not resolve a wrong target, unsupported command, mismatched client binding or malformed method. Recheck the endpoint, protocol and request before retrying.

Can I use a newer online CDP reference to decide what my installed browser supports?

Use the running browser’s /json/protocol for that decision. The online tip-of-tree protocol changes frequently and is not guaranteed to be backward-compatible with every browser build.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.