Get 50% off your first month on any monthly plan.

How to Build Your Own Wayback Machine Using ScreenshotAPI

Profile

Written By Hanzala Saleem

Updated At July 31, 2026 | 12 min read

To archive a website, you capture a snapshot of each page and store it with a timestamp so you can revisit that exact version later. The fastest way to build this yourself is to schedule automated screenshots through a screenshot API, save each image to storage, and log the capture in a small database. This guide shows you how to do that in Node.js in under an hour.

The Internet Archive's Wayback Machine already does this at web scale. You build your own when you need control: private archives, specific pages captured on your schedule, visual evidence for compliance, or before-and-after records of client sites. ScreenshotAPI handles the browser rendering so you only write the scheduling, storage, and viewer layers. By the end of this guide you will have a working archiving system and a clear view of when a screenshot archive is the right tool and when it is not.

What You Are Building

A self-hosted wayback machine is a small system that captures timestamped snapshots of web pages on a schedule and lets you browse past versions. In this build, a screenshot API renders each page in a real browser and returns an image, a scheduler triggers captures daily or weekly, a database records every snapshot, and a lightweight web viewer displays the timeline. It captures the visual state of a page, not its underlying HTML, which makes it ideal for brand monitoring, compliance evidence, and design history.

What Is a Wayback Machine and Why Build One?

Before we dive into the technical details, let's understand what we're building. A wayback machine is essentially a web archive that captures and stores snapshots of websites over time. Think of it as a digital time capsule for the internet.

Why would you want to build your own?

  • Brand Monitoring: Track how your competitors' websites evolve over time.
  • Legal Documentation: Preserve evidence of web content for compliance or legal purposes.
  • Historical Research: Document the evolution of web design and content in your industry.
  • Personal Archive: Save important web pages before they disappear.
  • Client Reporting: Show clients the progress and changes made to their sites.

Why Choose ScreenshotAPI.net for Website Archiving?

While creating a website archiving system, you need a reliable screenshot API that can handle multiple challenges. Here's why ScreenshotAPI.net stands out:

Reliable Rendering: The API uses real browsers to capture screenshots, ensuring you get pixel-perfect representations exactly as users see them, including proper fonts and layout.

Flexible Capture Options: You can capture full page screenshots, specific sections, or viewports at different screen sizes, which is useful for archiving both desktop and mobile versions. The service handles long pages and entire page capture automatically.

Scalability: Whether you're archiving ten websites or ten thousand, the API scales with your needs and supports developers with comprehensive documentation.

Screenshot Archiving vs HTML and WARC Archiving

Before you build, it helps to know what a screenshot archive does and does not preserve. A screenshot captures the rendered pixels of a page: exactly what a visitor saw, including fonts, layout, images, and cookie or promo banners. It does not capture the underlying HTML, links, or interactive elements. Tools like ArchiveBox and the WARC format used by the Internet Archive store the full page code so you can click links and replay the page later.

That difference decides which approach fits your goal. Choose screenshot archiving when the visual record is the point: proving what an ad or price page displayed on a given date, tracking a competitor redesign, or showing a client the before and after of a rebuild. Choose HTML or WARC archiving when you need the page to remain browsable and its links to work.

Many teams run both. They use a full HTML archiver for browsable copies and a screenshot archive for tamper-evident visual proof. The build in this guide covers the screenshot side, which is the faster half to stand up and the harder half to fake.

Before settling on a stack, it's worth taking time to compare the main Wayback Machine alternatives, since each one optimizes for a different priority. ArchiveBox is a self-hosted, open-source option that saves HTML, screenshots, and PDFs together, making it a strong fit for teams that want full control and privacy over their archive. Conifer (Webrecorder) excels at interactive, JavaScript-heavy pages because it produces high-fidelity WARC captures that replay almost exactly like the original site. Archive.today is popular for quick, single-page snapshots, especially when a team only needs a one-off proof-of-record without setting up bulk automation. Browsertrix Crawler suits teams that need large-scale, scheduled crawling across many domains, offering more enterprise-level automation than the others. The right choice ultimately depends on whether an agency needs browsable, clickable copies of competitor pages or simply wants tamper-evident, date-stamped visual proof.

