Screenshots as URLs.
Want a screenshot of a page for any reason? Just drop a link. Get a clean, browser-faithful screenshot. Instantly embeddable. Cached forever.
One-sentence value proposition This is the simplest way to clip the web: turn any page into a stable image just using the URL.
Most screenshot tools are dashboards, APIs, or workflows you have to integrate. This is different. Here, the screenshot is the URL.
You paste a link like:
screenshotit.app/example.com
and you get a real-browser screenshot you can embed anywhere—Markdown, blogs, wikis, notes, docs, or posts—without setup, SDKs, or UI.
It’s designed for writers, researchers, publishers, and builders who want web clippings that just work: no copy-paste, no manual uploads, no broken embeds when pages change.
What makes it different • URL-native: screenshots are addressable resources, not files you manage • Embed-first: made for Markdown, static sites, wikis, and notes • Stable by default: cached, immutable, and safe to reference long-term • Opinionated defaults: clean, above-the-fold captures without tweaking • Zero workflow: paste once, done forever
What it’s for • Clipping references into essays, research notes, or white papers • Capturing homepage or hero states for documentation • Creating visual previews in Markdown-based sites • Preserving how a page looked at the moment you cited it
What it's not It's not a screenshot editor, a dashboard, or a testing suite. It's a primitive: the web → image, via URL.
Append modifiers with @ to customize screenshots:
screenshotit.app/example.com@full # Full page
screenshotit.app/example.com@mobile # Mobile viewport
screenshotit.app/example.com@social # Social preview (1200×630)
screenshotit.app/example.com@refresh # Force fresh capture
screenshotit.app/example.com@full@mobile # Combine them
screenshotit.app/example.com@2026-01-28 # Screenshot from a specific date
The https:// protocol is optional — screenshotit.app/example.com and screenshotit.app/https://example.com resolve to the same screenshot. URLs are normalized (lowercased, query strings and fragments stripped) for consistent caching.
Use @YYYY-MM-DD to retrieve a screenshot from a specific date. If no screenshot exists for that exact date, the nearest earlier one is returned. Returns 404 only if no screenshots exist on or before the requested date.
Need an og:image for link previews? Use @social to get a screenshot sized exactly for Open Graph — 1200×630 at 2x for retina-sharp previews on Twitter/X, Facebook, LinkedIn, Discord, Slack, and more.
<meta property="og:image" content="https://screenshotit.app/yoursite.com@social">That's it. No image generation pipeline, no Puppeteer server, no build step. Every page on your site gets a live social preview image just by referencing its URL.
GitHub login adds an optional public username namespace without changing anonymous URLs:
screenshotit.app/@alice/example.com
screenshotit.app/@alice/example.com@full
Anyone can view an existing account screenshot. Only the account owner can create a missing screenshot, use @refresh, or delete it. Account objects use an immutable internal account ID in R2, so a future username change can retain the old username as an alias without moving stored images.
The dashboard at /dashboard lists owned screenshots, capture and access counts, storage usage, refresh links, and deletion controls. New accounts currently receive a limit of 100 logical screenshots and 100 MiB of stored account screenshots. Anonymous screenshots continue to use the shared namespace and existing behavior.
Prerequisites:
- Node.js 18+
- Cloudflare account (free tier works for development)
Setup:
npm install
cp .dev.vars.example .dev.varsSet the local GitHub OAuth credentials in .dev.vars. For local OAuth testing, create a separate development OAuth app and override APP_ORIGIN with the origin printed by wrangler dev; GitHub requires its callback URL to match <origin>/auth/github/callback.
Run locally:
npm run devNote: Browser Rendering API doesn't work in local mode. Use wrangler dev --remote to test against Cloudflare's infrastructure (requires authentication).
Run tests:
npm testScreenshot analytics are tracked server-side in Cloudflare D1:
access_countincrements on every successful screenshot response (cached or fresh)created_countincrements on every newly captured screenshot- Homepage uses this data for:
- most accessed screenshots leaderboard
- recently created screenshots list
Tracking starts from the point this feature is deployed. No backfill is performed by default.
-
Login to Cloudflare:
npx wrangler login
-
Create R2 bucket:
npx wrangler r2 bucket create screenshotit
-
Enable Browser Rendering API:
- Go to Cloudflare Dashboard → Workers & Pages → your account
- Browser Rendering requires a paid Workers plan ($5/month)
-
Create D1 database for analytics:
npx wrangler d1 create screenshotit-analytics
Copy the
database_idfrom output and set it inwrangler.jsoncunderd1_databases. -
Apply D1 migrations:
npx wrangler d1 migrations apply ANALYTICS_DB --local npx wrangler d1 migrations apply ANALYTICS_DB --remote
-
Create a GitHub OAuth App:
- In GitHub, open Settings → Developer settings → OAuth Apps.
- Use
https://screenshotit.appas the homepage URL. - Use
https://screenshotit.app/auth/github/callbackas the authorization callback URL. - Set the public client ID and secret as Worker secrets:
npx wrangler secret put GITHUB_CLIENT_ID npx wrangler secret put GITHUB_CLIENT_SECRET
- Enter both values only at Wrangler's interactive prompts; do not commit them.
-
Validate the bundle:
npx wrangler types src/worker-configuration.d.ts --include-runtime false --check npx wrangler deploy --dry-run
npm run deployThis deploys to screenshotit.<your-subdomain>.workers.dev.
To use a custom domain like screenshotit.app:
- Add domain to Cloudflare (DNS must be on Cloudflare)
- Go to Workers & Pages → screenshotit → Settings → Triggers
- Add custom domain
Cloudflare can deploy automatically when you push to GitHub:
- Go to Cloudflare Dashboard → Workers & Pages → Create
- Select "Connect to Git" and authorize GitHub
- Select your repository
- Configure build settings:
- Build command:
npm install - Deploy command:
npx wrangler deploy
- Build command:
- Deploy
Now every push to main automatically deploys.
Built on Cloudflare's edge infrastructure:
- Worker - Request handling, URL parsing, caching logic
- Browser Rendering API - Headless Chromium for screenshots
- R2 - Object storage for cached screenshots
- D1 - Analytics counters for accesses and creations
- GitHub OAuth - Initial account identity provider
- D1 accounts - Usernames, aliases, hashed sessions, ownership, and usage statistics