How to Capture Website Screenshots with Scrnify's API (JavaScript/Node.js Guide)

3/7/2025

Hey there! Laura and Heidi here from SCRNIFY! 👋

Ever needed to automatically capture high-quality screenshots of websites for your projects? Maybe you're building a monitoring dashboard, creating visual documentation, or generating social media previews? We've been there too—wrestling with headless browsers, handling deployment complexities, and dealing with all the quirks of browser automation.

That's exactly why we built SCRNIFY, a developer-friendly screenshot API service that handles all the complicated browser management for you! In this guide, we'll show you exactly how to integrate Scrnify's screenshot capabilities into your JavaScript and Node.js applications.

Let's get those screenshots flowing! 📸

Get free access to the SCRNIFY API during our open beta!

Prerequisites

Before diving into the code, make sure you have:

  • Node.js installed (we recommend v18 or higher since it includes the Fetch API)
  • A Scrnify API key (sign up here to get one for free during our beta)
  • Basic knowledge of JavaScript and async/await (we'll be using these throughout)

Installation & Setup

Unlike some screenshot services, SCRNIFY doesn't require any special packages or SDKs. You can use the standard Fetch API that's built into Node.js (v18+) or any HTTP client of your choice. For this tutorial, we'll show examples using both the native Fetch API and Axios (a popular HTTP client).

If you prefer using Axios, install it with:

npm install axios

Taking Your First Screenshot

Let's start with the basics! Here's how to capture a simple screenshot of a website:

const fs = require('fs');

// Replace with your actual API key
const API_KEY = 'YOUR_API_KEY';
const baseUrl = 'https://api.scrnify.com/capture';

async function captureBasicScreenshot() {
    try {
        // Set up the parameters
        const params = new URLSearchParams({
            key: API_KEY,
            url: 'https://example.com', // The URL to capture
            type: 'image',              // Capturing an image (not a video)
            format: 'png',              // Output format (png, jpeg, gif)
            width: '1920',              // Viewport width
            height: '1080'              // Viewport height
        });

        // Construct the full URL
        const requestUrl = `${baseUrl}?${params.toString()}`;

        console.log(`🚀 Capturing screenshot of example.com...`);

        // Make the API request
        const response = await fetch(requestUrl);

        // Check if the request was successful
        if (!response.ok) {
            throw new Error(`API error: ${response.status} ${response.statusText}`);
        }

        // Get the response as an array buffer
        const arrayBuffer = await response.arrayBuffer();
        const buffer = Buffer.from(arrayBuffer);

        // Save the image to a file
        fs.writeFileSync('screenshot.png', buffer);

        console.log(`✅ Screenshot saved to screenshot.png`);
    } catch (error) {
        console.error(`❌ Error capturing screenshot:`, error);
    }
}

captureBasicScreenshot();

What's happening here?

  1. We're setting up the request parameters using URLSearchParams to ensure proper encoding
  2. The core parameters (url, type, format, width, height) define what we want to capture
  3. We make a request to the Scrnify API endpoint with our parameters
  4. We receive the image data as a response and save it to a file

When you run this script, you'll get a 1920×1080 PNG screenshot of example.com saved as screenshot.png in your current directory!

Capturing Full-Page Screenshots

Want to capture the entire webpage, not just what's visible in the viewport? That's where the fullPage parameter comes in:

const params = new URLSearchParams({
    key: API_KEY,
    url: 'https://example.com',
    type: 'image',
    format: 'png',
    width: '1920',       // Width still matters for full-page screenshots
    fullPage: 'true'     // This is the magic parameter!
});

When you set fullPage to true, Scrnify will scroll through the entire page and capture everything, from the top all the way to the bottom. The height parameter is ignored in this case, since the height is determined by the page content.

This is perfect for capturing long pages like blog posts, documentation, or any content that extends below the fold!

Different Image Formats & Quality Settings

Scrnify supports multiple image formats, each with its own advantages:

JPEG (with quality control)

const params = new URLSearchParams({
    key: API_KEY,
    url: 'https://example.com',
    type: 'image',
    format: 'jpeg',      // Using JPEG format
    width: '1920',
    height: '1080',
    quality: '80'        // JPEG quality (1-100)
});

The quality parameter lets you control the compression level for JPEG images. Lower values mean smaller file sizes but reduced image quality. Higher values preserve more details but result in larger files.

PNG (lossless)

const params = new URLSearchParams({
    key: API_KEY,
    url: 'https://example.com',
    type: 'image',
    format: 'png',       // Using PNG format (lossless)
    width: '1920',
    height: '1080'
});

PNG is a lossless format, which means it maintains perfect image quality but typically creates larger files than JPEG.

GIF

const params = new URLSearchParams({
    key: API_KEY,
    url: 'https://example.com',
    type: 'image',
    format: 'gif',       // Using GIF format
    width: '1920',
    height: '1080'
});

While GIF is often used for animations, Scrnify also supports it for static screenshots.

Custom Viewport Sizes

One of the most powerful features of Scrnify's API is the ability to capture screenshots at any viewport size. This is perfect for testing responsive designs or generating screenshots for different devices:

Mobile View

const params = new URLSearchParams({
    key: API_KEY,
    url: 'https://example.com',
    type: 'image',
    format: 'png',
    width: '375',        // iPhone SE width
    height: '667',       // iPhone SE height
    userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'  // Mobile user agent
});

Tablet View

const params = new URLSearchParams({
    key: API_KEY,
    url: 'https://example.com',
    type: 'image',
    format: 'png',
    width: '768',        // iPad width
    height: '1024'       // iPad height
});

Ultrawide Desktop

const params = new URLSearchParams({
    key: API_KEY,
    url: 'https://example.com',
    type: 'image',
    format: 'png',
    width: '3440',       // Ultrawide monitor width
    height: '1440'       // Ultrawide monitor height
});

Using Axios Instead of Fetch

If you prefer Axios over the native Fetch API, here's how to accomplish the same basic screenshot with Axios:

const axios = require('axios');
const fs = require('fs');

// Replace with your actual API key
const API_KEY = 'YOUR_API_KEY';
const baseUrl = 'https://api.scrnify.com/capture';

async function captureScreenshotWithAxios() {
    try {
        // Set up the parameters
        const params = {
            key: API_KEY,
            url: 'https://example.com',
            type: 'image',
            format: 'png',
            width: '1920',
            height: '1080'
        };

        console.log(`🚀 Capturing screenshot with Axios...`);

        // Make the API request with responseType: 'arraybuffer'
        const response = await axios.get(baseUrl, {
            params: params,
            responseType: 'arraybuffer'  // Important for binary data like images
        });

        // Save the image to a file
        fs.writeFileSync('axios-screenshot.png', response.data);

        console.log(`✅ Screenshot saved to axios-screenshot.png`);
    } catch (error) {
        if (error.response) {
            console.error(`❌ API error: ${error.response.status}`);
        } else {
            console.error(`❌ Error capturing screenshot:`, error.message);
        }
    }
}

captureScreenshotWithAxios();

The key difference here is setting responseType: 'arraybuffer' in the Axios request options, which ensures the image data is properly handled.

Advanced Features: Wait Conditions

Sometimes you need to wait for specific events to occur before taking a screenshot, especially for dynamic content. Scrnify offers the waitUntil parameter to control exactly when a screenshot is taken:

const params = new URLSearchParams({
    key: API_KEY,
    url: 'https://example.com',
    type: 'image',
    format: 'png',
    width: '1920',
    height: '1080',
    waitUntil: 'networkIdle'  // Wait until network is idle
});

Available options for waitUntil include:

  • firstMeaningfulPaint (default): When the primary content is visible
  • DOMContentLoaded: When the HTML is loaded and parsed
  • load: When all resources (images, stylesheets) are loaded
  • networkIdle: When there are no active network connections for at least 500ms

Choose the option that best matches your needs—for content-heavy sites, networkIdle might be best, while firstMeaningfulPaint offers faster captures for simple pages.

Error Handling

When working with external APIs, proper error handling is crucial. Here's a more robust error handling example:

async function captureScreenshotWithErrorHandling() {
    try {
        // Set up parameters as before...

        const response = await fetch(requestUrl);

        // Check for different error scenarios
        if (response.status === 400) {
            throw new Error('Bad request: Check your parameters');
        } else if (response.status === 401) {
            throw new Error('Authentication error: Invalid API key');
        } else if (response.status === 403) {
            throw new Error('Forbidden: You lack permission for this request');
        } else if (response.status === 404) {
            throw new Error('Target URL not found');
        } else if (response.status === 500) {
            throw new Error('Server error: Please try again later');
        } else if (!response.ok) {
            throw new Error(`API error: ${response.status} ${response.statusText}`);
        }

        // Process successful response...
    } catch (error) {
        console.error(`❌ Error capturing screenshot:`, error.message);

        // You might want to retry or implement fallback behavior here
        if (error.message.includes('API key')) {
            console.log('💡 Tip: Check if your API key is correct and active');
        } else if (error.message.includes('URL not found')) {
            console.log('💡 Tip: Verify the target URL is accessible and properly formatted');
        }
    }
}

By handling different HTTP status codes, you can provide more specific error messages and implement appropriate recovery strategies.

Example Project: Screenshot Multiple URLs

Let's put everything together in a practical example—capturing screenshots from multiple websites and saving them to a folder:

const fs = require('fs');
const path = require('path');

// Replace with your actual API key
const API_KEY = 'YOUR_API_KEY';
const baseUrl = 'https://api.scrnify.com/capture';

// List of websites to capture
const websites = [
    { url: 'https://example.com', name: 'example' },
    { url: 'https://github.com', name: 'github' },
    { url: 'https://news.ycombinator.com', name: 'hackernews' }
];

// Create output directory if it doesn't exist
const outputDir = 'screenshots';
if (!fs.existsSync(outputDir)) {
    fs.mkdirSync(outputDir);
    console.log(`📁 Created output directory: ${outputDir}`);
}

async function captureWebsite(website) {
    try {
        const params = new URLSearchParams({
            key: API_KEY,
            url: website.url,
            type: 'image',
            format: 'png',
            width: '1920',
            height: '1080',
            waitUntil: 'networkIdle'
        });

        console.log(`🚀 Capturing ${website.name}...`);

        const response = await fetch(`${baseUrl}?${params.toString()}`);

        if (!response.ok) {
            throw new Error(`API error: ${response.status} ${response.statusText}`);
        }

        const arrayBuffer = await response.arrayBuffer();
        const buffer = Buffer.from(arrayBuffer);

        const outputPath = path.join(outputDir, `${website.name}.png`);
        fs.writeFileSync(outputPath, buffer);

        console.log(`✅ Saved ${website.name} to ${outputPath}`);
        return { success: true, name: website.name };
    } catch (error) {
        console.error(`❌ Error capturing ${website.name}:`, error.message);
        return { success: false, name: website.name, error: error.message };
    }
}

async function captureAllWebsites() {
    console.log(`📸 Starting batch screenshot job for ${websites.length} websites...`);

    // Use Promise.all to capture all websites in parallel
    const results = await Promise.all(websites.map(captureWebsite));

    // Report results
    const successful = results.filter(r => r.success).length;
    const failed = results.filter(r => !r.success).length;

    console.log('\n📊 Screenshot job completed:');
    console.log(`✅ Successful: ${successful}`);
    console.log(`❌ Failed: ${failed}`);

    if (failed > 0) {
        console.log('\nFailed websites:');
        results.filter(r => !r.success)
               .forEach(r => console.log(`- ${r.name}: ${r.error}`));
    }
}

captureAllWebsites().catch(console.error);

This script:

  1. Takes screenshots of multiple websites in parallel
  2. Saves them to a dedicated folder
  3. Provides a summary report of successful and failed attempts

This is just the beginning! You could extend this script to:

  • Add retry logic for failed attempts
  • Implement a queue system to control concurrency
  • Save metadata along with each screenshot
  • Create a CSV or JSON report with timestamps and results

Security Best Practices: Using Signed API Keys

For production environments, we strongly recommend using Scrnify's signed API keys for enhanced security. Here's how to implement them:

const crypto = require('crypto');

// Replace with your actual API credentials
const API_KEY = 'YOUR_API_KEY';
const API_SECRET = 'YOUR_API_SECRET';
const baseUrl = 'https://api.scrnify.com/capture';

function generateSignature(queryString, secret) {
    const hmac = crypto.createHmac('sha256', secret);
    hmac.update(queryString);
    return hmac.digest('hex');
}

async function captureScreenshotWithSignedKey() {
    try {
        // Create the parameters without the signature
        const params = new URLSearchParams({
            key: API_KEY,
            url: 'https://example.com',
            type: 'image',
            format: 'png',
            width: '1920',
            height: '1080',
            cache_ttl: '3600'  // Required for signed keys
        });

        // Generate the signature based on these parameters
        const signature = generateSignature(params.toString(), API_SECRET);

        // Add the signature to the parameters
        params.append('signature', signature);

        // Make the request with the signed parameters
        const requestUrl = `${baseUrl}?${params.toString()}`;
        const response = await fetch(requestUrl);

        // Process response as before...
    } catch (error) {
        console.error(`❌ Error:`, error);
    }
}

Using signed API keys gives you an extra layer of security by ensuring requests can't be tampered with, and the cache_ttl parameter helps optimize performance by controlling how long screenshots are cached.

Conclusion

Congratulations! You've learned how to:

  • Take basic screenshots with Scrnify's API
  • Capture full-page screenshots
  • Use different image formats and quality settings
  • Set custom viewport sizes
  • Handle errors properly
  • Build a practical multi-site screenshot tool
  • Implement security best practices with signed API keys

Scrnify makes screenshot capture simple, letting you focus on building great features instead of wrestling with headless browsers and server configurations. The pay-as-you-go model means you're only charged for what you actually use—no subscriptions or upfront commitments.

Get free access to the SCRNIFY API during our open beta and start generating screenshots today! Sign up at scrnify.com

Want to learn more? Check out our complete API documentation or explore our other tutorials on browser automation.

Have questions, suggestions, or cool projects you're building with Scrnify? We'd love to hear from you! Reach out on Twitter or GitHub.

Cheers, Laura & Heidi 🇦🇹

P.S. Keep an eye out for our next tutorial on video captures with Scrnify—turning static screenshots into dynamic recordings! 📹

Ready to Get Started?

Sign up now and start capturing stunning screenshots in minutes.

Sign Up Now