For an image you only need to display, create an <img>, set its src to the image URL, give it useful alt text, and add it to the page. Use fetch() and a Blob URL instead when JavaScript must inspect the response or work with the image bytes. If you need to read or export pixels through a canvas, the image host must allow your page’s origin with CORS.
Display an image by setting img.src
The simplest approach is to let the browser load the remote image as an image resource. You do not need to download it yourself with JavaScript first. Create an image element, set its URL and alternative text, then append it to a container that already exists in the document:
const img = document.createElement('img');
img.src = 'https://example.com/photo.jpg';
img.alt = 'A description of the image';
document.querySelector('#preview').append(img);
In this example, replace the illustrative URL with a URL that returns an image the browser can decode, and make sure the page contains an element with id="preview". Setting src starts the image load; appending the element puts it in the document so it can be displayed. If the container might not exist yet, run the code after the relevant HTML is available, or select the container after your page has finished constructing it.
Use new Image() when you want to prepare an image first
new Image() creates an HTMLImageElement that starts detached from the document. You can attach event handlers before assigning its source, then append it after it loads:
#1 Best Overall
const img = new Image();
img.alt = 'A description of the image';
img.addEventListener('load', () => {
document.querySelector('#preview').replaceChildren(img);
});
img.addEventListener('error', () => {
document.querySelector('#preview').textContent = 'The image could not be loaded.';
});
img.src = 'https://example.com/photo.jpg';
This variation lets the interface wait for a successful load before replacing its current contents. If the image is already cached, the load can complete quickly, so install the handlers before setting src. For a simple page that can show the image as soon as it is available, appending the element immediately is also fine.
Show loading and failure states
A URL does not guarantee that the browser will receive a usable image. The server may be unavailable, the URL may be wrong, the response may be HTML instead of image data, or the bytes may not be a format the browser can decode. Attach load and error handlers when users need feedback rather than an unexplained blank area.
const preview = document.querySelector('#preview');
const status = document.querySelector('#image-status');
const img = new Image();
img.alt = 'A description of the image';
img.addEventListener('load', () => {
status.textContent = '';
});
img.addEventListener('error', () => {
status.textContent = 'Image unavailable. Check the address or try again.';
});
status.textContent = 'Loading image…';
img.src = 'https://example.com/photo.jpg';
preview.replaceChildren(img);
Here, #image-status should be a visible status element in your HTML and #preview should be the image container. A load event means the browser successfully loaded and decoded the image; an error event does not by itself tell you whether the cause was a bad URL, an inaccessible server, a blocked request, or an unsupported response. Use the browser’s Network and Console panels to investigate the specific failure.
Rank #2
Fetch the response and display it as a Blob
Direct assignment is not the right choice if your code must check the HTTP status, inspect response headers, or process the binary response before displaying it. In that case, fetch the resource, check response.ok, convert the response to a Blob, and create a temporary blob: URL:
async function showFetchedImage(imageUrl) {
const response = await fetch(imageUrl);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const blob = await response.blob();
const objectUrl = URL.createObjectURL(blob);
const img = document.querySelector('#preview');
img.alt = 'A description of the image';
img.src = objectUrl;
return objectUrl;
}
showFetchedImage('https://example.com/photo.jpg').catch((error) => {
console.error('Could not load image:', error);
});
fetch() and response.blob() are asynchronous, so the function waits for the network response and conversion before assigning the object URL. Checking response.ok is important: Fetch does not treat every HTTP error status as a rejected promise. Without the check, an error page could be read as a Blob and then fail later when the browser tries to display it.
Revoke object URLs when you replace or remove an image
An object URL refers to a Blob held by the browser. Keep track of the URL you created and revoke it when the image is no longer needed. For example, when replacing an image, wait for the next one to load before revoking the old URL:
let currentObjectUrl = null;
async function replaceWithFetchedImage(imageUrl) {
const response = await fetch(imageUrl);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const blob = await response.blob();
const nextObjectUrl = URL.createObjectURL(blob);
const img = document.querySelector('#preview');
img.alt = 'A description of the image';
img.addEventListener('load', () => {
if (currentObjectUrl) URL.revokeObjectURL(currentObjectUrl);
currentObjectUrl = nextObjectUrl;
}, { once: true });
img.addEventListener('error', () => {
URL.revokeObjectURL(nextObjectUrl);
}, { once: true });
img.src = nextObjectUrl;
}
function removePreview() {
document.querySelector('#preview').removeAttribute('src');
if (currentObjectUrl) {
URL.revokeObjectURL(currentObjectUrl);
currentObjectUrl = null;
}
}
Call removePreview() when the displayed image is being removed. If you create object URLs repeatedly and never revoke them, the browser may retain the associated resources longer than needed. Do not revoke a URL while the image is still meant to be displayed or used.
Direct image loading versus Fetch and Blob URLs
| Approach | Best for | HTTP handling in JavaScript | Cleanup |
|---|---|---|---|
Set img.src |
Displaying an image with minimal code | Not through a Fetch response; use image load/error events | No Blob object URL to revoke |
fetch() → blob() → object URL |
Checking status, inspecting headers, or processing response bytes | Can inspect the response and check response.ok, subject to browser CORS rules |
Revoke each created object URL when finished |
| Canvas after loading an image | Drawing, transforming, or reading image pixels | Canvas access depends on the image request and the server’s CORS permission | No object URL required for a direct image URL; revoke one if the input came from a Blob URL |
There is no universal performance winner established for every browser, network, and image. Choose the direct element path unless you have a concrete need to handle the response as data; each extra step adds work and, for Blob URLs, a cleanup responsibility.
Free tools Windows power users keep installed
One-click scans. No signup required.
Cross-origin images and canvas access
A browser can generally display a remote image in an <img> without giving JavaScript permission to read its pixels. Those are different capabilities. If you draw an image from another origin onto a canvas without CORS approval, the canvas becomes tainted; calls such as getImageData(), toBlob(), or toDataURL() then raise a SecurityError.
Rank #4
For canvas pixel access, the image server must send a CORS response authorizing your page’s origin. Set crossOrigin before src so the browser makes a CORS-enabled image request:
const img = new Image();
img.crossOrigin = 'anonymous'; // Set before src.
img.addEventListener('load', () => {
const canvas = document.querySelector('canvas');
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
const context = canvas.getContext('2d');
context.drawImage(img, 0, 0);
// Pixel reads and canvas exports are permitted only if the server
// authorized this page's origin through its CORS response.
});
img.addEventListener('error', () => {
console.error('Image load failed, or the server did not allow the CORS request.');
});
img.src = 'https://cdn.example.com/photo.jpg';
anonymous does not bypass the server’s policy. If the remote server does not provide the required CORS permission, the CORS image request can fail. Setting crossOrigin after src is too late for that request; assign it first. If you only need to display the image, omit crossOrigin and do not draw it into a canvas.
Accessibility and display details
- Write meaningful alternative text. Set
alton dynamically created images. Describe the image’s purpose or equivalent content; if the image is purely decorative and conveys no information, usealt="". - Keep image sizing intentional. Use CSS such as
max-width: 100%; height: auto;when the image should fit its container while retaining its proportions. - Use image load events for interface state. Show a loading message only if the delay matters to the interface, and provide a useful failure message rather than leaving users with a blank preview.
- Do not infer format from the filename. A URL ending in
.jpgis not proof that the response contains a valid JPEG; the actual response and browser decoder determine whether it displays. - Use the correct kind of URL. The
srcshould resolve to image data, not a web page that happens to contain an image. A page URL may render as HTML and cannot be displayed as the image itself.
Troubleshooting common failures
The image area stays blank
Check that the selected container exists, that the code runs after it is available, and that the image URL is correct. Inspect the Network panel to see whether the request succeeded and what content was returned. Add an error handler so the interface can distinguish a failed load from a merely empty container.
Recommended Free Tools
Best Value
The response is an error page or the URL opens a web page
Use a direct image resource rather than a page URL. With the Fetch approach, check response.ok before converting the response to a Blob. With direct img.src, the image’s error event is the available element-level signal; inspect the request in developer tools for the HTTP status and response content.
fetch() fails but the same address displays in an image element
Displaying an image and reading its response with JavaScript have different cross-origin rules. A remote image may appear in an <img> while a script’s Fetch request is blocked because the server did not authorize your origin for that request. Configure the image server’s CORS response if you control it. If you only need display, use direct img.src and avoid Fetch.
The image displays, but canvas reads or exports throw SecurityError
The canvas is tainted because the image was loaded without valid CORS approval. Set img.crossOrigin = 'anonymous' before img.src, and ensure the server sends a CORS response that authorizes your origin. Client-side code cannot grant itself permission to read another server’s pixels.
A Blob URL stops working after an image replacement
Check whether the old URL was revoked before the image finished using it, or whether a URL was revoked and then reused. Create a fresh object URL for each new Blob, assign it to the image, and revoke it after the replacement has loaded or the image has been removed.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, 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 minuteOr skip the browser setup
If your goal is a screenshot of a web page rather than displaying one image file in your page, ScreenshotNeo is a website screenshot API and MCP server. It is not a substitute for setting an image element’s src; it captures a page and returns an image or PDF. For example, this cURL request saves a screenshot of a web page as WebP. See the ScreenshotNeo API documentation for request options and setup.
Quick Recap
curl -G "https://api.screenshotneo.com/v1/shot"
-d access_key=YOUR_API_KEY
--data-urlencode url=https://stripe.com
-o shot.webp
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture; each of those steps can be turned off. Bot checks, blank pages, and failed loads are not billed, and responses include page-verdict and billing headers. Its MCP server lets AI agents use screenshot tools. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Sign up for free and get 1,000 screenshots a month with no card.
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.




