ScreenshotNeo

BlogHow-to

How to Schedule Recurring Website Screenshots with ScreenshotOne

ScreenshotOne does not document a built-in recurring schedule. Use cron or a workflow scheduler to call its API, save each result, and monitor failures.

By the ScreenshotNeo team4 October 20269 min read

Direct answer: ScreenshotOne renders screenshot requests, but its reviewed API documentation does not describe a native recurring schedule or cron setting. To take screenshots on a cadence, schedule a job outside ScreenshotOne—using cron, a cloud scheduler, or an automation workflow—that calls the /take endpoint each time. Save each result under a unique timestamped name if you need an archive.

This guide covers a runnable cron example, equivalent cURL, Python, and Node.js requests, asynchronous delivery, retention, batching, reliability, costs, and common failures. See the ScreenshotOne API documentation for request options and the async and webhook documentation for longer-running captures.

1. Choose a schedule and define what to capture

Start with the target URLs, cadence, output format, and retention period. Decide whether each capture should represent the visible viewport or the whole page, and whether dynamic content needs extra wait time. Keep a distinct output for each run when historical comparisons matter.

Question Decision
How often? Choose a cron expression or workflow schedule, such as once each weekday morning.
Which pages? Maintain a list of URLs; validate that the scheduled environment can reach them.
What format? Choose PNG, JPEG, or another supported output setting as required by your workflow.
How long to keep results? Use storage you control for an archive; do not rely on a temporary result URL as long-term storage.

For a set of URLs, estimate monthly captures as number of URLs × scheduled runs per month, then include room for retries and test runs. Spread large batches over time so a single scheduled burst does not exceed the current request-rate capacity.

2. Run a scheduled capture with cron

The following Python script requests one screenshot, checks for an HTTP error, and writes the image to a timestamped file. Set SCREENSHOTONE_ACCESS_KEY in the job environment; do not put the key directly in a committed script or crontab.

#!/usr/bin/env python3
import os
from datetime import datetime, timezone
from pathlib import Path

import requests

ACCESS_KEY = os.environ["SCREENSHOTONE_ACCESS_KEY"]
TARGET_URL = "https://example.com"
OUTPUT_DIR = Path("/var/lib/site-shots")
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)

stamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
response = requests.get(
    "https://api.screenshotone.com/take",
    params={
        "access_key": ACCESS_KEY,
        "url": TARGET_URL,
        "full_page": "true",
    },
    timeout=90,
)
response.raise_for_status()
output = OUTPUT_DIR / f"example-{stamp}.png"
output.write_bytes(response.content)
print(f"Saved {output}")

Install the dependency in the Python environment used by the scheduled job with python -m pip install requests. Run the script once manually, verify that the saved file opens, and confirm the job user can write to the output directory.

For example, a cron entry that runs every weekday at 08:00 UTC is:

0 8 * * 1-5 SCREENSHOTONE_ACCESS_KEY=your_key /usr/bin/python3 /opt/jobs/capture.py >> /var/log/site-shots.log 2>&1

Cron implementations vary in how they load environment variables and interpret time zones. Prefer your host’s secret or environment-variable facility for the access key, and set the scheduler’s timezone explicitly where available.

3. Send the API request directly

The API accepts GET and POST requests. GET is convenient for ordinary capture options; POST with JSON is suitable when sending large HTML or Markdown input. These examples make one synchronous request. Store the returned bytes as an image, and handle non-success status codes rather than treating every response body as an image.

cURL

export SCREENSHOTONE_ACCESS_KEY='your_key'
curl --fail --show-error --silent \
  --get 'https://api.screenshotone.com/take' \
  --data-urlencode "access_key=$SCREENSHOTONE_ACCESS_KEY" \
  --data-urlencode 'url=https://example.com' \
  --data-urlencode 'full_page=true' \
  --output screenshot.png

Python

import os
import requests

response = requests.get(
    "https://api.screenshotone.com/take",
    params={
        "access_key": os.environ["SCREENSHOTONE_ACCESS_KEY"],
        "url": "https://example.com",
        "full_page": "true",
    },
    timeout=90,
)
response.raise_for_status()
with open("screenshot.png", "wb") as image_file:
    image_file.write(response.content)

Node.js

import { writeFile } from "node:fs/promises";

const params = new URLSearchParams({
  access_key: process.env.SCREENSHOTONE_ACCESS_KEY,
  url: "https://example.com",
  full_page: "true",
});
const response = await fetch(`https://api.screenshotone.com/take?${params}`, {
  signal: AbortSignal.timeout(90_000),
});
if (!response.ok) {
  throw new Error(`ScreenshotOne returned HTTP ${response.status}: ${await response.text()}`);
}
await writeFile("screenshot.png", Buffer.from(await response.arrayBuffer()));

For POST requests, send JSON with the request options in the body and keep the access key in the documented location for that request form. Follow the current API docs for accepted parameters and response format. A scheduled workflow should avoid logging full request URLs if they contain an access key.

4. Schedule longer captures asynchronously

A synchronous request is simple when it finishes within the scheduler’s execution limit. For longer captures—or automation platforms with short limits—use async=true and a webhook_url. ScreenshotOne sends completion information to the webhook. Set webhook_errors=true if the workflow needs error details in webhook payloads or headers.

Webhook requests can be signed. In production, validate the X-ScreenshotOne-Signature using the secret signing key and HMAC SHA-256 before accepting the event. Make the receiver idempotent: a repeated completion notification should not create duplicate archive records or trigger duplicate downstream work. Consult the async mode documentation for the precise request and signature format.

5. Capture multiple URLs without overloading the job

