AI Training Datasets

Turn URL lists into clean screenshot datasets for machine learning. Batch capture thousands of web pages with blocked ads and cookies. Free tier available.

Vitalii Holben Updated

A screenshot API built for AI training data turns any URL list into a labeled image dataset. Feed in 10,000 URLs, get back 10,000 consistently-sized PNG files with clean renders, no cookie banners, no chat widgets. ML teams use this to collect website screenshots for machine learning. Some train page classifiers. Others build layout detectors or screenshot-to-code models. The pipeline is the same regardless of the task, and below is what it looks like in practice.

Why real website screenshots beat synthetic training data

Synthetic datasets look clean but miss the chaos of real web pages. A generated e-commerce layout won't have the broken CSS you see on live Shopify stores. It won't include the third-party script that shifts the hero image 40 pixels down. And it definitely won't look like a Japanese site mixing horizontal and vertical text as it actually renders in Chrome on Linux.

Real screenshots from live URLs give your model the full distribution: clean sites, broken sites, sites with aggressive popups, RTL Arabic layouts, single-page apps that take 6 seconds to hydrate. Your model learns what you show it. Show it cookie banners, it learns cookie banners.

The biggest public datasets in this space all started the same way. WebSight collected 823K screenshot-HTML pairs for code generation. ScreenRef gathered 586K screenshots for GUI grounding. Roboflow's Website Screenshots dataset has 1,206 annotated images for element detection. Different goals, same starting point: a URL list and a way to screenshot thousands of pages consistently.

Building a screenshot API pipeline for training data

Four stages: URL collection, batch capture, storage, and labeling. The API handles stage two. The rest is your infrastructure.

Stage 1: URL collection

Common Crawl, the Tranco top-1M list, or domain-specific crawls from your own scraper. The URL source determines the distribution of your dataset. Want to train a page classifier? Mix e-commerce, news, SaaS, blogs, and government sites evenly. Want a layout detector? Oversample pages with complex grids and sidebars.

Stage 2: Batch capture

The batch endpoint accepts up to 100 URLs per request with shared capture settings. Fire multiple batches in parallel, use webhooks to collect results as they finish.

import requests
import json

urls = open("urls.txt").read().splitlines()
API_KEY = "YOUR_API_KEY"

# Split into batches of 100
for i in range(0, len(urls), 100):
    batch = urls[i:i+100]
    resp = requests.post(
        "https://api.screenshotrun.com/v1/screenshots/batch",
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json",
        },
        json={
            "urls": batch,
            "width": 1280,
            "height": 800,
            "format": "png",
            "block_cookies": True,
            "block_ads": True,
            "block_chats": True,
            "delay": 2,
            "webhook_url": "https://your-server.com/webhook/screenshots",
        },
    )
    data = resp.json()
    print(f"Batch {i//100 + 1}: {len(data['data'])} screenshots queued")

Each webhook callback delivers the screenshot URL, dimensions, file size, and the original URL. Store the metadata alongside the image for your annotation pipeline later.

Stage 3: Storage and naming

Dump images into S3, GCS, or a local directory with deterministic naming. I usually hash the URL to get a consistent filename: sha256(url)[:16].png. Saves headaches with naming collisions down the road. Re-running the pipeline on the same URL list produces the same filenames, making diffing and versioning straightforward.

Stage 4: Labeling

Label Studio, CVAT, or Roboflow for annotation. For page classification (e-commerce vs blog vs SaaS), the labels are simple strings. For element detection (buttons, forms, navbars), you need bounding boxes over each screenshot. For screenshot-to-code, the label is the page's HTML source, which you can extract separately via scraping or via the API's extract_metadata parameter.

Clean captures: removing noise from training data

ML models are sensitive to input variance that has nothing to do with what you're trying to learn. A cookie consent banner covering 30% of the viewport is noise, not signal. Same for ads that shift the layout and chat widgets that add a visual feature your model doesn't need. All of that muddies the training data.

Three parameters clean up most of it:

{
  "url": "https://example.com",
  "width": 1280,
  "height": 800,
  "format": "png",
  "block_cookies": true,
  "block_ads": true,
  "block_chats": true,
  "hide_selectors": [".newsletter-popup", ".promo-banner"]
}

Cookie blocking removes consent dialogs before the capture. Ad blocking strips display ads and tracking banners. And block_chats hides Intercom, Drift, HubSpot, and the rest.

If a specific site has a custom popup that slips through, hide_selectors targets it by CSS selector. Clean input, clean model.

Want component-level training data? Use the selector parameter

Full-page screenshots work for page classification. For training a model to detect buttons, forms, or navigation bars, you want cropped images of individual components. One parameter does it.

The selector parameter captures a single DOM element instead of the full viewport. Pass "selector": "nav" and you get just the navigation bar. Pass "selector": "form.checkout" and you get the checkout form. Loop through a list of selectors per page and you have a component-level dataset without any manual cropping.

selectors = {
    "navbar": "nav, header nav, [role='navigation']",
    "hero": ".hero, [class*='hero'], .banner",
    "footer": "footer, [role='contentinfo']",
    "form": "form:not([role='search'])",
    "cta_button": ".cta, [class*='cta'], a.btn-primary",
}

for url in urls:
    for label, sel in selectors.items():
        resp = requests.get(
            "https://api.screenshotrun.com/v1/screenshots/capture",
            params={
                "url": url,
                "selector": sel,
                "format": "png",
                "block_cookies": "true",
                "response_type": "json",
            },
            headers={"Authorization": f"Bearer {API_KEY}"},
        )
        if resp.ok:
            save_image(resp.json(), label, url)

