Use a curated array of screenshot URLs or local files, choose one with JavaScript, and assign it to an <img> element. The example below includes accessible alt text, stable dimensions, a “Show another” control, a loading-error fallback, and notes for remote images, CORS, CSP, licensing, performance, and deployment.
What you are building
The page will select one screenshot from a list when it loads and can select another when a visitor clicks a button. Each list item contains a URL, descriptive alternative text, and optional dimensions. Local files and remote URLs both work for display, provided the remote host allows the browser to request the image and does not block hotlinking.
An HTML <img> embeds the image in the document. Its alt value is the text a screen reader announces and the text shown when the image cannot load. Supplying known width and height values lets the browser reserve space before the file arrives, reducing layout movement. See the MDN <img> reference.
Choose and organize your screenshot sources
Local, curated assets
For a small collection, put files such as dashboard.webp and checkout.png in an images/screenshots/ directory and reference them with paths beginning at your site root. You control availability, dimensions, and updates, and visitors do not depend on another domain.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
Remote image URLs
A direct URL in src is enough when the page only needs to display the image. The remote server can still change the file, require authorization, block hotlinking, or disappear. Confirm that the owner permits embedding or copying; the browser documentation does not establish rights for any particular screenshot source.
API-backed collections
If an API returns a changing collection, have your server obtain and validate the data, then send the page usable image URLs and metadata. Do not assume browser JavaScript can scrape arbitrary sites. Script-initiated cross-origin reads are governed by the same-origin policy and require the source server’s CORS permission; see MDN’s same-origin policy and CORS guide.
Complete HTML, CSS, and JavaScript example
Save this as index.html. Replace the sample paths with screenshots you are licensed to use. The script selects a new item without repeating the current item when two or more choices exist.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Random screenshot</title>
<style>
:root { color-scheme: light dark; }
body { max-width: 70rem; margin: 2rem auto; padding: 0 1rem;
font: 1rem/1.5 system-ui, sans-serif; }
figure { margin: 1.5rem 0; }
#shot { display: block; max-width: 100%; height: auto; border-radius: .5rem; }
#status { min-height: 1.5em; }
.error { color: #b00020; }
</style>
</head>
<body>
<main>
<h1>Random screenshot</h1>
<button id="another" type="button">Show another</button>
<p id="status" role="status" aria-live="polite"></p>
<figure>
<img id="shot" width="1600" height="1000"
src="images/screenshots/home.webp"
alt="Homepage dashboard showing weekly traffic">
<figcaption id="caption"></figcaption>
</figure>
</main>
<script>
const screenshots = [
{ src: "images/screenshots/home.webp", alt: "Homepage dashboard showing weekly traffic", width: 1600, height: 1000 },
{ src: "images/screenshots/settings.webp", alt: "Settings screen with notification controls", width: 1600, height: 1000 },
{ src: "https://cdn.example.com/product-report.png", alt: "Product report with a monthly sales chart", width: 1200, height: 800 }
];
const image = document.querySelector("#shot");
const caption = document.querySelector("#caption");
const status = document.querySelector("#status");
let current = -1;
function randomIndex() {
if (screenshots.length === 0) return -1;
if (screenshots.length === 1) return 0;
let next;
do { next = Math.floor(Math.random() * screenshots.length); }
while (next === current);
return next;
}
function showRandom() {
const next = randomIndex();
if (next < 0) {
status.textContent = "No screenshots are configured.";
status.className = "error";
image.hidden = true;
return;
}
current = next;
const item = screenshots[current];
status.textContent = "Loading screenshot…";
status.className = "";
image.hidden = false;
image.onerror = () => {
status.textContent = "This screenshot could not be loaded.";
status.className = "error";
image.alt = "Screenshot unavailable";
};
image.onload = () => { status.textContent = ""; };
image.width = item.width;
image.height = item.height;
image.alt = item.alt;
image.src = item.src;
caption.textContent = item.alt;
}
document.querySelector("#another").addEventListener("click", showRandom);
showRandom();
</script>
</body>
</html>
When you do not know an image’s dimensions, omit the numeric attributes rather than inventing them, but expect more layout movement while it loads. You can still constrain display size with CSS.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minuteRank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
How the random selection works
- Define allowed entries. The array is an explicit allow-list, so a malformed or unexpected URL cannot be injected at runtime.
- Generate an index.
Math.floor(Math.random() * screenshots.length)produces an integer from zero through the final array index. - Avoid immediate repeats. The loop redraws while the new index equals
current. With one entry, repetition is unavoidable and the function returns that entry. - Update the element. The script sets
src,alt, dimensions, and the caption together so the text describes the selected image. - Handle failure. The
errorevent leaves a readable message instead of a broken-image icon and changes the alternative text to indicate unavailability.
This is random selection, not guaranteed equal frequency over a short run. If you need every item once before any repeats, shuffle a copy of the array and consume it as a queue, reshuffling only when empty.
Remote images, CORS, and canvas
Displaying a cross-origin image and reading its bytes are different operations. A normal <img src="https://other.example/image.png"> can render without giving your JavaScript access to the pixels. If you draw that image to a canvas and call getImageData() or export the canvas, the canvas can become tainted unless the image server grants CORS permission. The details are covered in MDN’s cross-origin canvas guide.
Adding crossorigin="anonymous" changes the request to a CORS request. It does not bypass policy: if the server does not return an appropriate Access-Control-Allow-Origin header, the image may fail to load. Use that attribute only when the host is configured for it. For downloads, metadata requests, or image processing, fetch through your own server or use a source that explicitly supports the required CORS mode.
Content Security Policy (CSP)
A CSP response header controls which resources a browser may load. Permit only the image hosts you actually use with img-src; if img-src is absent, default-src governs images. For a local-only collection:
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteRank #3
Content-Security-Policy: default-src 'self'; img-src 'self'; script-src 'self'
For the example’s remote host, add it explicitly:
Content-Security-Policy: default-src 'self'; img-src 'self' https://cdn.example.com; script-src 'self'
Keep JavaScript in an external file if your policy disallows inline scripts. Avoid adding a broad wildcard merely to hide a failed request. MDN’s CSP reference explains directive behavior, and Mozilla’s Web Security Guidelines recommend CSP as a strong defense for new sites.
Accessibility and resilience checklist
- Write alt text that identifies the screen and its meaningful content, not “random screenshot.” If an image is purely decorative, use an empty
alt="". - Keep the “Show another” control a real button so it works with keyboard and assistive technology.
- Use
role="status"andaria-live="polite"for loading and error messages without stealing focus. - Provide intrinsic dimensions or an aspect-ratio container to prevent large layout shifts.
- Show a visible fallback when a request fails because of a network error, content blocker, expired URL, or hotlink protection. The alt text is also available when an image cannot load, as documented by MDN.
- Do not expose private screenshots, signed URLs, tokens, or personal data in client-side source.
Performance and update strategies
Keep the initial load small
Use appropriately sized WebP or JPEG files, responsive variants, and compression appropriate to the content. The browser downloads the selected image immediately in the example. If the image is below the fold, add loading="lazy"; do not lazy-load the primary image a visitor sees first.
Preload only when the first choice is known
A <link rel="preload" as="image" href="…"> helps only a predictable first image. Preloading every candidate wastes bandwidth and defeats random selection’s purpose. When visitors frequently click “Show another,” consider preloading one next candidate after the current image has loaded.
Recommended Free Tools
Rank #4
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
Cache deliberately
Serve stable local assets with long cache lifetimes and version their filenames when replacing them. For remote assets, follow the source server’s cache headers. If an API list changes, cache the list on your server for a defined interval rather than making every browser request the provider.
Prevent broken rotation
Validate entries when you publish them, monitor for HTTP failures, and remove URLs that require a login or reject embedding. A retry can help a transient network error, but repeated retries delay the fallback and do not solve authorization or hotlink restrictions.
Common failures and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Nothing appears and the console reports a CSP violation. | The image host is not in img-src. |
Add the exact permitted origin to CSP, or use a local asset. |
| The image displays, but canvas export throws a security error. | The cross-origin response lacks CORS permission. | Configure the image server’s Access-Control-Allow-Origin, use crossorigin="anonymous", or proxy through an authorized server. |
fetch() fails while a direct img works. |
Fetch is a script cross-origin read and is blocked by same-origin policy/CORS. | Enable CORS on the API, call it from your server, or keep a direct img URL. |
| Only some entries fail. | Bad paths, expired URLs, authentication, or hotlink protection. | Open each URL directly, check the Network panel, correct the path or permission, and retain the error fallback. |
| The page jumps when the screenshot changes. | Unknown or incorrect intrinsic dimensions. | Store accurate width and height per entry, or reserve space with CSS. |
| Every click shows the same item. | The collection has one entry, or the random index is not being recalculated. | Confirm the array length and call showRandom() inside the button handler. |
| Users see screenshots they should not access. | Sensitive files were shipped to a public array. | Remove private assets and enforce authorization server-side; client-side code cannot protect a URL it must download. |
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. A single request returns a PNG, JPEG, WebP, or PDF, so your site can display a generated result without maintaining browser automation. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and billing status. Its MCP tools—take_screenshot, get_page_info, and capture_pdf—let Claude, Cursor, or another MCP client take captures.
See the ScreenshotNeo documentation for authentication and options. This cURL example saves a WebP response:
Free tools Windows power users keep installed
One-click scans. No signup required.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
Every plan includes the capture options you may need: full-page shots with lazy images loaded, CSS-selector elements, device presets and custom viewports, dark mode, retina scale, PDF controls, custom CSS or JavaScript, clicks and waits, request/resource blocking, headers, cookies, user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, selectable-TTL caching, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage data, and an OpenAPI specification. Parameter names used by other screenshot APIs also work, which can simplify migration.
Best Value
The Free plan includes 1,000 screenshots each month with no card. Paid plans start at $5 for 3,000 shots; Growth is $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000. Yearly billing provides two months free, and every feature is on every plan. Create a free ScreenshotNeo account to get started.
FAQ
Can I choose a different screenshot every time the page opens?
Yes. The example calls showRandom() during initialization. Selection is made in the visitor’s browser, so it is independent for each page load.
Should I use background-image instead of <img>?
Use <img> for meaningful screenshot content because it supports alternative text, intrinsic dimensions, and image-specific loading behavior. Use a CSS background only when the image is decorative.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Can visitors see the list of screenshot URLs?
Yes. Anything sent to the browser can be inspected. Keep confidential images behind an authenticated server endpoint and do not place secrets in JavaScript.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

