ScreenshotNeo

BlogHow-to

How to Automate Website Screenshot Captures with CloudConvert API

Build a CloudConvert API job that captures a website, exports the image, and handles completion, temporary URLs, retries, and common errors.

By the ScreenshotNeo team4 October 20269 min read

Use CloudConvert API v2 to automate a website screenshot by creating a job with a capture-website task, then an export/url task. Submit the job to POST https://api.cloudconvert.com/v2/jobs with a server-side Bearer API key. When the job completes, retrieve the exported file URL and download the result before that temporary URL expires.

This guide shows the documented job shape and practical integration patterns. Confirm exact capture parameters for the desired output in the current CloudConvert capture operation reference or Job Builder; the minimal example below has not been executed as part of this guide.

1. Create an API key and protect it

  1. Create a CloudConvert API key and grant only the task and job permissions your integration needs. CloudConvert documents Bearer authentication and scoped keys in its API introduction.
  2. Store the key in a server-side secret manager or environment configuration. Do not put it in browser JavaScript, a mobile app bundle, or a public repository.
  3. Use the generic API base https://api.cloudconvert.com/v2, or choose a documented regional endpoint when your data-location requirements call for it. CloudConvert documents Germany (eu-central) and Virginia, USA (us-east) endpoints; confirm current requirements for your deployment.

API keys do not expire unless revoked, according to CloudConvert’s API introduction. Treat them as long-lived credentials: limit scope, restrict access, and rotate them under your security policy.

2. Submit a capture job with cURL

A CloudConvert job groups tasks. The capture task renders the URL as an image, and the export task makes the result available as a downloadable URL.

curl --request POST \
  --url https://api.cloudconvert.com/v2/jobs \
  --header "Authorization: Bearer $CLOUDCONVERT_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "tasks": {
      "capture-site": {
        "operation": "capture-website",
        "url": "https://example.com",
        "output_format": "png"
      },
      "export-image": {
        "operation": "export/url",
        "input": "capture-site"
      }
    }
  }'

The operation documentation describes PDF, PNG, and JPG website capture. The output format is required. The example uses PNG; choose jpg or pdf when suitable and verify format-specific parameters in the current operation reference. The job response includes the job and task information; retain the job ID for status checks.

3. Poll job status when you need a synchronous flow

For a simple script or low-volume workflow, create the job, retrieve its status, and download the export URL after the export task finishes. CloudConvert’s quickstart documents synchronous status retrieval as an alternative to webhooks.

The following Python example uses the documented job structure and checks task status. Set the API key in the environment. The endpoint paths and response fields should be checked against the current API reference when implementing a production client.

import os
import time
import requests

API_KEY = os.environ["CLOUDCONVERT_API_KEY"]
BASE = "https://api.cloudconvert.com/v2"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}
payload = {
    "tasks": {
        "capture-site": {
            "operation": "capture-website",
            "url": "https://example.com",
            "output_format": "png",
        },
        "export-image": {
            "operation": "export/url",
            "input": "capture-site",
        },
    }
}

created = requests.post(f"{BASE}/jobs", headers=headers, json=payload, timeout=30)
created.raise_for_status()
job_id = created.json()["data"]["id"]

deadline = time.monotonic() + 15 * 60
while time.monotonic() < deadline:
    response = requests.get(f"{BASE}/jobs/{job_id}", headers=headers, timeout=30)
    response.raise_for_status()
    job = response.json()["data"]
    status = job["status"]

    if status == "finished":
        tasks = job.get("tasks", [])
        export_task = next(t for t in tasks if t.get("name") == "export-image")
        file_url = export_task["result"]["files"][0]["url"]
        image = requests.get(file_url, timeout=90)
        image.raise_for_status()
        with open("screenshot.png", "wb") as output:
            output.write(image.content)
        print("Saved screenshot.png")
        break

    if status == "error":
        raise RuntimeError(f"CloudConvert job failed: {job}")

    time.sleep(3)
else:
    raise TimeoutError(f"Job {job_id} did not finish before the client deadline")