Not every page will have every selector. The API returns an error if the selector doesn't match, so your script needs to handle that gracefully. Annoying, but not a dealbreaker. For large URL lists, the hit rate across common selectors like nav and footer is high enough to build substantial per-component datasets.

Visual dataset augmentation with API parameters

Data augmentation in computer vision usually means random crops, flips, and color jitter. For web screenshot datasets, you can augment at capture time using the same URL with different parameters. Same page, genuinely different renders.

ParameterAugmentationExample
dark_modeLight and dark variants of the same page2× dataset size from same URL list
deviceDesktop, mobile, tablet renders3× variants per URL
widthMultiple viewport widths (320, 768, 1280, 1920)Test responsive breakpoints
geolocation + proxySame page from different countriesLocalized layouts, currencies, RTL
cssInject custom styles (hide elements, change fonts)Robustness to style variation

I've found dark mode to be the easiest win. Every URL that supports prefers-color-scheme gives you two training samples instead of one, and the visual difference is real, not a synthetic color shift. Device emulation is the second: the same page at 375px (mobile) and 1280px (desktop) produces genuinely different layouts that a responsive-design model needs to see.

Which ML tasks can you feed with screenshots?

Page classification

E-commerce, blog, SaaS dashboard, documentation, government portal. Full viewport screenshots at 1280×800, PNG format, no cookie banners. Labels are one string per image. Urlbox published a case study where they built a CNN classifier on screenshots from the Alexa Top Sites with high accuracy on "clean" vs "obstructed" pages. Same approach works for any category taxonomy.

GUI grounding

Training a model to locate a UI element from a natural language instruction ("click the sign-up button," "find the search bar"). Datasets like ScreenRef (586K screenshots, 633K instructions) and ScreenSpot use annotated web screenshots. The capture pipeline provides the raw images; annotation is a separate step in Label Studio or similar.

Screenshot-to-code

Given a screenshot, generate the HTML and CSS that produced it. WebSight has 823K pairs, WebCode2M has 2M. To build your own, you need the screenshot and the page source captured together. The API's extract_metadata parameter returns the final URL and response headers. Scrape the HTML separately, or go the other direction: render known HTML via the html parameter and keep the screenshot-code pair.

Visual anomaly detection

Capture the same page on a schedule, train a model to flag unexpected changes. This overlaps with website change monitoring but the ML angle is different: instead of pixel-diffing two images, you train a model to learn what "normal" looks like and flag deviations. Useful for defacement detection, ad injection monitoring, or visual regression testing at scale.

What this pipeline won't solve

Look, screenshots are pixels. If your model needs DOM structure, z-index stacking, or accessibility attributes, you need the HTML too. The API captures images, not markup. For structured DOM data, pair it with a scraper.

JavaScript-heavy SPAs can produce inconsistent screenshots if the page hasn't finished hydrating. Set delay=3 or use wait_for_selector to target a specific element that only appears after render completes. Even so, some sites show different content on every load due to personalization or A/B testing. For page classification, that variability is noise — you want one canonical render per URL. For robustness training, it's a feature. Depends on your task.

And at 200 screenshots/month on the free tier, you're building a proof-of-concept, not a production dataset. The Starter plan at $9/month gives you 2,000. For serious dataset work (10K+ screenshots), you'll need a higher-volume plan. Check pricing for the right fit.

From URL list to training data in one script

Start with 500 URLs across 5 categories — enough to validate webpage screenshots for model training before scaling. Capture at 1280×800, PNG, with cookie and ad blocking. That gives you 100 samples per class, a solid baseline classifier. If your model needs element-level data, add the selector parameter for component crops. If it needs device diversity, capture each URL at three viewports. The Python integration guide covers authentication and error handling. The bulk screenshots use case covers the batch workflow in more detail.

For runtime AI input rather than training data, see the AI agents use case. Different pipeline, different page.

FAQ#

The free tier includes 200 screenshots per month. Enough to build a small proof-of-concept dataset across a few categories. For serious dataset work (10K+ images), check the Starter or Pro plans.

Yes. The selector parameter captures a single DOM element by CSS selector. Pass selector=nav to get just the navigation bar, or selector=form to get a form. Loop through selectors per URL to build component-level datasets without manual cropping.

Three parameters handle it: block_cookies removes consent dialogs, block_ads strips display advertising, and block_chats hides chat widgets like Intercom or Drift. For custom popups, use hide_selectors with a CSS selector targeting the specific element.

PNG, JPEG, WebP, AVIF, and TIFF. PNG is the most common for training data because it is lossless. JPEG and WebP produce smaller files if storage is a constraint, but introduce compression artifacts that may affect model training.

Yes. Capture the same URL with different parameters to get genuinely different renders. Use dark_mode for light/dark variants, device for desktop/mobile/tablet, width for multiple viewport sizes, and geolocation with proxy for country-specific layouts. Each combination produces a distinct training sample from the same URL.

Written by

Vitalii Holben

Co-founder and CEO of ScreenshotRun. Full-stack developer building screenshot API tools that help developers capture, automate, and monitor web pages at scale. Based in Europe, shipping code since 201...

Screenshot API in a few clicks

Free plan includes 200 screenshots every month. No credit card required.

Sign up → copy your key → make your first call