How Building Your Own Compares to Existing Tools

ApproachWhat it capturesBest forSetup effortOngoing cost
Build your own with ScreenshotAPIFull page screenshots (PNG, JPEG, PDF) with timestampsPrivate visual archives, compliance evidence, client reportingLow, a few hours in Node.jsAPI usage plus your storage
ArchiveBox (self-hosted)HTML, screenshots, PDF, and WARCBrowsable offline copies of many URLsMedium, Docker and server upkeepServer and storage you maintain
Internet Archive Save Page NowPublic HTML snapshot in the Wayback MachinePublic preservation of a single pageNone, paste a URLFree, but public and not on your schedule
Managed screenshot archivingScheduled screenshots stored for youTeams that want archiving without codeNone to lowSubscription per plan

Building your own sits between a full HTML archiver and a paste-a-URL public service. You get private, scheduled, visual snapshots you control, without running a crawler or a heavy server.

Understanding the Core Concept

ScreenshotAPI real-browser render Capture Engine scheduled captures cron scheduler Storage disk or S3 + database Retrieval Viewer browse timeline Capture on a schedule, store with a timestamp, retrieve any past version.

Building a wayback machine involves three main components:

  1. Capture Engine: Takes screenshots of websites at scheduled intervals
  2. Storage System: Organizes and stores the captured images with timestamps, locally or in a cloud bucket
  3. Retrieval Interface: Allows you to browse and compare archived versions

ScreenshotAPI handles the browser rendering, while you build the scheduling, storage, and interface around it. If you would rather send captures straight to your own cloud bucket instead of managing files on disk, the storage integration lets the API write each snapshot to S3 or a compatible provider automatically, which is the approach most teams move to once their archive grows past a few thousand images.

Step-by-Step Guide to Building Your Wayback Machine

Step 1: Get Your ScreenshotAPI.net API Key

First of all you need access to the screenshot API. Go to ScreenshotAPI.net and sign up for a free account. Once registered, you can get an API key that authenticates your requests. Keep this key secure, as it's your gateway to the screenshot functionality.

Step 2: Set Up Your Development Environment

For this tutorial, I'll use Node.js because it's perfect for API integrations and has excellent async support for handling multiple captures. Here's what you'll need:

  • Node.js version 14 or higher installed
  • A code editor like VS Code
  • Basic understanding of REST APIs and JavaScript
  • A place to store your screenshots (local storage or cloud)

First, create a new project directory and initialize it:

mkdir wayback-machine
cd wayback-machine
npm init -y

Install the necessary Node.js packages:

npm install axios node-cron express sqlite3 fs-extra dotenv

These libraries will help you make API calls, schedule regular captures, handle file operations, and manage your database.

Step 3: Create Your Screenshot Capture Function

Now let's write the core function that captures website screenshots. Create a file called capture.js:

const axios = require('axios');
const fs = require('fs-extra');
const path = require('path');

