Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To display a remote image, create an <img> element, set its src to the image URL, give it useful alternative text, and add it to the page. Use fetch() and a Blob URL instead when your code needs to inspect the response or handle HTTP errors. If you need to read or change image pixels with canvas, the image server must allow your page through CORS.

Display an image directly with img.src

For the common case—showing an image without inspecting its bytes—the browser can load the URL directly. This works with an existing image element or one created in JavaScript.

Use an image already in the page

Given <img id="preview" alt="">, assign its source and an appropriate description:

const img = document.querySelector('#preview');
img.alt = 'A mountain lake at sunrise';
img.src = 'https://example.com/photo.jpg';

Create and append the image

When the page does not already contain an image element, create one and append it to a container:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const img = document.createElement('img');
img.src = 'https://example.com/photo.jpg';
img.alt = 'A mountain lake at sunrise';
document.querySelector('#preview').append(img);

The container must exist when this code runs. For example, place the script after the container in the HTML, or run the code after the document has loaded. The equivalent new Image() constructor creates an image element that is initially detached; assign its source and append it when you want it to appear. See MDN’s Image() constructor documentation.

Show loading and failure states

Image loading is asynchronous. Attach event handlers if the interface needs to tell the user whether the request succeeded:

const img = new Image();
img.alt = 'A mountain lake at sunrise';
img.onload = () => console.log(`Loaded ${img.naturalWidth} × ${img.naturalHeight}`);
img.onerror = () => console.error('The image could not be loaded or decoded.');
img.src = 'https://example.com/photo.jpg';
document.querySelector('#preview').append(img);

Set src after registering the handlers so they are in place before loading begins. A failed load can result from a missing resource, access restrictions, an unsupported or invalid image response, or a network problem. The URL’s file extension alone does not guarantee that the server returns decodable image data.

Fetch the image and display a Blob URL

Choose Fetch when JavaScript must check the HTTP status, examine response headers, or work with the downloaded bytes before showing the image. fetch() returns a response; response.blob() asynchronously reads its body into a Blob; and URL.createObjectURL() creates a temporary URL that an image element can use. See MDN’s Fetch API documentation and Response.blob().

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
async function showFetchedImage(url, img) {
  const response = await fetch(url);
  if (!response.ok) {
    throw new Error(`Image request failed: HTTP ${response.status}`);
  }

  const blob = await response.blob();
  const objectUrl = URL.createObjectURL(blob);
  img.alt = 'A mountain lake at sunrise';
  img.src = objectUrl;
  return objectUrl;
}

const img = document.querySelector('#preview');
showFetchedImage('https://example.com/photo.jpg', img)
  .then((objectUrl) => {
    // Save objectUrl if you need to revoke it when replacing or removing the image.
  })
  .catch((error) => console.error(error));

Check response.ok before converting the body. Fetch can fulfill with an HTTP error response such as 404; checking the status makes that failure explicit rather than attempting to display an error page as an image. You can inspect headers such as Content-Type before calling blob() if your application needs to validate the response.

Revoke temporary object URLs

A Blob URL is temporary and remains associated with its Blob until released. Revoke it when the image is no longer in use—for example, after replacing the image or removing it from the page. Do not revoke it immediately after setting img.src, because the image may not have finished loading.

let currentObjectUrl;

async function replaceWithFetchedImage(url, img) {
  const response = await fetch(url);
  if (!response.ok) throw new Error(`HTTP ${response.status}`);

  const blob = await response.blob();
  const nextObjectUrl = URL.createObjectURL(blob);
  const previousObjectUrl = currentObjectUrl;

  img.onload = () => {
    if (previousObjectUrl) URL.revokeObjectURL(previousObjectUrl);
  };
  img.onerror = () => {
    URL.revokeObjectURL(nextObjectUrl);
  };

  currentObjectUrl = nextObjectUrl;
  img.src = nextObjectUrl;
}

// When the image is permanently removed:
function removePreview(img) {
  img.remove();
  if (currentObjectUrl) {
    URL.revokeObjectURL(currentObjectUrl);
    currentObjectUrl = undefined;
  }
}

For a simple one-time display, direct img.src avoids the extra Fetch and object-URL lifecycle. Use the Blob route when its response-handling capabilities matter.

Use a remote image with canvas