For a small list, loop over URLs sequentially or put each capture in a queue. For larger groups, limit concurrency, record each URL’s result independently, and use bounded retries for transient failures. Avoid unbounded parallel requests: ScreenshotOne’s usage endpoint reports concurrency.remaining and concurrency.reset for the current one-minute request bucket.

ScreenshotOne describes /bulk as a wrapper around its regular endpoints, and its guide notes that a custom bulk solution may be preferable. Check the current bulk and usage documentation before selecting an approach for a large schedule. A queue is useful when captures vary in duration or when you need to retry one failed URL without repeating the whole batch.

6. Choose capture settings for consistent snapshots

  • Full page: Set full_page=true when the archive needs the full document. Full-page capture may not work on every site, so validate representative pages before relying on unattended runs.
  • Viewport: Set width and height consistently when comparing runs. A changed viewport can alter responsive layouts and make snapshots misleading.
  • Wait behavior: The documented default wait event is load, and the default delay is zero. If content appears late, use an appropriate wait_until option, wait for a selector, or add a delay. More waiting increases run time.
  • Output: Choose the format and quality options in the API docs according to the downstream use. Preserve the extension and content type consistently in your storage workflow.

Dynamic pages can still vary because their data changes between scheduled runs. If the goal is visual comparison, capture at a consistent time and viewport, and consider whether personalized or rotating content should be excluded from interpretation.

7. Save results for the retention period you need

A successful API response can be written directly to storage controlled by the scheduled job. Use a timestamp or run identifier in the object key so that a new capture does not overwrite history. For long-term retention, ScreenshotOne recommends compatible S3 storage. Its temporary screenshot URLs are documented as available for a maximum of four hours unless caching is configured with a longer TTL.

Store enough metadata to identify each image later: target URL, scheduled time, capture options, response outcome, and any retry or error status. Keep credentials out of filenames, logs, and public object metadata.

8. Monitor the schedule and make retries safe

  1. Record a run identifier, intended schedule time, target URL, and final outcome.
  2. Alert on missed runs and repeated failures, not just process crashes.
  3. Retry only errors likely to be transient, with a bounded attempt count and delay.
  4. Write each result atomically or use a temporary file followed by a rename so partial downloads are not mistaken for complete images.
  5. Make downstream delivery idempotent so a retry does not duplicate notifications or archive entries.

Check HTTP status codes and validate that the response is actually the expected image before declaring success. For asynchronous runs, monitor both job submission and webhook completion; submission alone does not mean the screenshot was delivered.

9. Estimate cost and capacity

First estimate monthly volume: URLs × runs per month, plus testing and likely retries. Then compare that total with the selected plan’s monthly quota and request-rate limit. A schedule that fires many captures at the same minute can hit a rate limit even when its monthly volume is low.

As of the pricing page snapshot accessed October 3, 2026, ScreenshotOne listed 100 free screenshots per month; Basic at $17 per month for 2,000 screenshots and 40 requests per minute; Growth at $79 per month for 10,000 and 80 requests per minute; and Scale at $259 per month for 50,000 and 150 requests per minute. The page says successful non-cached screenshots count toward quotas and lists plan-specific overage rates. Prices and limits can change, so verify the current pricing page before setting a budget.

10. Troubleshoot common failures

Symptom Likely cause Fix
Unauthorized or invalid-key response The key is missing, malformed, or unavailable in the scheduler environment. Check the secret configuration and confirm the job reads the intended environment variable. Do not print the key in logs.
Request times out The page or full-page capture takes longer than the caller allows, or the workflow has a strict execution limit. Increase the client timeout where possible; use async mode and a webhook for longer jobs.
Screenshot shows incomplete content Content loads after the default load event or needs client-side rendering time. Wait for a relevant selector or choose a suitable wait event or delay, then validate the result on the target page.
Full-page image is incomplete or fails The page’s layout or behavior is incompatible with full-page capture. Test the URL with and without full_page=true; use viewport captures if that meets the requirement.
Scheduler reports success but no archive file exists The process lacks write permission, the destination is wrong, or the response was not saved. Check the job user’s permissions, use an absolute destination path, and log the final output location.
Rate or concurrency limit reached Too many requests ran in the current request bucket. Queue work, reduce parallelism, stagger schedules, and consult usage values for remaining capacity and reset time.
Zapier task times out ScreenshotOne’s Zapier guide notes a 30-second execution limit. Use an asynchronous request and webhook where the workflow supports it.
Old screenshot URL no longer works Temporary URLs have limited availability. Copy the image into durable storage promptly, or configure caching with a suitable longer TTL.

11. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server from ScreenshotNeo. One GET request returns an image or PDF, with capture options for full pages, selectors, waits, custom CSS and JavaScript, and more. See the ScreenshotNeo API documentation.

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

Equivalent Python and Node.js requests:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

For a recurring schedule, call the same endpoint from your scheduler and save each response with a unique timestamp. ScreenshotNeo removes cookie banners, popups, and chat widgets before the shot; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000.

Sign up free for 1,000 screenshots a month, with no card required.

12. FAQ

Does ScreenshotOne run the recurring schedule?

The reviewed API docs describe rendering requests, not a native recurring scheduler. The cadence comes from the external scheduler or workflow that calls the API.

Can I keep every run as a historical snapshot?

Yes. Save each response to storage you control under a unique timestamp or run ID; do not use a temporary result URL as the archive.

Should I use a synchronous request or a webhook?

Use synchronous delivery when the capture reliably fits within the caller’s time limit. Use async mode and a webhook when runs may take longer or the automation platform has a short execution window.

How do I avoid capturing a page before it is ready?

Choose a wait condition that matches the page’s behavior, such as a selector that appears when the relevant content is ready, and verify it against real scheduled runs.

Sources