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

In browser JavaScript, use fetch() to request the image, check response.ok, read the response with response.blob(), and pass that Blob to the File constructor. The result is a named File suitable for upload controls, FormData, and APIs that require a file rather than a URL.

async function imageUrlToFile(url, filename) {
  const response = await fetch(url);
  if (!response.ok) {
    throw new Error(`Image request failed: ${response.status}`);
  }

  const blob = await response.blob();
  return new File([blob], filename, {
    type: blob.type || "application/octet-stream",
    lastModified: Date.now(),
  });
}

The important limitation is cross-origin access: the image server must allow your page through CORS. Setting mode: "no-cors" does not make the response readable.

The basic URL-to-File conversion

fetch() resolves for many HTTP error responses, so status checking belongs before reading the body. A successful response is converted to a Blob, then wrapped in a File with the filename and metadata you choose.

async function imageUrlToFile(url, filename) {
  const response = await fetch(url);

  if (!response.ok) {
    throw new Error(`Image request failed: ${response.status} ${response.statusText}`);
  }

  const blob = await response.blob();

  return new File([blob], filename, {
    type: blob.type || "application/octet-stream",
    lastModified: Date.now(),
  });
}

const file = await imageUrlToFile(
  "https://example.com/images/avatar.jpg",
  "avatar.jpg"
);
console.log(file.name, file.type, file.size);

The function returns a Promise because both the network request and body read are asynchronous. The fallback MIME type is only metadata; it does not prove that the bytes are really an image.

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

Blob, File and object URL: choose the right result

Blob

A Blob is the binary data returned by response.blob(). Use it when an API accepts raw binary data, when you need to inspect the response, or when a filename is irrelevant.

File

A File is Blob data plus a name and optional type and lastModified values. Use it for upload workflows that expect a file-like object, such as FormData.append() or a component that reads input.files.

Object URL

URL.createObjectURL(blob) creates a temporary local URL for previews. It is not a File and does not upload anything by itself. Revoke it only after the preview is no longer needed.

const file = await imageUrlToFile(url, "photo.webp");
const previewUrl = URL.createObjectURL(file);

const image = document.querySelector("img");
image.src = previewUrl;

// Later, when the preview is removed:
URL.revokeObjectURL(previewUrl);

Revoking immediately after assigning src can break later rendering or interactions. Keep the URL alive for the lifetime of the preview.

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

Upload the resulting File

Once you have a File, append it to FormData just as you would a file selected by a user.

async function uploadImageFromUrl(imageUrl) {
  const file = await imageUrlToFile(imageUrl, "downloaded-image.jpg");
  const form = new FormData();
  form.append("image", file, file.name);

  const response = await fetch("/api/upload", {
    method: "POST",
    body: form,
  });

  if (!response.ok) {
    throw new Error(`Upload failed: ${response.status}`);
  }

  return response.json();
}

Do not manually set the Content-Type header when sending FormData; the browser adds the multipart boundary.

Choose a safe filename and MIME type

Do not assume the URL extension identifies the actual format. URLs may be extensionless, encoded, redirected, or point to a dynamically generated image. Supply a filename explicitly and prefer the server-provided Blob type.

function extensionForType(type) {
  const extensions = {
    "image/jpeg": ".jpg",
    "image/png": ".png",
    "image/webp": ".webp",
    "image/gif": ".gif",
    "image/avif": ".avif",
  };
  return extensions[type] || "";
}

async function imageUrlToNamedFile(url, baseName = "image") {
  const response = await fetch(url);
  if (!response.ok) throw new Error(`Image request failed: ${response.status}`);

  const blob = await response.blob();
  const suffix = extensionForType(blob.type);
  return new File([blob], `${baseName}${suffix}`, {
    type: blob.type || "application/octet-stream",
    lastModified: Date.now(),
  });
}

For untrusted input, validate the content and impose an application-appropriate size limit before storing or processing it. A declared type alone is not content validation.

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

Cancellation, timeouts and useful errors

Pass an AbortSignal when users can cancel a download or when your interface has a deadline.

async function imageUrlToFile(url, filename, { signal, type } = {}) {
  let response;
  try {
    response = await fetch(url, { signal });
  } catch (error) {
    if (error.name === "AbortError") {
      throw new Error("Image download was cancelled");
    }
    throw new Error(`Image request could not be completed: ${error.message}`);
  }

  if (!response.ok) {
    throw new Error(`Image request failed: ${response.status}`);
  }

  const blob = await response.blob();
  return new File([blob], filename, {
    type: type || blob.type || "application/octet-stream",
    lastModified: Date.now(),
  });
}

