User-Generated Content Screenshots via API

Capture user posts, reviews, and listings before they're edited or deleted. Automate UGC evidence for moderation, DMCA, and trust & safety.

Vitalii Holben Updated

The API captures any user-generated content as a screenshot — a forum post, a product review, a marketplace listing, a comment thread. You pass the URL, optionally target a specific element with selector, and get back a pixel-perfect image of what that content looked like at that moment. One call. If the user edits their post, deletes it, or a moderator removes it, you already have the visual record.

Why UGC disappears before you can document it

Users delete things. That's the whole problem. A customer posts a defamatory review on your marketplace, you flag it for legal review, and by the time the attorney sees it three days later the user has already edited out the worst parts. Or a seller on your platform lists a counterfeit product, gets reported, and deletes the listing before your trust and safety team screenshots it. You're left explaining to the brand owner that yes, the listing existed, but no, you don't have proof.

Platform exports don't help much here. They give you text and metadata, but not the visual layout. Where was the image positioned? What did the username look like? Did the profile picture match? A screenshot captures that full visual context. And in disputes, DMCA filings, and court proceedings, visual context is what actually holds up.

Manual screenshotting works when you're dealing with three reports a week. At 300? Someone on your trust and safety team is spending half their day opening tabs, scrolling, pressing Cmd+Shift+4, renaming files, and dropping them into the right ticket. The API does that in under two seconds per page.

Capture a specific post or comment with the selector parameter

Most UGC lives inside a larger page — a comment within a thread, a review on a product page, a listing in a marketplace grid. Capturing the full page gives you context but also noise. The selector parameter lets you target the exact element:

curl "https://api.screenshotrun.com/v1/screenshots/capture?\
url=https://your-platform.com/forum/thread/12345#comment-678\
&selector=.comment[data-id='678']\
&delay=2000\
&block_cookies=true\
&block_ads=true\
&certified=true\
&format=png\
&response_type=json" \
  -H "Authorization: Bearer YOUR_API_KEY"

The delay=2000 handles dynamically loaded comment threads where the target element might not exist in the initial DOM. If the comment loads via AJAX or Intersection Observer (most modern forums do), the browser needs a moment after page load to actually render it. Alternatively, use wait_for_selector=.comment[data-id='678'] for more precise timing — it pauses the capture until that exact element appears in the DOM, then fires.

Automate evidence capture for trust and safety queues

When a user reports content on your platform, the report goes into a queue. But between the report timestamp and the moment a reviewer opens it — could be minutes, could be a day — the content might change. Or vanish entirely. An automated pipeline that screenshots reported content the instant a report is filed closes that gap before it opens.

Here's a Node.js webhook handler that captures flagged content when your moderation system fires a report event:

const express = require('express');
const app = express();
app.use(express.json());

const API = 'https://api.screenshotrun.com/v1/screenshots/capture';
const API_KEY = process.env.SCREENSHOT_API_KEY;

app.post('/webhooks/content-report', async (req, res) => {
  const { content_url, content_selector, report_id, reporter_id } = req.body;

  const params = new URLSearchParams({
    url: content_url,
    selector: content_selector || '',
    delay: '2000',
    block_cookies: 'true',
    block_ads: 'true',
    certified: 'true',
    format: 'png',
    response_type: 'json',
  });

  const resp = await fetch(`${API}?${params}`, {
    headers: { 'Authorization': `Bearer ${API_KEY}` },
  });
  const data = await resp.json();

  // Store screenshot URL and certification hash with the report
  await db.reports.update(report_id, {
    screenshot_url: data.data.screenshot_url,
    cert_hash: data.data.certification.hash,
    cert_timestamp: data.data.certification.timestamp,
    captured_at: new Date().toISOString(),
  });

  res.json({ status: 'captured', report_id });
});

app.listen(3000);

Every report now has a screenshot attached before anyone touches it. The certified=true parameter adds a SHA-256 hash and timestamp, so if the case escalates to legal, you have tamper-proof evidence of what the content looked like when it was reported.

