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.
#1 Best Overall
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.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Rank #2
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.
Recommended Free Tools
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.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsRank #4
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.
Best Value
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.
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.
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.
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.

