Screenshots (PNG / JPEG)
The screenshot endpoints capture a publicly accessible webpage or raw HTML markup as a PNG or JPEG image, through the same asynchronous pipeline as the PDF endpoints: submit a job, poll its status, download the image. One screenshot costs one render unit plus its bytes ā the same monthly quotas and the same per-file limits as PDFs apply (150 MB per file, 24-hour retention, 3 download attempts, 1 active stream). Available on every plan.
Endpoint: POST /url-to-image
POST https://api.pdfik.net/url-to-image
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Yes | The public URL of the page to capture. Local/internal IPs are blocked. |
webhook_url | string | No | Optional callback URL where the job outcome payload will be POSTed. Credentials must not be embedded in the URL (https://user:pass@host is rejected) ā configure delivery headers in the dashboard instead. |
options | object | No | Image output options: format, full_page, quality, viewport. See Image Options. |
render | object | No | Timeout and wait selectors for browser load states (Pro+ plans only). See Browser Options. |
auth | object | No | Authorization settings for pages requiring login credentials (Pro+ plans only). Same type/value contract as on /url-to-pdf: basic ('username:password') or bearer (token). |
delivery | object | No | Upload the finished image straight to your own bucket via a presigned PUT URL (Pro+ plans only). See Delivery to Your Own Bucket. |
test | boolean | No | Run the job in test mode: full pipeline, no real render, the bundled sample PNG is returned. Quotas are not debited. Defaults to false. |
Endpoint: POST /html-to-image
POST https://api.pdfik.net/html-to-image
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
html | string | Yes | The raw HTML markup to capture. Sanitized with the same allowlist as /html-to-pdf: <script>, <style>, <iframe> and similar elements are removed together with their content; styling works via inline style="ā¦" attributes. For full pages with stylesheets, host them and use /url-to-image. |
webhook_url | string | No | Optional callback URL where the job outcome payload will be POSTed. Credentials must not be embedded in the URL (https://user:pass@host is rejected) ā configure delivery headers in the dashboard instead. |
options | object | No | Image output options: format, full_page, quality, viewport. See Image Options. |
render | object | No | Timeout and wait selectors for browser load states (Pro+ plans only). See Browser Options. |
delivery | object | No | Upload the finished image straight to your own bucket via a presigned PUT URL (Pro+ plans only). See Delivery to Your Own Bucket. |
test | boolean | No | Run the job in test mode: full pipeline, no real render, the bundled sample PNG is returned. Quotas are not debited. Defaults to false. |
Image Options (options)
| Parameter | Type | Default | Description |
|---|---|---|---|
format | string | "png" | Output image format: "png" or "jpeg" ("jpg" is accepted as an alias for "jpeg"). |
full_page | boolean | false | Capture the whole scrollable page instead of just the visible area. See Page height. |
quality | integer | ā | JPEG quality, 1-100. JPEG only ā sending quality with format: "png" is rejected with 422 before anything is charged. |
viewport | object | 1024x768 | The browser window the page is opened in: {"width": ā¦, "height": ā¦} in CSS pixels, width 320-1920 and height 320-8192. Outside that range the request is rejected with 422. The viewport sets the image width; with full_page: false (the default) it also sets the image height. |
You choose the size
There is no scaling, fitting or guessing anywhere in this endpoint. We open the page in exactly the window you ask for and capture it, so the output size is something you decide, not something you discover. With the defaults that is a flat 1024x768 image ā a tablet-sized window, enough for a preview or a social card without asking our renderers for a full page every time.
If you want a desktop shot, ask for a desktop window: {"width": 1920, "height": 1080}.
If you want a phone shot, ask for a phone: {"width": 390, "height": 844}. The page
itself decides how it responds to that window, exactly as it would in a real browser.
Page height
With full_page: true the image height follows the real page, and is clipped at
8,192 px. That is a ceiling, not a target: a page that is 2,000 px long gives a
2,000 px image, not a padded 8,192 px one. A page longer than the ceiling is cut off
there ā the job still finishes done with the top of the page. Content that overflows
horizontally, beyond the viewport width, is never captured.
For pages longer than the ceiling, capture them in parts with full_page: false, or
render them with /url-to-pdf, which has no such limit.
The capture itself must finish within 60 seconds, independently of
render.page_load_timeout_ms; a capture that takes longer fails the job with
PAGE_TIMEOUT and is not retried. Use
full_page: false or a smaller viewport for very long or heavy pages.
{
"url": "https://example.com",
"options": {
"format": "jpeg",
"quality": 80,
"full_page": true,
"viewport": { "width": 1920, "height": 1080 }
}
}
Delivery to Your Own Bucket (delivery)
Add a delivery object (mode, url) to have the finished image uploaded straight to
your own storage via a presigned PUT URL ā nothing is stored on PDFik's side: once the
job is done, the job.finished webhook reports the outcome only (no file_url, no
expires_at ā we never record where the file went), and the download endpoint answers
404.
Pro and Business plans. The URL must use https on the standard port 443 (any other
port is rejected with 422). The full rules (URL requirements, expiry, retries, error
behavior) are documented in
Delivery to Your Own Bucket; it
cannot be combined with test mode.
Request Headers
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your API key (sk_live_...). |
Idempotency-Key | No | 1-255 characters from A-Z a-z 0-9 _ - . :. Retrying a request with the same key returns the original job instead of creating (and billing) a duplicate. Recommended for retry-after-timeout logic. |
The Asynchronous Flow
- Submit Job: Post the URL or HTML to
/url-to-imageor/html-to-image. You'll receive ajob_idand a status ofqueued. - Poll Status: Send
GETrequests to/jobs/{job_id}untilstatusisdone(orfailed). - Download File: Send a request to
/jobs/{job_id}/downloadto stream the image binary directly. The responseContent-Typeisimage/pngorimage/jpeg(matching the requestedformat), with the filename{job_id}.pngor{job_id}.jpg. The file is available for 24 hours after generation (the exact moment is theexpires_atfield in the status response); at most 3 download attempts and 1 active stream are allowed per file. See File Retention & Downloads.
Test Mode
Test mode ("test": true) works on both screenshot endpoints: the job runs
through the real pipeline without rendering, and the download returns the bundled
sample PNG ā for both requested formats (a jpeg test job is also served the PNG
sample). Test jobs are free ā they consume no PDF or data-volume quota ā and are
rate-limited separately. See Testing.
Integration Examples
1. Basic Request (curl)
curl -X POST https://api.pdfik.net/url-to-image \
-H "X-API-Key: sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"options": { "format": "png", "full_page": true }
}'
Response (202 Accepted):
{
"job_id": "8bfa5cc3-09ef-436f-80d4-a0eb867123aa",
"status": "queued",
"detail": "Job successfully sent to processing queue."
}
2. JavaScript (ES6 Fetch)
const API_KEY = 'sk_live_YOUR_KEY';
async function captureScreenshot(url) {
// 1. Submit the URL to start the screenshot job
const submitRes = await fetch('https://api.pdfik.net/url-to-image', {
method: 'POST',
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
url,
options: { format: 'jpeg', quality: 80 }
})
});
if (!submitRes.ok) throw new Error(`Failed to submit job: ${submitRes.statusText}`);
const { job_id } = await submitRes.json();
// 2. Poll the job status endpoint until it completes or fails
let status = 'queued';
while (status !== 'done' && status !== 'failed') {
await new Promise(resolve => setTimeout(resolve, 2000));
const statusRes = await fetch(`https://api.pdfik.net/jobs/${job_id}`, {
headers: { 'X-API-Key': API_KEY }
});
if (statusRes.status === 429) continue; // rate limited: wait and poll again
if (!statusRes.ok) throw new Error(`Status check failed: ${statusRes.status} ${await statusRes.text()}`);
status = (await statusRes.json()).status;
}
if (status === 'failed') throw new Error('Screenshot job failed');
// 3. Download the image (Content-Type: image/jpeg here)
const downloadRes = await fetch(`https://api.pdfik.net/jobs/${job_id}/download`, {
headers: { 'X-API-Key': API_KEY }
});
if (!downloadRes.ok) throw new Error(`Download failed: ${downloadRes.status} ${await downloadRes.text()}`);
return await downloadRes.arrayBuffer(); // returns image binary buffer
}
3. Python (httpx)
import time
import httpx
API_KEY = "sk_live_YOUR_KEY"
BASE_URL = "https://api.pdfik.net"
HEADERS = {"X-API-Key": API_KEY}
def html_to_image(html: str, output_path: str = "output.png") -> None:
with httpx.Client(base_url=BASE_URL, headers=HEADERS) as client:
# 1. Submit
submit = client.post("/html-to-image", json={
"html": html,
"options": {"format": "png", "viewport": {"width": 1280, "height": 720}},
})
submit.raise_for_status()
job_id = submit.json()["job_id"]
# 2. Poll
status = "queued"
while status not in ("done", "failed"):
time.sleep(2)
r = client.get(f"/jobs/{job_id}")
if r.status_code == 429: # rate limited: wait and poll again
continue
r.raise_for_status()
status = r.json()["status"]
if status == "failed":
raise RuntimeError("Screenshot job failed")
# 3. Download
with open(output_path, "wb") as f:
with client.stream("GET", f"/jobs/{job_id}/download") as response:
response.raise_for_status()
for chunk in response.iter_bytes():
f.write(chunk)
html_to_image('<h1 style="color: #1e3a8a;">Hello</h1>')
SDKs and CLI
The official clients cover both endpoints: urlToImage / htmlToImage in the
JavaScript and Java SDKs,
url_to_image / html_to_image in the Python SDK, and
pdfik url-to-image <url> / pdfik html-to-image <file.html | -> in the
CLI.