async function captureWebsite(url, apiKey, outputFolder = 'archives') {
  try {
    // Create output folder if it doesn't exist
    await fs.ensureDir(outputFolder);

    // Prepare the API request
    const apiUrl = 'https://shot.screenshotapi.net/v3/screenshot';
    const params = {
      token: apiKey,
      url: url,
      full_page: 'true',
      output: 'image',
      file_type: 'png',
      no_cookie_banners:'true',
      wait_for_event: 'load'
    };

    // Make the request to capture the full page screen
    const response = await axios.get(apiUrl, {
      params: params,
      responseType: 'arraybuffer'
    });

    if (response.status === 200) {
      // Generate filename with timestamp
      const timestamp = new Date().toISOString().replace(/:/g, '-').split('.')[0];
      const safeUrl = url.replace(/https?:\/\//, '').replace(/\//g, '_');
      const filename = `${safeUrl}_${timestamp}.png`;
      const filepath = path.join(outputFolder, filename);

      // Save the screenshot as PNG format
      await fs.writeFile(filepath, response.data);

      console.log(`Screenshot saved: ${filename}`);
      return filepath;
    }
  } catch (error) {
    console.error(`Error capturing screenshot: ${error.message}`);
    return null;
  }
}

module.exports = { captureWebsite };

This function constructs a proper API request with your credentials, handles the response asynchronously, generates a meaningful filename with timestamps, and saves the full image to your archive folder. The service automatically handles cookie banners and ads during the screenshot capture process.

Step 4: Build the Scheduling System

A wayback machine isn't useful if you have to manually trigger it every time. Let's automate the capture process using node-cron. Create a file called scheduler.js:

const cron = require('node-cron');
const { captureWebsite } = require('./capture');

class ArchiveScheduler {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.tasks = [];
  }

  async captureAll(urls) {
    for (const url of urls) {
      await captureWebsite(url, this.apiKey);
      // Be respectful, don't hammer the API
      await this.sleep(5000);
    }
  }

  sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  scheduleDaily(urls, hour = 2, minute = 0) {
    // Schedule daily at specified time (default 2:00 AM)
    const task = cron.schedule(`${minute} ${hour} * * *`, async () => {
      console.log('Starting daily capture...');
      await this.captureAll(urls);
    });

    this.tasks.push(task);
    console.log(`Scheduled daily captures at ${hour}:${minute} for ${urls.length} websites`);
    return task;
  }

  scheduleHourly(urls, minute = 0) {
    // Schedule hourly at specified minute
    const task = cron.schedule(`${minute} * * * *`, async () => {
      console.log('Starting hourly capture...');
      await this.captureAll(urls);
    });

    this.tasks.push(task);
    console.log(`Scheduled hourly captures for ${urls.length} websites`);
    return task;
  }

  scheduleWeekly(urls, dayOfWeek = 1, hour = 2, minute = 0) {
    // Schedule weekly (default: Monday at 2:00 AM)
    const task = cron.schedule(`${minute} ${hour} * * ${dayOfWeek}`, async () => {
      console.log('Starting weekly capture...');
      await this.captureAll(urls);
    });

    this.tasks.push(task);
    console.log(`Scheduled weekly captures for ${urls.length} websites`);
    return task;
  }

  stopAll() {
    this.tasks.forEach(task => task.stop());
    console.log('All scheduled tasks stopped');
  }
}

module.exports = { ArchiveScheduler };

This scheduler runs in the background to automate screenshot capture at your specified intervals. Running captures at 2 AM when traffic is low is generally a good practice.

Step 5: Create a Database to Track Your Archives

While storing images is straightforward, you need a way to track metadata and log each capture. Let's use SQLite for simplicity. Create a file called database.js:

const sqlite3 = require('sqlite3').verbose();
const path = require('path');
const fs = require('fs-extra');

class ArchiveDatabase {
  constructor(dbPath = 'wayback_archive.db') {
    this.db = new sqlite3.Database(dbPath);
    this.initialize();
  }

  initialize() {
    return new Promise((resolve, reject) => {
      this.db.run(`
        CREATE TABLE IF NOT EXISTS archives (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          url TEXT NOT NULL,
          capture_date DATETIME DEFAULT CURRENT_TIMESTAMP,
          filepath TEXT NOT NULL,
          file_size INTEGER,
          status TEXT DEFAULT 'success'
        )
      `, (err) => {
        if (err) reject(err);
        else resolve();
      });
    });
  }

