ScreenshotNeo

BlogHow-to

How to Save ApiFlash Screenshots to Amazon S3

Upload ApiFlash screenshots directly to Amazon S3 with a single API request. See runnable cURL, Python, and Node.js examples, options, and fixes for common errors.

By the ScreenshotNeo team4 October 20268 min read

ApiFlash can upload a screenshot directly to an Amazon S3 bucket. Call https://api.apiflash.com/v1/urltoimage with your ApiFlash access key, the page URL, and the destination parameters s3_access_key_id, s3_secret_key, s3_bucket, and s3_key. Set response_type=json if your application only needs the S3 result and does not need the screenshot bytes returned in the response. ApiFlash documents the endpoint and parameters.

What you need

  • An ApiFlash access key.
  • An S3 bucket and an object key, such as screenshots/example.png.
  • A target page URL that includes its scheme, such as https://example.com.
  • AWS credentials supplied to the request. Do not publish real credentials in source code, logs, browser code, or examples.

The ApiFlash documentation describes the credential fields used for its direct upload, but the reviewed material does not specify a least-privilege IAM policy or bucket-hardening configuration for this integration. Follow current AWS security guidance for your account and protect credentials in the architecture you choose.

Save a screenshot directly to S3

Use the following request shape, replacing every placeholder. The URL target must include https:// or http://. The endpoint accepts GET parameters or POST form data; these examples use GET.

curl -G "https://api.apiflash.com/v1/urltoimage" \
  --data-urlencode "access_key=YOUR_APIFLASH_ACCESS_KEY" \
  --data-urlencode "url=https://example.com" \
  --data-urlencode "response_type=json" \
  --data-urlencode "format=png" \
  --data-urlencode "s3_access_key_id=YOUR_AWS_ACCESS_KEY_ID" \
  --data-urlencode "s3_secret_key=YOUR_AWS_SECRET_ACCESS_KEY" \
  --data-urlencode "s3_bucket=YOUR_BUCKET" \
  --data-urlencode "s3_key=screenshots/example.png"

Use --data-urlencode for values such as the target URL so reserved characters are encoded correctly. With response_type=json, the endpoint returns a JSON response rather than transferring screenshot bytes to the caller. See the ApiFlash documentation for the documented response details.

Python

This example requires the requests package. Install it with python -m pip install requests. It checks the HTTP status and prints the JSON response.

import os
import requests

endpoint = "https://api.apiflash.com/v1/urltoimage"
params = {
    "access_key": os.environ["APIFLASH_ACCESS_KEY"],
    "url": "https://example.com",
    "response_type": "json",
    "format": "png",
    "s3_access_key_id": os.environ["AWS_ACCESS_KEY_ID"],
    "s3_secret_key": os.environ["AWS_SECRET_ACCESS_KEY"],
    "s3_bucket": os.environ["S3_BUCKET"],
    "s3_key": "screenshots/example.png",
}

response = requests.get(endpoint, params=params, timeout=90)
response.raise_for_status()
print(response.json())

Set the environment variables through your deployment platform’s secret manager or another protected configuration mechanism. Avoid printing the request URL: GET parameters contain credentials.

Node.js

This runnable example uses Node.js with built-in fetch (Node.js 18 or later). It reads credentials from environment variables and reports non-success responses.

const endpoint = new URL('https://api.apiflash.com/v1/urltoimage');
const params = {
  access_key: process.env.APIFLASH_ACCESS_KEY,
  url: 'https://example.com',
  response_type: 'json',
  format: 'png',
  s3_access_key_id: process.env.AWS_ACCESS_KEY_ID,
  s3_secret_key: process.env.AWS_SECRET_ACCESS_KEY,
  s3_bucket: process.env.S3_BUCKET,
  s3_key: 'screenshots/example.png',
};

for (const [key, value] of Object.entries(params)) {
  if (!value) throw new Error(`Missing required environment variable or value: ${key}`);
  endpoint.searchParams.set(key, value);
}

const response = await fetch(endpoint, { signal: AbortSignal.timeout(90_000) });
const body = await response.text();
if (!response.ok) {
  throw new Error(`ApiFlash returned HTTP ${response.status}: ${body}`);
}
console.log(body);

As in the Python example, avoid logging the full endpoint URL because its query string includes secrets.

Options and request behavior

Parameter or behavior How to use it
access_key Your ApiFlash API key.
url The complete page address, including protocol. Encode it when constructing a GET request manually.
s3_access_key_id, s3_secret_key The AWS credential fields ApiFlash documents for the upload.
s3_bucket The destination bucket name.
s3_key The destination object key, including any desired path and filename.
response_type=json Use when the caller needs the API result but does not need image bytes in its HTTP response. The default response is image bytes with content headers.
format Choose jpeg, png, or webp. The documented default is jpeg. Match the key’s extension to the selected format for clarity.
s3_endpoint Set this for a custom S3-compatible storage endpoint. Leaving it empty uses AWS S3.
s3_region An optional region setting that may be needed with a compatible provider.

ApiFlash accepts GET or POST form data. POST can help keep request fields out of the URL in parts of your own application, but the request still carries secrets to the service. Use HTTPS and ensure any HTTP client, proxy, and application logs avoid recording credential-bearing requests.

