Nodium Screenshot API -- Practical Guides
Step-by-step guides for common screenshot scenarios. Each guide includes working cURL examples and best practices.
Table of Contents
- Screenshots of Authenticated Pages
- Full-Page Screenshots
- Capturing Specific Elements
- Generating PDFs
- Dark Mode Screenshots
- Cleaning Up Content
- Animated Screenshots & Video
- Webhooks & Async Mode
- Signed URLs
- Extracting Metadata
- OpenAI Vision Integration
1. Screenshots of Authenticated Pages
Many applications require login to access dashboards, admin panels, or user-specific content. Nodium supports multiple authentication methods.
Using cookies
Pass session cookies to authenticate as a logged-in user. Extract cookies from your browser's DevTools (Application > Cookies) or from your authentication API response.
curl -X POST "https://api.nodium.io/api/v1/screenshot/take" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://app.example.com/dashboard",
"format": "png",
"cookies": [
"session_id=abc123def456; Domain=app.example.com; Path=/; Secure; HttpOnly",
"user_pref=dark; Domain=app.example.com; Path=/"
],
"wait_until": ["networkidle2"],
"delay": 2
}' -o dashboard.pngUsing an Authorization header
For APIs and SPAs that use Bearer tokens or Basic Auth:
curl -X POST "https://api.nodium.io/api/v1/screenshot/take" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://app.example.com/dashboard",
"format": "png",
"authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}' -o dashboard.pngUsing custom headers
Some services use non-standard headers for authentication:
curl -X POST "https://api.nodium.io/api/v1/screenshot/take" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://internal.example.com/report",
"format": "png",
"headers": [
"X-API-Token:my-internal-token-123",
"X-Org-ID:org_456"
]
}' -o report.pngTips for authenticated screenshots
- Use
wait_until: ["networkidle2"]to ensure all AJAX requests complete after authentication - Add
delay: 2to give SPAs time to render after login redirects - Use
fail_if_content_contains: ["Login", "Sign in"]to detect authentication failures - If the page uses CSP that blocks injected scripts, add
bypass_csp: true
2. Full-Page Screenshots
Capture the entire scrollable content of a page, not just the visible viewport.
Basic full-page capture
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=YOUR_API_KEY&url=https://example.com&format=png&full_page=true" -o fullpage.pngFull page with lazy-loading support
Modern websites lazy-load images and content as you scroll. The full_page_scroll parameter physically scrolls the page to trigger these elements.
curl -X POST "https://api.nodium.io/api/v1/screenshot/take" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/blog",
"format": "png",
"full_page": true,
"full_page_scroll": true,
"full_page_scroll_delay": 800,
"full_page_scroll_by": 500,
"wait_until": ["networkidle2"]
}' -o fullpage-lazy.pngProtecting against infinite scroll
Some pages (feeds, timelines) scroll indefinitely. Set a maximum height to prevent extremely large images:
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=YOUR_API_KEY&url=https://news.example.com/feed&format=png&full_page=true&full_page_scroll=true&full_page_max_height=15000" -o capped.pngRecommended settings by page type
| Page Type | full_page_scroll_delay | full_page_scroll_by | full_page_max_height |
|---|---|---|---|
| Static blog post | 200 | viewport height | -- |
| Image-heavy portfolio | 800 | 400 | 20000 |
| Social media feed | 600 | 500 | 10000 |
| SPA dashboard | 400 | viewport height | -- |
3. Capturing Specific Elements
Use the selector parameter to capture a single HTML element instead of the full page.
Basic element capture
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=YOUR_API_KEY&url=https://example.com&format=png&selector=%23hero-section" -o hero.pngNote: URL-encode the#character as%23when using query parameters.
Capturing elements in Shadow DOM
Some web components use Shadow DOM to encapsulate their markup. Prefix the selector with shadow/ to traverse shadow boundaries:
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=YOUR_API_KEY&url=https://example.com&format=png&selector=shadow/.pricing-card" -o shadow-element.pngHandling elements that need scrolling
If the target element is below the fold, selector_scroll_into_view (enabled by default) scrolls to it first. This also triggers lazy-loading:
curl -X POST "https://api.nodium.io/api/v1/screenshot/take" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/pricing",
"format": "png",
"selector": ".pricing-table",
"selector_scroll_into_view": true,
"wait_until": ["networkidle2"],
"delay": 1
}' -o pricing.pngStrict mode -- fail if element not found
By default, the API captures the full page if the selector is not found. Enable strict mode to get an error instead:
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=YOUR_API_KEY&url=https://example.com&format=png&selector=.dynamic-chart&error_on_selector_not_found=true&wait_for_selector=.dynamic-chart" -o chart.pngChoosing the right algorithm
| Algorithm | When to Use |
|---|---|
default | Most cases -- uses the browser's native element bounding box |
clip | When the element is partially hidden by overflow, position, or z-index |
4. Generating PDFs
Convert any web page into a well-formatted PDF document.
Basic PDF generation
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=YOUR_API_KEY&url=https://example.com&format=pdf" -o document.pdfRecommended settings for professional PDFs
This combination produces the best results for most pages:
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=YOUR_API_KEY&url=https://example.com&format=pdf&media_type=screen&pdf_print_background=true&pdf_fit_one_page=true" -o professional.pdfmedia_type=screen-- Renders the page as it appears on screen (not the print stylesheet)pdf_print_background=true-- Includes background colors and imagespdf_fit_one_page=true-- Scales everything to fit on one page
Multi-page PDF with margins
curl -X POST "https://api.nodium.io/api/v1/screenshot/take" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/report",
"format": "pdf",
"pdf_print_background": true,
"pdf_paper_format": "a4",
"pdf_margin_top": "20mm",
"pdf_margin_right": "15mm",
"pdf_margin_bottom": "20mm",
"pdf_margin_left": "15mm"
}' -o report.pdfPDF from raw HTML (invoices, receipts)
curl -X POST "https://api.nodium.io/api/v1/screenshot/take" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"html": "<html><body style=\"font-family:Arial;padding:40px\"><h1>Invoice #1234</h1><p>Amount: $99.00</p><p>Date: 2026-03-05</p></body></html>",
"format": "pdf",
"pdf_print_background": true,
"pdf_paper_format": "letter",
"pdf_margin": "20mm"
}' -o invoice.pdfPaper format reference
| Format | Size (mm) | Common Use |
|---|---|---|
a4 | 210 x 297 | Standard international |
letter | 216 x 279 | US standard |
legal | 216 x 356 | US legal documents |
tabloid | 279 x 432 | Large format |
a3 | 297 x 420 | Posters, diagrams |
a5 | 148 x 210 | Booklets |
5. Dark Mode Screenshots
Capture websites in dark mode, or create responsive comparison sets.
Force dark mode
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=YOUR_API_KEY&url=https://example.com&format=png&dark_mode=true" -o dark.pngForce light mode
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=YOUR_API_KEY&url=https://example.com&format=png&dark_mode=false" -o light.pngResponsive dark mode comparison
Capture the same page across multiple devices and color schemes using bulk:
curl -X POST "https://api.nodium.io/api/v1/screenshot/bulk" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"execute": true,
"options": {
"url": "https://example.com",
"format": "png",
"block_ads": true,
"block_cookie_banners": true
},
"requests": [
{ "viewport_device": "desktop_1080p", "dark_mode": false },
{ "viewport_device": "desktop_1080p", "dark_mode": true },
{ "viewport_device": "iphone_16_pro", "dark_mode": false },
{ "viewport_device": "iphone_16_pro", "dark_mode": true }
]
}'Transparent background with dark mode
For embedding screenshots on dark backgrounds:
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=YOUR_API_KEY&url=https://example.com&format=png&dark_mode=true&omit_background=true" -o dark-transparent.pngNote: omit_background=true only works with formats that support transparency: PNG, WebP, and MOV (video).
6. Cleaning Up Content
Remove ads, cookie banners, chat widgets, and other distractions to get clean screenshots.
One-command cleanup
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=YOUR_API_KEY&url=https://news-site.com/article&format=png&block_ads=true&block_cookie_banners=true&block_chats=true&block_trackers=true" -o clean.pngHide specific elements
curl -X POST "https://api.nodium.io/api/v1/screenshot/take" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"format": "png",
"hide_selectors": [
".newsletter-popup",
"#cookie-consent",
".sticky-header",
"[data-testid=promo-banner]"
]
}' -o hidden.pngBlock specific third-party requests
curl -X POST "https://api.nodium.io/api/v1/screenshot/take" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"format": "png",
"block_requests": [
"*google-analytics.com*",
"*facebook.net*",
"*hotjar.com*",
"*intercom.io*"
]
}' -o blocked.pngBlock resource types for faster loading
Blocking fonts and media can significantly speed up capture:
curl -X POST "https://api.nodium.io/api/v1/screenshot/take" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"format": "png",
"block_resources": ["font", "media"]
}' -o fast.pngCustom CSS override
Use styles for fine-grained visual control:
curl -X POST "https://api.nodium.io/api/v1/screenshot/take" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"format": "png",
"styles": ".popup, .modal-backdrop, .overlay { display: none !important; } body { overflow: visible !important; }"
}' -o styled.png7. Animated Screenshots & Video
Record scroll animations, page interactions, or static recordings as video or GIF.
Scroll animation as GIF
Perfect for social media, README files, and product demos:
curl "https://api.nodium.io/api/v1/screenshot/animate?access_key=YOUR_API_KEY&url=https://example.com&format=gif&scenario=scroll&duration=8" -o scroll.gifScroll animation as MP4
curl -X POST "https://api.nodium.io/api/v1/screenshot/animate" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"format": "mp4",
"scenario": "scroll",
"duration": 12,
"scroll_by": 600,
"scroll_duration": 2000,
"scroll_back": true,
"scroll_easing": "ease_in_out_cubic",
"block_ads": true,
"block_cookie_banners": true
}' -o demo.mp4Scroll to a specific section then stop
curl -X POST "https://api.nodium.io/api/v1/screenshot/animate" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"format": "mp4",
"scenario": "scroll",
"duration": 10,
"scroll_till_selector": "#pricing",
"scroll_easing": "ease_in_out_quint"
}' -o to-pricing.mp4Static page recording
Record a page without scrolling, useful for capturing CSS animations or live content:
curl "https://api.nodium.io/api/v1/screenshot/animate?access_key=YOUR_API_KEY&url=https://example.com&format=mp4&scenario=default&duration=5" -o static-recording.mp4Navigate to another page during recording
curl -X POST "https://api.nodium.io/api/v1/screenshot/animate" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"format": "mp4",
"scenario": "scroll",
"duration": 15,
"scroll_try_navigate": true,
"scroll_navigate_after": 7000,
"scroll_navigate_to_url": "https://example.com/pricing"
}' -o navigate.mp4GIF for social media
Use social media device presets for optimal dimensions:
curl -X POST "https://api.nodium.io/api/v1/screenshot/animate" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"format": "gif",
"scenario": "scroll",
"duration": 6,
"viewport_device": "social_twitter_post",
"scroll_easing": "ease_in_out_cubic"
}' -o twitter-preview.gif8. Webhooks & Async Mode
Use async mode for long-running operations and receive results via webhooks.
When to use async mode
- Pages that take more than 60 seconds to fully load
- Bulk processing where you do not need results immediately
- Operations with
delay > 30seconds - When you want to offload processing from your server
Basic async with webhook
curl -X POST "https://api.nodium.io/api/v1/screenshot/take" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://heavy-spa.example.com",
"format": "png",
"async": true,
"timeout": 120,
"webhook_url": "https://your-server.com/webhooks/screenshot",
"webhook_sign": true,
"webhook_errors": true,
"external_identifier": "report-2026-03-05"
}'Immediate response (202 Accepted):
{
"status": "accepted",
"trace_id": "abc123-def456"
}Handling the webhook
When the screenshot is ready, Nodium sends a POST request to your webhook_url with the screenshot binary as the body and metadata in the headers.
// Express.js webhook handler
const crypto = require("crypto");
app.post("/webhooks/screenshot", (req, res) => {
// 1. Verify the signature
const signature = req.headers["x-nodium-signature"];
const expectedSignature = crypto
.createHmac("sha256", process.env.NODIUM_SIGNING_KEY)
.update(req.rawBody)
.digest("hex");
if (signature !== expectedSignature) {
return res.status(401).send("Invalid signature");
}
// 2. Check for errors
const errorCode = req.headers["x-nodium-error-code"];
if (errorCode) {
console.error(
`Screenshot failed: ${errorCode} - ${req.headers["x-nodium-error-message"]}`
);
return res.status(200).send("Error acknowledged");
}
// 3. Process the screenshot
const externalId = req.headers["x-nodium-external-identifier"];
const renderingTime = req.headers["x-nodium-rendering-seconds"];
const sizeBytes = req.headers["x-nodium-size-bytes"];
console.log(
`Screenshot ${externalId} ready: ${sizeBytes} bytes in ${renderingTime}s`
);
// Save the screenshot (req.body contains the binary data)
fs.writeFileSync(`screenshots/${externalId}.png`, req.body);
res.status(200).send("OK");
});Webhook signature verification
When webhook_sign=true (the default), the body is signed with HMAC-SHA256 using your signing key. Always verify the signature before processing the webhook payload:
import hmac
import hashlib
def verify_webhook(body: bytes, signature: str, signing_key: str) -> bool:
expected = hmac.new(
signing_key.encode(),
body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)9. Signed URLs
Signed URLs let you expose screenshot URLs publicly (e.g. in <img> tags) without revealing your API key.
How signing works
- Collect all query parameters (excluding
signature), sort them alphabetically - Build a canonical query string:
key1=value1&key2=value2&... - Compute HMAC-SHA256 of the canonical string using your signing key
- Append the hex-encoded signature as the
signatureparameter
Example: generating a signed URL in Node.js
const crypto = require("crypto");
function generateSignedUrl(accessKey, signingKey, params) {
const baseUrl = "https://api.nodium.io/api/v1/screenshot/take";
// Add access_key to params
const allParams = { access_key: accessKey, ...params };
// Sort parameters alphabetically
const sortedKeys = Object.keys(allParams).sort();
const canonical = sortedKeys
.map((k) => `${k}=${encodeURIComponent(allParams[k])}`)
.join("&");
// Sign
const signature = crypto
.createHmac("sha256", signingKey)
.update(canonical)
.digest("hex");
return `${baseUrl}?${canonical}&signature=${signature}`;
}
// Usage
const url = generateSignedUrl("YOUR_API_KEY", "YOUR_SIGNING_KEY", {
url: "https://example.com",
format: "png",
viewport_width: "1280",
});
console.log(url);
// Safe to embed in HTML: <img src="..." />Example: generating a signed URL in Python
import hmac
import hashlib
from urllib.parse import urlencode
def generate_signed_url(access_key: str, signing_key: str, params: dict) -> str:
base_url = "https://api.nodium.io/api/v1/screenshot/take"
all_params = {"access_key": access_key, **params}
canonical = urlencode(sorted(all_params.items()))
signature = hmac.new(
signing_key.encode(),
canonical.encode(),
hashlib.sha256,
).hexdigest()
return f"{base_url}?{canonical}&signature={signature}"
url = generate_signed_url("YOUR_API_KEY", "YOUR_SIGNING_KEY", {
"url": "https://example.com",
"format": "png",
"viewport_width": "1280",
})
print(url)Enforcing signed URLs
In the Nodium Dashboard under Settings > Signed URLs, you can enable enforcement. When active, all requests without a valid signature are rejected with signature_is_required (HTTP 400).
This is recommended for production to prevent unauthorized use of your API key.
# This works when enforcement is enabled
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=KEY&url=https://example.com&format=png&signature=a1b2c3d4e5f6..."
# This fails when enforcement is enabled
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=KEY&url=https://example.com&format=png"
# Error: {"error_code": "signature_is_required", ...}10. Extracting Metadata
Extract structured information from web pages alongside or instead of screenshots.
Open Graph and page title
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=YOUR_API_KEY&url=https://github.com&format=png&response_type=json&metadata_page_title=true&metadata_open_graph=true&metadata_icon=true"Response:
{
"screenshot_url": "https://cdn.nodium.io/screenshots/abc.png",
"metadata": {
"page_title": "GitHub: Let's build from here",
"open_graph": {
"title": "GitHub: Let's build from here",
"description": "GitHub is where over 100 million developers shape the future of software...",
"image": "https://github.githubassets.com/assets/social-share.png",
"url": "https://github.com/",
"type": "website",
"site_name": "GitHub"
},
"icon": {
"url": "https://github.githubassets.com/favicons/favicon.svg",
"type": "image/svg+xml"
}
}
}Font detection
Discover all fonts used on a page:
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=YOUR_API_KEY&url=https://example.com&format=png&response_type=json&metadata_fonts=true"Response (partial):
{
"metadata": {
"fonts": [
"Inter",
"system-ui",
"Fira Code",
"Georgia"
]
}
}HTTP response inspection
Check the target site's HTTP status and headers:
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=YOUR_API_KEY&url=https://example.com&format=png&response_type=json&metadata_http_response_status_code=true&metadata_http_response_headers=true"Content extraction
Extract the full page content as HTML or Markdown:
# Extract as Markdown
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=YOUR_API_KEY&url=https://example.com/blog/post&format=png&response_type=json&metadata_content=true&metadata_content_format=markdown"Response:
{
"content": {
"url": "https://cdn.nodium.io/content/abc123.md",
"expires": "2026-03-06T12:00:00Z"
}
}The content URL is temporary and can be fetched to retrieve the extracted content.
Direct content output
Instead of extracting metadata alongside a screenshot, you can use format=html or format=markdown to get the content directly:
# Get rendered HTML
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=YOUR_API_KEY&url=https://example.com&format=html" -o page.html
# Get Markdown
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=YOUR_API_KEY&url=https://example.com&format=markdown" -o page.md11. OpenAI Vision Integration
Analyze screenshots with GPT Vision in a single API call. The screenshot is captured and sent to OpenAI Vision in one step.
Describing page layout
curl -X POST "https://api.nodium.io/api/v1/screenshot/take" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"format": "png",
"response_type": "json",
"openai_api_key": "sk-proj-...",
"vision_prompt": "Describe the visual layout of this web page. List the main sections and their approximate positions.",
"vision_max_tokens": 500
}'Response:
{
"screenshot_url": "https://cdn.nodium.io/screenshots/abc.png",
"vision": {
"completion": "The page has a top navigation bar with logo on the left and menu items on the right. Below that is a hero section with a large heading, subheading, and two CTA buttons..."
}
}Extracting structured data
curl -X POST "https://api.nodium.io/api/v1/screenshot/take" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/pricing",
"format": "png",
"response_type": "json",
"openai_api_key": "sk-proj-...",
"vision_prompt": "Extract all pricing plans from this page. For each plan, provide: name, price, billing period, and list of features. Return as JSON.",
"vision_max_tokens": 1000
}'Visual QA testing
curl -X POST "https://api.nodium.io/api/v1/screenshot/take" \
-H "X-Access-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://staging.example.com",
"format": "png",
"response_type": "json",
"openai_api_key": "sk-proj-...",
"vision_prompt": "Check this web page for visual issues: overlapping elements, broken layouts, text overflow, missing images, or alignment problems. Report any issues found.",
"vision_max_tokens": 500
}'Use cases
| Prompt Category | Example Prompt |
|---|---|
| Layout analysis | "Describe the page layout and navigation structure." |
| Data extraction | "Extract the product name, price, and rating from this page as JSON." |
| Accessibility check | "Identify potential accessibility issues: contrast, text size, missing alt text." |
| Competitive analysis | "What are the main value propositions communicated on this landing page?" |
| QA testing | "Compare this page against standard e-commerce best practices. List issues." |
| Design to code | "Generate HTML/CSS that reproduces this page layout." |
Important: Your OpenAI API key is passed directly to OpenAI and is never stored by Nodium. You are billed by OpenAI for Vision API usage.