  async logCapture(url, filepath) {
    const stats = await fs.stat(filepath);
    const fileSize = stats.size;

    return new Promise((resolve, reject) => {
      this.db.run(`
        INSERT INTO archives (url, filepath, file_size)
        VALUES (?, ?, ?)
      `, [url, filepath, fileSize], function(err) {
        if (err) reject(err);
        else resolve(this.lastID);
      });
    });
  }

  getArchivesByUrl(url) {
    return new Promise((resolve, reject) => {
      this.db.all(`
        SELECT * FROM archives
        WHERE url = ?
        ORDER BY capture_date DESC
      `, [url], (err, rows) => {
        if (err) reject(err);
        else resolve(rows);
      });
    });
  }

  getAllUrls() {
    return new Promise((resolve, reject) => {
      this.db.all(`
        SELECT DISTINCT url FROM archives ORDER BY url
      `, (err, rows) => {
        if (err) reject(err);
        else resolve(rows.map(row => row.url));
      });
    });
  }

  close() {
    this.db.close();
  }
}

module.exports = { ArchiveDatabase };

Now every capture is logged with its URL, timestamp, location, and file size. This makes it easy to query your archive later and track the image size of each snapshot.

Step 6: Build a Simple Web Interface

Having all these screenshots is great, but you need a way to browse them. Here's a simple Express-based web interface. Create a file called server.js:

const express = require('express');
const path = require('path');
const { ArchiveDatabase } = require('./database');

const app = express();
const db = new ArchiveDatabase();

// Serve static files (screenshots)
app.use('/archives', express.static('archives'));
app.use(express.static('public'));

// Set view engine
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));

// Home page - list all archived URLs
app.get('/', async (req, res) => {
  try {
    const urls = await db.getAllUrls();
    res.render('index', { urls });
  } catch (error) {
    res.status(500).send('Error loading archives');
  }
});

