How to Convert an Image to Base64 HTML Code
Convert local files or canvas images into Base64 data URLs, embed them in HTML, handle errors, and choose safer options for large images.
Short answer: an image embedded as Base64 HTML is usually a data URL in this form:
data:[media-type];base64,[encoded-data]
For a file selected in the browser, call FileReader.readAsDataURL(file). For an image already drawn on a canvas, call canvas.toDataURL(). Put the returned value directly in an image element:
<img src="data:image/png;base64,iVBORw0KGgo..." alt="Embedded image">
Keep the data:image/...;base64, prefix when the value is used as an HTML src. Remove everything through the first comma only when another API explicitly asks for the bare Base64 payload.
1. Understand the data URL format
A data URL contains a media type, an encoding marker, and the encoded bytes:
data:image/png;base64,ENCODED_BYTES
data:identifies the URL scheme.image/pngis the MIME type. Use the actual type when known, such asimage/jpegorimage/webp.base64says that the payload is Base64 encoded.- The text after the comma is the encoded image data.
The browser can use the complete string anywhere an image URL is accepted, including <img src>, CSS backgrounds, and canvas image sources. See the data URL specification and MDN’s data URL reference.
2. Convert a selected local image with FileReader
Use FileReader.readAsDataURL() when the input is a browser File or Blob. Reading is asynchronous; the result is available after the load event fires.
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>Image to Base64 data URL</title>
<input id="file" type="file" accept="image/*">
<img id="preview" alt="Selected image preview">
<textarea id="output" rows="8" cols="80" readonly></textarea>
<script>
const input = document.querySelector('#file');
const preview = document.querySelector('#preview');
const output = document.querySelector('#output');
input.addEventListener('change', () => {
const file = input.files[0];
if (!file) return;
if (!file.type.startsWith('image/')) {
output.value = 'Choose an image file.';
return;
}
const reader = new FileReader();
reader.addEventListener('load', () => {
const dataUrl = reader.result;
preview.src = dataUrl;
output.value = dataUrl;
});
reader.addEventListener('error', () => {
output.value = 'The browser could not read this file.';
});
reader.readAsDataURL(file);
});
</script>
This follows the browser API documented by MDN’s readAsDataURL() reference. The returned value is already a complete data URL, so it can be assigned directly to src.
Get only the Base64 payload
If a service requires only the encoded bytes, split at the first comma:
const dataUrl = reader.result;
const base64 = dataUrl.substring(dataUrl.indexOf(',') + 1);
Do not do this for an HTML image source. Without the prefix, the browser does not know the media type or that the value is Base64.
3. Convert an existing canvas image
Use canvas.toDataURL() when the image is already on a canvas or needs cropping, drawing, filtering, or other transformations first.
<canvas id="canvas" width="640" height="360"></canvas>
<img id="result" alt="Canvas export">
<script>
const canvas = document.querySelector('#canvas');
const context = canvas.getContext('2d');
const image = new Image();
image.onload = () => {
context.drawImage(image, 0, 0, canvas.width, canvas.height);
const dataUrl = canvas.toDataURL('image/jpeg', 0.85);
document.querySelector('#result').src = dataUrl;
};
image.src = '/images/example.jpg';
</script>
PNG is the default export format. JPEG and WebP support depends on the browser. For supported lossy formats, the quality argument is between 0 and 1. Always inspect the returned prefix when requesting an optional format:
const dataUrl = canvas.toDataURL('image/webp', 0.8);
if (dataUrl.startsWith('data:image/png')) {
console.log('WebP was not supported; the browser returned PNG.');
}
See MDN’s toDataURL() documentation for the format and quality behavior.
4. Complete examples in Python and Node.js
Python: read a file and create a data URL
from base64 import b64encode
from pathlib import Path
path = Path("photo.png")
mime_type = "image/png"
encoded = b64encode(path.read_bytes()).decode("ascii")
data_url = f"data:{mime_type};base64,{encoded}"
html = f'<img src="{data_url}" alt="Embedded image">'
Path("output.html").write_text(html, encoding="utf-8")
print(data_url[:80] + "...")
Set mime_type to match the actual file. This example writes a standalone HTML file containing the image.
Node.js: read a file and create a data URL
import { readFile } from 'node:fs/promises';
const bytes = await readFile('photo.png');
const mimeType = 'image/png';
const dataUrl = `data:${mimeType};base64,${bytes.toString('base64')}`;
console.log(dataUrl);
In a CommonJS project, use const fs = require('node:fs'); and fs.readFileSync('photo.png').toString('base64').
cURL: download an image before encoding it locally
cURL itself transfers bytes; use your shell’s Base64 utility to encode the downloaded file:
curl -L "https://example.com/photo.png" -o photo.png
printf 'data:image/png;base64,' > image-data-url.txt
base64 < photo.png | tr -d '\n' >> image-data-url.txt
Change the MIME type to match the downloaded resource. Validate the response before encoding when the URL may return an HTML error page instead of an image.
5. Choose FileReader or canvas
| Input and goal | Recommended method | Reason |
|---|---|---|
| User-selected local file | FileReader.readAsDataURL() |
Produces the complete data URL directly. |
| Image already drawn to canvas | canvas.toDataURL() |
Exports the current bitmap, including edits. |
| Crop, resize, or filter before embedding | Canvas, then toDataURL() |
Transform the pixels before encoding. |
| Large image | toBlob() plus an object URL, or a normal image URL |
Avoids one huge in-memory string and keeps assets manageable. |
6. HTML and CSS embedding patterns
Image element
<img src="data:image/jpeg;base64,/9j/4AAQ..." alt="Product photo">
CSS background
.hero {
background-image: url("data:image/svg+xml;base64,PHN2Zy...");
}
Canvas as an image source
const image = new Image();
image.src = canvas.toDataURL();
Escape the value appropriately when inserting it into HTML attributes or CSS generated from untrusted input. Do not concatenate untrusted strings into markup without normal validation and escaping.
7. Large images, memory, and caching
Base64 data URLs are convenient for small, self-contained assets. They duplicate the encoded image inside the HTML or CSS document, so a large image creates a large string in memory and makes the document harder to cache independently. MDN warns that toDataURL() materializes the entire image in an in-memory string and recommends toBlob() for large images.
canvas.toBlob((blob) => {
if (!blob) throw new Error('Canvas export failed');
const objectUrl = URL.createObjectURL(blob);
document.querySelector('#result').src = objectUrl;
// Call URL.revokeObjectURL(objectUrl) when the image is no longer needed.
}, 'image/jpeg', 0.85);
Use a regular URL when independent browser caching, responsive images, or content management matters. Use a data URL when portability or a single self-contained HTML document is more important.
8. Cross-origin canvas errors
A canvas becomes not origin-clean when it draws cross-origin content without the required permission headers. Calling toDataURL() on such a canvas can throw a SecurityError. Load an image with the correct CORS mode and ensure the image server sends an appropriate Access-Control-Allow-Origin header:
const image = new Image();
image.crossOrigin = 'anonymous';
image.onload = () => {
context.drawImage(image, 0, 0);
const dataUrl = canvas.toDataURL();
};
image.src = 'https://static.example.com/photo.jpg';
The server must opt in to that origin; setting crossOrigin alone cannot bypass the restriction.
9. Troubleshooting checklist
| Symptom | Likely cause | Fix |
|---|---|---|
| The image is broken | The data URL prefix is missing or the MIME type is wrong. | Keep data:image/type;base64, and verify the file type. |
| The output is empty | The code reads reader.result before the load event. |
Use the result inside the completion handler. |
Canvas export throws SecurityError |
The canvas contains cross-origin pixels. | Use CORS-enabled resources and set crossOrigin before src. |
| Requested WebP or JPEG becomes PNG | The browser does not support that export type. | Inspect the returned prefix and accept PNG or choose another supported type. |
| The page becomes slow | A large image was materialized as a Base64 string. | Use toBlob(), an object URL, or a separate image resource. |
| Only a backend accepts the value | It expects raw Base64 rather than a data URL. | Remove the prefix through the first comma and send the remaining payload. |
| Encoded output is corrupted | Binary bytes were decoded as text or line breaks were inserted. | Read bytes directly and use a binary-safe Base64 encoder. |
10. Security and reliability considerations
- Validate the selected file type and size before reading it.
- Do not treat a client-supplied MIME type as proof of the file’s contents on a server.
- Remember that Base64 is encoding, not encryption. Anyone who receives the HTML can decode the image.
- For user-generated HTML, escape attribute content and apply your normal content-security policy.
- Handle
FileReadererrors and null results rather than assuming every read succeeds. - For canvas workflows, wait for image loading before drawing and exporting.
11. Or skip the browser setup
If your actual goal is to obtain a clean image of a web page or HTML output, ScreenshotNeo provides a website screenshot API and MCP server. It accepts one GET request and returns PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation for all options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server lets Claude, Cursor, and other MCP clients call take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
12. FAQ
Is Base64 the same as a data URL?
No. Base64 is the encoded payload. A data URL wraps that payload with the media type and encoding declaration so it can be used as an image URL.
Can I convert an image without uploading it?
Yes. FileReader reads a local browser file, and canvas APIs export pixels already loaded in the page.
Why does my Base64 image work in an image tag but not in JSON?
Your JSON consumer may require the bare payload, may reject very large strings, or may require a separate MIME-type field. Check that API’s contract before removing the data URL prefix.
Which format should I choose?
Use PNG when lossless output or transparency matters. Use JPEG or WebP when the browser supports it and a smaller lossy image is acceptable. Confirm the returned prefix because unsupported requests can fall back to PNG.
Should every image be embedded as Base64?
No. Inline data URLs suit small, self-contained assets. Use a normal URL or a Blob object URL for large images or assets that should be cached separately.