Choose a response and object key

If the screenshot is only needed from S3, request response_type=json; this avoids returning the image bytes in the API response. If your application also needs the image bytes, use the default image response and process those bytes separately. The direct S3 parameters are still the mechanism for the bucket upload.

Choose an object key that is deterministic when you want a stable location, or include an application-generated identifier when each capture should have its own object. The documentation establishes the s3_key destination field but does not describe overwrite, versioning, or collision behavior; decide how your application handles repeated keys and verify bucket behavior for your setup.

Custom S3-compatible storage

For a compatible storage service, add its endpoint using s3_endpoint. The docs also describe s3_region as an optional setting that may be required by a provider. For example, add these fields to the cURL command:

  --data-urlencode "s3_endpoint=YOUR_S3_COMPATIBLE_ENDPOINT" \
  --data-urlencode "s3_region=YOUR_PROVIDER_REGION"

Use the endpoint and region values supplied by your storage provider. Do not assume every provider accepts AWS defaults.

Quota, cache, and rate limits

  • ApiFlash documents a screenshot cache TTL default of 86,400 seconds (one day) and a maximum of 2,592,000 seconds (30 days). Identical successful requests may be served from cache and do not count against monthly quota, according to its documentation.
  • The documented processing rate is 20 requests per second with a burst size of 400. Excess requests are delayed until the burst limit is exceeded; additional requests can receive 429.
  • ApiFlash documents throttling repeated identical failed captures to five per hour. Avoid rapid retries of the same failing capture.
  • Inspect X-Quota-Limit, X-Quota-Remaining, and X-Quota-Reset response headers, or use the documented /v1/urltoimage/quota endpoint to check quota.

For throughput-sensitive jobs, queue requests, respect rate-limit responses, and use bounded retries with backoff. A timeout at your client does not prove the remote capture or upload did not finish; before retrying, consider whether repeating the same object key could cause an unwanted duplicate or replacement.

Common errors and fixes

Status Documented meaning What to check
400 Invalid parameters or target cannot be captured. Check parameter names, required S3 fields, URL scheme and encoding, and whether the page is reachable for capture.
401 ApiFlash key is invalid or revoked. Check the configured ApiFlash key and replace a revoked or incorrect key.
402 Monthly quota exceeded. Inspect quota headers or the quota endpoint, then wait for reset or review the account plan.
403 The plan does not support a requested feature. Check whether the requested option is supported on the current plan.
429 Rate limit exceeded. Reduce concurrency, queue the work, and retry with backoff after the limit permits.
500 Capture failure in ApiFlash. Check that the target is available and retry later with a bounded retry policy. Repeated identical failures may be throttled.

Also check S3 destination spelling, the selected provider endpoint and region, and that your credentials are current. The listed API statuses do not establish a precise diagnosis for every storage-side rejection, so inspect the response body and your AWS or provider-side records without exposing secrets.

Performance, reliability, and cost

Direct upload keeps your application from having to receive and forward screenshot bytes when JSON response mode meets your needs. It also makes the screenshot service responsible for the S3 upload step, so your application should handle API errors, timeouts, quota limits, and retries deliberately. If your application needs to inspect or transform the bytes before storage, receiving the image response and uploading it in your own service is another architecture, with additional code and credential handling to operate.

ApiFlash’s product page currently lists S3 export on its Free, Lite, Medium, and Large plan cards, showing 100, 1,000, 10,000, and 100,000 screenshots per month at $0, $7, $35, and $180 per month respectively. These displayed plan details can change; verify the current plan page before purchasing. The documented cache behavior can affect quota consumption for identical successful requests. The reviewed sources do not quantify performance or cost differences between direct export and application-mediated upload.

Security checklist

  • Keep ApiFlash and AWS credentials in protected server-side configuration, not public browser code or a checked-in file.
  • Use HTTPS and avoid logging full GET URLs or request objects that contain credentials.
  • Review current AWS guidance for access scope, key rotation, and bucket access controls; the reviewed ApiFlash docs do not provide an integration-specific least-privilege policy.
  • Use a predictable object-key strategy and decide how repeated captures should be handled.
  • Do not put live credentials in examples, issue reports, or screenshots of logs.

Or skip the browser setup

ScreenshotNeo is a website screenshot API with a single GET request. Its API accepts a URL and returns PNG, JPEG, WebP, or PDF; 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

ScreenshotNeo removes cookie banners, popups, and chat widgets before the screenshot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents use the take_screenshot, get_page_info, and capture_pdf tools. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.

Start free with 1,000 screenshots a month and no card.

FAQ

Can ApiFlash upload directly to my S3 bucket?

Yes. Supply the documented S3 credential, bucket, and object-key parameters on the URL-to-image request.

Can I use POST instead of GET?

Yes. ApiFlash documents both GET parameters and POST form data.

Do I need to download the screenshot from the API first?

No. Direct S3 upload is documented. Use response_type=json when you do not need screenshot bytes in the response.

Can I use a non-AWS S3-compatible provider?

The documentation provides s3_endpoint for a custom compatible endpoint and an optional s3_region setting.

Which image formats can I save?

The documented formats are JPEG, PNG, and WebP; JPEG is the default.