CloudConvert’s quickstart says export URLs are valid for 24 hours. Download the file promptly or export it to durable storage if it must be retained longer. The client-side 15-minute deadline above is an example policy, not a CloudConvert service limit.

4. Use Node.js for an application worker

This example uses Node.js 18 or later, where fetch is available without an extra package. It submits the same job and shows a synchronous status loop. The API key stays on the server.

const apiKey = process.env.CLOUDCONVERT_API_KEY;
if (!apiKey) throw new Error("Set CLOUDCONVERT_API_KEY");

const base = "https://api.cloudconvert.com/v2";
const headers = {
  Authorization: `Bearer ${apiKey}`,
  "Content-Type": "application/json",
};

const payload = {
  tasks: {
    "capture-site": {
      operation: "capture-website",
      url: "https://example.com",
      output_format: "png",
    },
    "export-image": {
      operation: "export/url",
      input: "capture-site",
    },
  },
};

async function requestJson(url, options = {}) {
  const response = await fetch(url, { ...options, headers: { ...headers, ...options.headers } });
  if (!response.ok) {
    const body = await response.text();
    throw new Error(`HTTP ${response.status}: ${body}`);
  }
  return response.json();
}

const created = await requestJson(`${base}/jobs`, {
  method: "POST",
  body: JSON.stringify(payload),
});
const jobId = created.data.id;
const deadline = Date.now() + 15 * 60 * 1000;

while (Date.now() < deadline) {
  const result = await requestJson(`${base}/jobs/${jobId}`);
  const job = result.data;

  if (job.status === "finished") {
    const exportTask = job.tasks.find((task) => task.name === "export-image");
    const fileUrl = exportTask.result.files[0].url;
    const fileResponse = await fetch(fileUrl);
    if (!fileResponse.ok) throw new Error(`File download failed: HTTP ${fileResponse.status}`);
    const bytes = new Uint8Array(await fileResponse.arrayBuffer());
    await import("node:fs/promises").then(({ writeFile }) => writeFile("screenshot.png", bytes));
    console.log("Saved screenshot.png");
    break;
  }

  if (job.status === "error") throw new Error(`CloudConvert job failed: ${JSON.stringify(job)}`);
  await new Promise((resolve) => setTimeout(resolve, 3000));
}

if (Date.now() >= deadline) throw new Error(`Job ${jobId} exceeded the client deadline`);

For production, add bounded retries for transient network failures and HTTP 429 responses. Respect the Retry-After header when present, and avoid retrying a job-creation request blindly if you cannot determine whether the first request created a job.

5. Prefer webhooks for recurring automation

Polling is straightforward, but a webhook avoids repeatedly checking jobs that are still running. CloudConvert recommends webhooks for completion handling in its quickstart. A typical flow is:

  1. Submit the job and record its job ID in your database.
  2. Configure a completion webhook using the current API’s webhook options.
  3. When notified, verify the webhook according to CloudConvert’s current webhook guidance, then fetch the job/task details if needed.
  4. Read the export task’s file URL and copy the file to your storage or process it immediately.
  5. Make the handler idempotent so a repeated notification cannot duplicate downstream work.

Use the current webhook documentation for event names, signature validation, and configuration fields; those details are not specified in the research material used for this guide. Keep a recovery path that can query job status if a notification is delayed or your endpoint is unavailable.

6. Choose capture settings for the page

The screenshot product page describes full-page capture as the default and presents viewport width, zoom, selector waiting, authorization headers for protected resources, and synchronous or asynchronous processing. It demonstrates a width of 1440 and wait_for_element: "body". Since parameters can differ by output format, use the current Job Builder or operation reference to confirm each option name and supported combination.

