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

  1. Screenshots of Authenticated Pages
  2. Full-Page Screenshots
  3. Capturing Specific Elements
  4. Generating PDFs
  5. Dark Mode Screenshots
  6. Cleaning Up Content
  7. Animated Screenshots & Video
  8. Webhooks & Async Mode
  9. Signed URLs
  10. Extracting Metadata
  11. 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.

bash
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.png

Using an Authorization header

For APIs and SPAs that use Bearer tokens or Basic Auth:

bash
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.png

Using custom headers

Some services use non-standard headers for authentication:

bash
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.png

Tips for authenticated screenshots

  • Use wait_until: ["networkidle2"] to ensure all AJAX requests complete after authentication
  • Add delay: 2 to 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

bash
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.png

Full 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.

bash
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.png

Protecting against infinite scroll

Some pages (feeds, timelines) scroll indefinitely. Set a maximum height to prevent extremely large images:

bash
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.png
Page Typefull_page_scroll_delayfull_page_scroll_byfull_page_max_height
Static blog post200viewport height--
Image-heavy portfolio80040020000
Social media feed60050010000
SPA dashboard400viewport height--

3. Capturing Specific Elements

Use the selector parameter to capture a single HTML element instead of the full page.

Basic element capture

bash
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.png
Note: URL-encode the # character as %23 when 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:

bash
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.png

Handling 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:

bash
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.png

Strict 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:

bash
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.png

Choosing the right algorithm

AlgorithmWhen to Use
defaultMost cases -- uses the browser's native element bounding box
clipWhen 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

bash
curl "https://api.nodium.io/api/v1/screenshot/take?access_key=YOUR_API_KEY&url=https://example.com&format=pdf" -o document.pdf

This combination produces the best results for most pages:

bash
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.pdf
  • media_type=screen -- Renders the page as it appears on screen (not the print stylesheet)
  • pdf_print_background=true -- Includes background colors and images
  • pdf_fit_one_page=true -- Scales everything to fit on one page

Multi-page PDF with margins

bash
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.pdf

PDF from raw HTML (invoices, receipts)

bash
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.pdf

Paper format reference

FormatSize (mm)Common Use
a4210 x 297Standard international
letter216 x 279US standard
legal216 x 356US legal documents
tabloid279 x 432Large format
a3297 x 420Posters, diagrams
a5148 x 210Booklets

5. Dark Mode Screenshots

Capture websites in dark mode, or create responsive comparison sets.

Force dark mode

bash
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.png

Force light mode

bash
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.png

Responsive dark mode comparison

Capture the same page across multiple devices and color schemes using bulk:

bash
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:

bash
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.png
Note: 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

bash
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.png

Hide specific elements

bash
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.png

Block specific third-party requests

bash
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.png

Block resource types for faster loading

Blocking fonts and media can significantly speed up capture:

bash
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.png

Custom CSS override

Use styles for fine-grained visual control:

bash
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.png

7. 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:

bash
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.gif

Scroll animation as MP4

bash
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.mp4

Scroll to a specific section then stop

bash
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.mp4

Static page recording

Record a page without scrolling, useful for capturing CSS animations or live content:

bash
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.mp4
bash
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.mp4

GIF for social media

Use social media device presets for optimal dimensions:

bash
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.gif

8. 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 > 30 seconds
  • When you want to offload processing from your server

Basic async with webhook

bash
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):

json
{
  "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.

javascript
// 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:

python
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

  1. Collect all query parameters (excluding signature), sort them alphabetically
  2. Build a canonical query string: key1=value1&key2=value2&...
  3. Compute HMAC-SHA256 of the canonical string using your signing key
  4. Append the hex-encoded signature as the signature parameter

Example: generating a signed URL in Node.js

javascript
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

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.

bash
# 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

bash
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:

json
{
  "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:

bash
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):

json
{
  "metadata": {
    "fonts": [
      "Inter",
      "system-ui",
      "Fira Code",
      "Georgia"
    ]
  }
}

HTTP response inspection

Check the target site's HTTP status and headers:

bash
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:

bash
# 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:

json
{
  "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:

bash
# 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.md

11. 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

bash
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:

json
{
  "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

bash
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

bash
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 CategoryExample 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.