const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 15000);
try {
  const file = await imageUrlToFile(url, "image.jpg", {
    signal: controller.signal,
  });
  console.log(file);
} finally {
  clearTimeout(timer);
}

Cross-origin images and CORS

A same-origin image normally works without special configuration. For a different origin, the image server must include a CORS response permission for your page’s origin. Without that permission, browser JavaScript cannot read the response body or headers.

What the browser error means

A CORS error is a server-policy failure, not a problem that can be fixed by changing the filename or by converting the response differently. The remote server must send an appropriate Access-Control-Allow-Origin response, or your own server must fetch the image.

Why no-cors is not a workaround

fetch(url, { mode: "no-cors" }) returns an opaque response for a disallowed cross-origin request. Its body and headers are unavailable to JavaScript, so you cannot call blob() to obtain usable image bytes.

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

Same-origin proxy option

If you control a backend, have it fetch only authorized URLs and expose a same-origin endpoint to the browser. Restrict destinations, validate redirects, enforce response-size limits, and avoid turning the endpoint into an unrestricted server-side request forgery proxy.

Browser versus server-side JavaScript

This recipe targets browsers, where fetch, Blob and File are available according to the runtime and browser version. Server runtimes differ: some provide fetch and Blob, while a File implementation may be absent or runtime-specific. If the receiving API accepts binary data, a server may only need the response bytes and a separately supplied filename. Verify the APIs supported by your chosen runtime before reusing browser code unchanged.

Common failures and fixes

HTTP 404, 403 or 500

Cause: the server returned an error response, which still resolves from fetch.
Fix: check response.ok, log the status, and verify the URL, authentication and remote access rules.

“Failed to fetch” or a CORS console message

Cause: the browser was not permitted to read the cross-origin response, or a network/TLS failure occurred.
Fix: enable CORS on the image host or fetch through a controlled same-origin backend. Do not use no-cors when you need the bytes.

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

The resulting File has an empty or unexpected type

Cause: the server omitted or misreported Content-Type, or the caller supplied a generic fallback.
Fix: treat the type as metadata, validate the actual content where required, and assign a type accepted by the destination only after validation.

The upload rejects the object

Cause: the endpoint may require a particular field name, extension, size, or MIME type.
Fix: inspect the API contract, pass the filename as the third argument to form.append, and enforce its limits before uploading.

The browser runs out of memory

Cause: the entire response is held in memory as Blob/File data, potentially alongside a preview and upload copy.
Fix: impose size limits, avoid duplicate conversions, release object URLs, and use a server-side or streaming design for very large assets.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance, reliability and security checklist

  • Use a reasonable request timeout and an AbortController.
  • Check status before reading the body.
  • Choose the filename instead of trusting a URL path.
  • Limit download size when the URL is user-controlled.
  • Validate image content before storing, transforming or displaying untrusted data.
  • Use a controlled proxy only for destinations your application is authorized to retrieve.
  • Reuse the File directly instead of converting Blob to data URLs unless a data URL is specifically required.
  • Revoke preview object URLs when the preview is discarded.

Or skip the browser setup

If the image you need is a webpage screenshot rather than an existing image asset, ScreenshotNeo returns a clean PNG, JPEG, WebP or PDF from one request. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; bot checks, blank pages, failed loads and cache hits are not billed, and response headers identify the page verdict and billing result.

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

cURL:

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

JavaScript (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(`Screenshot failed: ${res.status}`);
const bytes = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', bytes);

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)

See the ScreenshotNeo documentation for options such as full-page and element capture, device and retina settings, custom CSS or JavaScript, waiting rules, headers, cookies, geolocation, PDF output, caching, signed links, asynchronous webhooks and bulk capture. Its MCP server provides take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Create a free ScreenshotNeo account.

Frequently Asked Questions

Can I convert an image URL directly to a File without fetch?

Not in browser JavaScript. The browser must obtain the image bytes first; fetch followed by Blob and File is the standard path.

Should I return a Blob or a File from my helper?

Return a File when the consumer needs a filename or file metadata. Return a Blob when it only needs binary data or a preview.

Can I preserve the original filename from the URL?

You can derive a candidate name, but URL paths are not reliable evidence. Supplying an explicit safe filename is more predictable.

Free tools Windows power users keep installed

One-click scans. No signup required.

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

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.