DMCA takedown documentation

Under 17 U.S.C. § 512, platforms that host user content need to respond to DMCA takedown notices. Part of that response is documenting what was posted, when it was visible, and when it was removed. A screenshot with a certification timestamp covers the "what" and "when it was visible" in a single file.

The typical DMCA workflow: rights holder sends a takedown notice, your team verifies the claim, captures the infringing content, removes it, stores the evidence. Simple enough on paper. But without automation, that middle step — capturing the content — depends on someone manually screenshotting before someone else clicks delete. At scale (think a marketplace with thousands of seller listings), the automation isn't optional. It's the only way the evidence exists by the time the legal team needs it.

For platforms handling counter-notices, the same applies in reverse. You need proof that the content was restored on a specific date. Schedule a capture after restoration and store the certified screenshot alongside the counter-notice file.

Marketplace listing verification

Marketplaces have a constant problem with sellers listing counterfeit goods, using stolen product photos, or making claims that don't hold up. Brand protection teams send complaints. So what does the marketplace actually need? Evidence of what the listing looked like when the complaint was filed. Not what it looks like after the seller quietly edits out the brand name two hours later.

A daily sweep of flagged seller listings captures the state of each listing with certified=true. If a seller changes their listing between Tuesday and Thursday, you have both versions with verifiable dates. Brand owners also use this approach from the outside — they screenshot infringing listings on marketplaces they don't control, building an evidence file before filing a complaint.

For this use case, full_page=true matters because marketplace listings often have product details, seller information, shipping terms, and return policies spread across a long scrollable page. A viewport-only screenshot misses the seller's claims buried at the bottom.

Forum and community moderation records

Community platforms — Reddit-style forums, Discord-adjacent chat platforms, discussion boards — deal with content reports that reference specific messages in specific threads. And the context around the message matters almost as much as the message itself. Was it a reply to something provocative? Was there a pattern of harassment across multiple posts? Was the user impersonating someone? A single screenshot of the offending message, ripped from its thread, tells half the story at best.

A full-thread screenshot preserves the conversational context that a single-message screenshot loses. Use full_page=true for short threads. For longer threads, target the relevant section with selector or use scroll_to to position the viewport around the flagged content and capture a window of surrounding messages.

If your platform has authenticated-only content (members-only forums, private channels), pass session cookies via the cookies parameter. The API doesn't log in for you, but it accepts valid session cookies to capture pages behind login walls.

Capture UGC across multiple platforms

Brands monitoring what users say about them across the web need screenshots from platforms they don't control. A mention on a niche forum, a review on a local business directory, a complaint on a consumer advocacy site. The same API call works regardless of the platform:

import requests

API = "https://api.screenshotrun.com/v1/screenshots/capture"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}

mentions = [
    {"url": "https://forum.example.com/thread/12345#post-678", "selector": "#post-678"},
    {"url": "https://reviews.example.com/business/your-brand/review/456", "selector": ".review-card"},
    {"url": "https://complaints.example.com/case/789", "selector": ""},
]

for mention in mentions:
    params = {
        "url": mention["url"],
        "delay": "2000",
        "block_cookies": "true",
        "block_ads": "true",
        "certified": "true",
        "format": "png",
        "response_type": "json",
    }
    if mention["selector"]:
        params["selector"] = mention["selector"]

    resp = requests.get(API, headers=HEADERS, params=params).json()
    print(f"Captured: {mention['url'][:60]}...")
    print(f"  Hash: {resp['data']['certification']['hash'][:16]}...")

The stealth parameter helps on platforms that detect headless browsers. Forums running Cloudflare, review sites with bot protection, community platforms with anti-scraping measures. Stealth mode makes the API's browser look like a regular desktop visitor. Not bulletproof — aggressive rate limiting and interactive CAPTCHAs will still block you — but it handles standard Cloudflare challenges and most JavaScript fingerprinting. We recommend spacing requests to no more than 10 per minute per domain.

What makes UGC pages hard to screenshot?