// Timeline page - show all captures for a specific URL
app.get('/timeline', async (req, res) => {
  try {
    const url = req.query.url;
    const captures = await db.getArchivesByUrl(url);
    res.render('timeline', { url, captures });
  } catch (error) {
    res.status(500).send('Error loading timeline');
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Wayback Machine running on http://localhost:${PORT}`);
});

This creates a simple web app interface where you can select a website and view its capture timeline. Users can easily download and print archived versions.

Step 7: Putting It All Together

Now let's create a main file that ties everything together. Create index.js:

require('dotenv').config();
const { captureWebsite } = require('./capture');
const { ArchiveScheduler } = require('./scheduler');
const { ArchiveDatabase } = require('./database');

// Configuration
const API_KEY = process.env.SCREENSHOTAPI_KEY;
const WEBSITES_TO_MONITOR = [
  'https://example.com',
  'https://competitor1.com',
  'https://competitor2.com'
];

async function main() {
  // Initialize database
  const db = new ArchiveDatabase();

  // Create scheduler
  const scheduler = new ArchiveScheduler(API_KEY);

  // Schedule daily captures at 2 AM
  scheduler.scheduleDaily(WEBSITES_TO_MONITOR, 2, 0);

  console.log('Wayback Machine initialized!');
  console.log(`Monitoring ${WEBSITES_TO_MONITOR.length} websites`);
  console.log('Scheduled captures will run daily at 2:00 AM');

  // Optional: Capture immediately on start
  console.log('Taking initial snapshots...');
  for (const url of WEBSITES_TO_MONITOR) {
    const filepath = await captureWebsite(url, API_KEY);
    if (filepath) {
      await db.logCapture(url, filepath);
    }
  }

  console.log('Initial snapshots complete!');
}

// Handle graceful shutdown
process.on('SIGINT', () => {
  console.log('Shutting down gracefully...');
  process.exit(0);
});

main().catch(console.error);

Create a .env file to store your API key:

SCREENSHOTAPI_KEY=your_api_key_here

Local disk is fine for a first run, but a growing archive belongs in durable object storage. Two paths work here. The first is to keep the capture code above and upload each saved file to your bucket after writing it, using the AWS SDK. The second, which removes a step, is to let the screenshot request deliver the image directly to your storage through the storage integration, so the file never touches your server.

A minimal upload after capture looks like this:

const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
const fs = require('fs-extra');

const s3 = new S3Client({ region: process.env.AWS_REGION });

async function uploadSnapshot(filepath, key) {
  const body = await fs.readFile(filepath);
  await s3.send(new PutObjectCommand({
    Bucket: process.env.ARCHIVE_BUCKET,
    Key: key,
    Body: body,
    ContentType: 'image/png'
  }));
  console.log(`Uploaded to s3://${process.env.ARCHIVE_BUCKET}/${key}`);
}

module.exports = { uploadSnapshot };

Store the returned object key in the same database row as the local path. That way your viewer can serve snapshots from the bucket and your disk stays clean between runs.

Common Use Cases and Examples

Competitor Analysis: A marketing agency archives competitors' homepages weekly, tracking messaging changes, design updates, and promotional campaigns using full page screenshots.

Compliance Monitoring: A legal firm captures regulated websites daily to ensure compliance with advertising standards and maintain evidence for cases, storing each version as data for review.

Portfolio Documentation: A web design agency archives client websites before and after redesigns, creating compelling before-and-after showcases with full size page screenshots.

Price Tracking: An e-commerce consultant monitors competitor pricing pages, capturing changes and identifying pricing strategies through regular webpage snapshots.

Content Preservation: A journalist archives news articles and social media posts for investigative research before they can be deleted or modified, ensuring no online content is lost.

Conclusion: Your Time Machine Awaits

Building your own wayback machine with ScreenshotAPI.net gives you unexpected control over website archiving. Whether you're tracking competitors, preserving content for legal purposes, or simply documenting the evolution of the web, this system puts you in the driver's seat.

The beauty of this approach is its flexibility. Start simple with basic scheduled captures, then expand with comparison tools, mobile viewports, and cloud storage as your needs grow. The service supports various features including custom width parameters, scale adjustments, and zoom control. You can also export to different formats like JPEG or PDF based on your requirements.

Pairing ScreenshotAPI's real-browser rendering with a small amount of Node.js gives you an archiving tool built to your exact needs, without running a crawler or maintaining a heavy server. You control what gets captured, how often, and where it is stored.

Websites change and disappear without warning. A private, scheduled screenshot archive means you keep a dated visual record of the pages that matter, whether that is a competitor's homepage, a regulated pricing page, or a client site mid-redesign.

Ready to start? Create a free ScreenshotAPI account, get your API key, and run your first scheduled capture today.

Frequently Asked Questions

Can a screenshot-based wayback machine replace the Internet Archive?

No, and it is not meant to. The Internet Archive stores browsable HTML for billions of public pages. A screenshot archive stores private, timestamped images of the specific pages you choose. Use it when you need visual proof and control, not a public, clickable copy of the whole web.

What is the difference between a screenshot archive and a WARC archive?

A screenshot archive saves the rendered image of a page, so you see exactly what a visitor saw. A WARC archive saves the raw HTML and assets, so the page stays clickable and its links work. Screenshots prove appearance. WARC preserves function.

How often should I capture snapshots?

Match the schedule to how fast the page changes. Pricing and news pages suit daily captures, marketing sites suit weekly, and legal or compliance pages often run hourly. The scheduler in this guide supports all three, so you can set different intervals per URL.

Where should I store archived screenshots long term?

Object storage such as S3 is the durable choice once your archive grows. It is cheap, scales without limit, and keeps snapshots off your application server. Store the object key alongside each database record so your viewer can load images directly from the bucket.

Capturing publicly available pages for internal research, monitoring, or evidence is generally accepted, but rules vary by country and use. Avoid archiving pages behind a login without permission, and consult your legal team before relying on archives in a dispute. This is general information, not legal advice.