Displaying a remote image and accessing its pixels are different operations. A browser generally permits an image to appear in an <img> even when the image comes from another origin. But drawing a cross-origin image without CORS approval taints the canvas: JavaScript cannot then read pixels or export the canvas using methods such as getImageData(), toBlob(), or toDataURL(). MDN explains the restriction in its CORS-enabled images guide.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For pixel access, the image server must return an Access-Control-Allow-Origin header authorizing your page’s origin (or an appropriate wildcard response). Set crossOrigin before assigning src so the browser requests the image in CORS mode:

const img = new Image();
img.crossOrigin = 'anonymous'; // Set before src.
img.onload = () => {
  const canvas = document.querySelector('canvas');
  canvas.width = img.naturalWidth;
  canvas.height = img.naturalHeight;
  const context = canvas.getContext('2d');
  context.drawImage(img, 0, 0);

  // These operations require the canvas to remain origin-clean:
  const pixels = context.getImageData(0, 0, canvas.width, canvas.height);
};
img.onerror = () => console.error('Image load or CORS request failed.');
img.src = 'https://cdn.example.com/photo.jpg';

crossOrigin = 'anonymous' does not grant permission by itself; the remote server must still authorize the request. If it does not, the browser may block the CORS-mode image request. Setting the property after src is too late to affect the request already started.

Choose the right approach

Approach Best for HTTP handling and byte access CORS and cleanup
Direct img.src Showing an image as simply as possible Does not expose a Fetch response for status checks or byte inspection. Cross-origin display usually needs no pixel-access permission; canvas pixel reads still require CORS approval.
fetch() → Blob → object URL Checking status or headers, or obtaining binary data before display JavaScript can check response.ok and process the Blob. Revoke the object URL when it is no longer needed. Fetching a cross-origin resource is subject to CORS.
Canvas with a CORS-enabled image Transforming or reading image pixels Canvas APIs can work with pixels only when the canvas remains origin-clean. The image server must grant CORS permission, and crossOrigin must be set before src.

There is no universal performance winner established for every browser and network. Direct embedding is the shortest path when display is all you need; Fetch and canvas add work for specific capabilities.

Accessibility and display details

  • Write useful alternative text. Set alt to a concise description that conveys the image’s purpose. If the image is decorative and adds no information, use an empty alternative text value (alt=""). See W3C’s Images Tutorial.
  • Handle both outcomes when the UI depends on them. Use load and error events for status messages, retries, or replacement content.
  • Do not infer format from the URL alone. The response must contain image data the browser can decode; redirects or an HTML error page can make a URL ending in .jpg fail to display.
  • Size the rendered element deliberately. CSS controls how the image fits the layout, while naturalWidth and naturalHeight report its intrinsic dimensions after loading.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot common failures

The image does not appear

Confirm that the element exists, the container selector matches, and the assigned URL is reachable. Inspect the browser’s Network panel for the final response status and content type. A server may redirect to a page, require authentication, return an error, or send bytes the browser cannot decode. Register an error handler to expose load failure in the interface.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Fetch reports a CORS error

Direct image embedding can work while Fetch fails because Fetch gives JavaScript access to the response and is governed by cross-origin rules. The image server must send CORS headers permitting your site to fetch it. Client-side JavaScript cannot override the remote server’s policy. If you only need visual display, use direct img.src; if your code needs the response or pixels, use a server that permits the required access.

The image displays but canvas export or pixel reading throws

The canvas was tainted by drawing an image without CORS approval. Configure the remote server to authorize your origin, then set img.crossOrigin = 'anonymous' before img.src and load the image again. An already-tainted canvas cannot be made origin-clean by changing the image element afterward.

Fetch returns an HTTP error or a Blob that will not display

Check response.ok and the status before reading the body. If the request succeeds but display still fails, inspect the response’s Content-Type and verify that its bytes are a supported image rather than HTML or another payload.

Memory use grows after repeatedly replacing images

Revoke each Blob URL once the corresponding image is no longer needed. Keep the current URL in state so it can be released when the image is replaced or removed; avoid revoking it before the image has loaded.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Or skip the browser setup

If the task is to capture a website as an image rather than display an existing image URL, ScreenshotNeo provides a screenshot API. One GET request returns a PNG, JPEG, WebP, or PDF. For example, use cURL to capture a page as WebP:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options. ScreenshotNeo removes cookie banners, popups, and chat widgets before a capture; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The Free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000. Learn about ScreenshotNeo, or sign up for 1,000 free 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.