Need Configuration to investigate Practical note
Capture a page that loads content later Wait for a CSS selector, a delay, or the documented readiness condition Wait for a meaningful content element where possible; a fixed delay can waste time or still be too short.
Control image dimensions Viewport width and height, zoom, or full-page mode Set dimensions intentionally for consistent layout. Check whether the chosen output format supports the desired settings.
Capture a protected page Authorization or other request headers Keep credentials private and limit access. The product page describes protected-resource authorization headers.
Save a document view PDF output Check page and rendering options in the current operation reference.
Reduce image size JPG output instead of PNG Choose based on whether smaller files or lossless detail matters more; compare your own outputs.

CloudConvert’s capture task documents a default timeout of five hours. This is a task timeout ceiling/default, not a recommended target duration. Set your own application deadline and surface a useful failure state well before an unattended worker waits indefinitely.

7. Handle errors, retries, and failed captures

Symptom Likely cause Fix
HTTP 401 or 403 Missing, invalid, or insufficiently scoped API key Check the Bearer header and grant the minimum job/task permissions required.
HTTP 400 when creating a job Invalid task structure, unsupported option, missing URL, or output format Check the operation reference and Job Builder for the exact parameter names and format requirements.
HTTP 429 Dynamic API rate limit Wait for the Retry-After duration when supplied, then retry with bounded exponential backoff and jitter.
Job ends in error The page may fail to load, require unavailable authentication, time out, or reject automated access Inspect task/job error details, verify the URL is reachable from the service, confirm required headers, and test an authorized page with fewer options.
Screenshot misses dynamic content Capture occurred before client-side rendering finished Use a selector wait or a suitable wait condition. Avoid excessively long fixed delays.
Export URL no longer works The temporary URL has passed its 24-hour validity window Download on completion and move the file to durable storage promptly.
Worker creates duplicate jobs after a timeout The client lost the response after CloudConvert accepted the request Persist returned job IDs, track submission state, and reconcile uncertain submissions before resending.

Retry transient transport errors and rate limits; do not retry permanent authorization or invalid-parameter errors unchanged. The documentation reviewed does not establish behavior for every site’s CAPTCHA, consent flow, robots policy, or anti-bot controls. Capture only pages you are authorized to access and diagnose such cases against the site’s requirements.

8. Performance, reliability, and cost

  • Latency: A capture requires a remote browser render and can take longer when a page loads slowly or waits for late content. The five-hour task timeout is not a latency target. Use an application deadline, bounded concurrency, and job monitoring.
  • Reliability: Webhooks reduce polling traffic, while status retrieval provides a recovery mechanism. Make completion handling idempotent and retain job IDs and error details for diagnosis.
  • Storage: Export URLs are temporary for 24 hours according to the quickstart. Copy important results to durable object storage or another system you control.
  • Rate limits: CloudConvert documents dynamic rate limits and may return 429 with Retry-After. Throttle job creation and honor that header.
  • Cost: CloudConvert’s website screenshot page advertises a starting price of $0.008 per file. This is a vendor-published starting price, not a guaranteed quote; check the current plan, usage, and configuration before estimating production cost.

9. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server for developers. A single GET request can return a PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation for request options.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Cookie banners are accepted like a visitor, and 60+ known consent platforms, newsletter popups, and chat widgets are removed before capture; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots.

Sign up for ScreenshotNeo and get 1,000 free screenshots a month with no card.

10. Frequently asked questions

Can I use CloudConvert to create a PDF instead of an image?

Yes. The capture operation documents PDF, PNG, and JPG use cases. Set the requested output format and verify any format-specific options in the current reference.

Can I capture a page that requires authentication?

The screenshot product page describes authorization headers for protected resources. Confirm the supported parameter and pass secrets only from a protected server-side integration.

Should I use a webhook or polling?

Use webhooks for recurring workflows where you can expose a reliable callback endpoint. Polling can be simpler for a small script, provided it uses a deadline and sensible interval.

Can I use an SDK instead of raw HTTP?

CloudConvert lists official SDKs for PHP, Node.js, Python, Ruby, Java, and .NET. The API overview also lists integrations such as Zapier, Power Automate, Make, and n8n.

How long can I rely on the exported file URL?

The quickstart documents a 24-hour validity window. Treat it as temporary and copy files you need to keep into durable storage.