Dynamic loading is the big one. Almost every modern platform lazy-loads content — comments load on scroll, reviews paginate, forum threads infinite-scroll. The full_page parameter handles the scrolling part, but you still need either delay or wait_for_selector to give dynamically loaded content time to actually render. Without it, you get screenshots with grey placeholders where comments should be.

Login walls. Private groups, members-only forums, authenticated review dashboards — all require valid session cookies passed via the cookies parameter. The API runs each capture in an ephemeral browser instance with no stored cookies or cache, so you need to provide the session on every request.

Embedded media. User posts often include embedded videos, iframes, tweet embeds, Instagram embeds. Videos render as a poster frame (or blank). Tweet/Instagram embeds usually work, but they load asynchronously and need 2-3 seconds of delay to fully render. Some platforms block iframe embedding entirely, which means embedded content from those sources appears as a grey rectangle.

Infinite scroll threads. If a forum thread has 500 comments, full_page=true will scroll through all of them. That produces a very tall screenshot (potentially tens of thousands of pixels) and takes longer to render. For long threads, target the specific section with selector instead.

UGC screenshots vs. Pagefreezer and manual tools

Pagefreezer ($500+/month) is the enterprise standard for social media and website archiving. Comprehensive, SOC 2 certified, built for compliance teams. But it's a closed platform — no API to integrate into your moderation queue, your ticketing system, or your custom trust and safety pipeline. You get their dashboard, their workflows, their timeline.

Smarsh and Global Relay serve the same financial compliance niche at similar enterprise price points. Good for FINRA archiving requirements, overkill for a marketplace that just needs to screenshot a seller listing before removing it.

Manual browser screenshots fall apart at volume. Even with browser extensions like GoFullPage, someone still has to open the page, wait for it to load, trigger the capture, download the file, and attach it to the right ticket. At 50 reports per day, that's roughly two hours of someone's time. I've talked to trust and safety leads who had a dedicated person doing nothing but this. The API does the same thing in background, triggered by the report event, before a human ever looks at the case.

The API fits between "manual screenshots" and "enterprise archiving platform." Automation and tamper-proof timestamps, without the six-figure annual contract or the three-month onboarding. Start with your highest-volume content type — if marketplace listings are 60% of your moderation queue, automate those first. A hundred captures per day is 3,000 per month, well within the Starter plan. Scale from there once the pipeline proves itself.

FAQ#

Yes, with the stealth parameter enabled. Social platforms actively detect and block headless browsers, but stealth mode bypasses standard Cloudflare challenges and most JavaScript fingerprinting. Keep requests under 10 per minute per domain to avoid rate limiting. Interactive CAPTCHAs on some platforms may still block captures.

Certified screenshots include a SHA-256 hash and ISO 8601 timestamp that prove the image has not been altered since capture. This strengthens their evidentiary value in DMCA disputes, defamation cases, and compliance audits. However, they are not equivalent to RFC 3161 timestamped evidence or notarized captures. Consult legal counsel for jurisdiction-specific admissibility requirements.

Pass valid session cookies via the cookies parameter. Log into your platform in a browser, extract the session cookie, and include it in the API request. The API does not store or manage login sessions — each capture uses the cookies you provide for that specific request.

It depends on your report volume. A platform handling 50 content reports per day uses about 1,500 API calls per month. At 200 reports per day, that is 6,000 calls per month. The Starter plan covers moderate volumes. If you also run scheduled sweeps of flagged listings or user profiles, add those captures to your estimate.

Yes. Use the selector parameter with a CSS selector targeting the specific element — for example, selector=.comment[data-id="678"] or selector=.review-card. The API renders the full page but returns only the targeted element as the screenshot. This reduces file size and focuses on the relevant content.

The API captures whatever is visible at the URL when the request runs. If the content has already been deleted, the screenshot will show the page without that content — typically a 404 page or a "content removed" message. To avoid this, trigger captures immediately when a report is filed using a webhook integration, not on a delayed schedule.

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