Skip to content

Image to Base64

Convert an image file to a Base64 data URL for embedding in HTML or CSS.

🖼️

Drop an image here or click to browse

Supports JPG, PNG, WebP, GIF, BMP, SVG

This tool encodes an image file as a base64 string formatted as a data: URI you can drop into an HTML <img> tag or a CSS background-image declaration. The encoding happens entirely in your browser; the image never leaves your machine.

What a data URI looks like

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGNgAAIAAAUAAeImBZsAAAAASUVORK5CYII=">

Three parts after data::

  1. MIME type — image/png, image/jpeg, image/gif, image/svg+xml, image/webp. Tells the browser how to decode the bytes.
  2. ;base64 — the encoding marker. Without it the data is interpreted as URL-encoded text, not base64.
  3. The encoded payload — the image bytes encoded with base64.

The result is a single self-contained string that the browser renders as the image with no separate HTTP request.

Where data URIs make sense

  • Tiny inline icons. A 200-byte SVG arrow as a CSS list-style-image saves a request and renders without flicker. The base64 overhead at this size is meaningless.
  • Email HTML. Many email clients block external images (privacy heuristics) but render data URIs. Critical icons in marketing emails sometimes ship as data URIs for this reason.
  • Single-file HTML deliverables. A self-contained index.html that opens correctly when emailed or downloaded — no external assets means no broken images.
  • Build-time inlining of small assets. Webpack’s url-loader/asset/inline and Vite’s assetsInlineLimit (default 4KB) automatically inline small images as data URIs. The threshold is the size at which the inline cost is less than the request cost.

Where data URIs hurt

  • Anything cacheable. A standalone logo.png is cached by the browser after the first request and reused on every page. A data URI is duplicated into every HTML or CSS file that references it — bytes downloaded fresh each time.
  • Anything parseable. A 2 MB base64 string in HTML pushes the HTML parse work way up. The DOM is heavier, JavaScript that walks it is slower, and DevTools choke on it.
  • Anything you’d want to lazy-load. Inline images load with the page. A 100 KB image as a data URI is 100 KB of critical-path payload; as a separate file it can be loading="lazy".
  • Anything you might re-process. Server-side image optimization, CDN compression, format negotiation (WebP fallbacks) — all of these expect a separate file. Inline data URIs bypass them.

The size break-even

Rule of thumb: inline files smaller than ~2 KB; serve everything larger as a file. The exact crossover depends on:

  • HTTP/2 vs HTTP/1.1 (HTTP/2 multiplexes requests cheaply; the per-request cost is lower).
  • Whether the image is reused (a shared logo wins by being a separate cached file).
  • Whether the image is critical-path (an above-the-fold hero might warrant inlining despite being large).

The 4 KB Webpack default is in roughly the right neighborhood. Below that, inlining usually wins. Above 10 KB, separate files almost always win.

SVG is special

SVG is text. You can inline it three ways:

  1. As a data URI, base64-encoded — same as PNG/JPEG.
  2. As a data URI, URL-encoded (not base64) — usually shorter than base64 for SVG.
  3. As an inline <svg> element — directly in the HTML, no encoding at all.

For SVG, options 2 and 3 are usually better than base64. URL-encoded SVG in CSS:

background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'...%3E");

Inline <svg> is more capable still — it’s stylable with CSS, animatable, and accessible to screen readers in a way encoded SVG isn’t.

Format choice

If the image is a photograph: JPEG or WebP. If the image is a diagram or screenshot: PNG (lossless) or WebP (lossless). If the image is a vector icon: SVG. If you have to support <img> tags in pre-2020 browsers: stay with PNG/JPEG and skip WebP/AVIF.

The tool above accepts any file the browser FileReader can read; the MIME type is set from the file’s reported type.

What encoding doesn’t do

  • It doesn’t compress. A PNG that’s 100 KB on disk is ~133 KB as a base64 string — strictly larger. If the image needs to be smaller, optimize before encoding (pngquant, mozjpeg, cwebp).
  • It doesn’t change format. A JPEG encoded as base64 is still a JPEG. Converting between image formats requires decoding the image, re-encoding it in the new format, then base64-encoding.
  • It doesn’t protect the image. Anyone with the data URI has the image. Encoding is not obscuring.

Common pitfalls

  • Forgetting the ;base64 marker. data:image/png,... (no ;base64) treats the payload as URL-encoded text. The browser tries to parse it as text, fails, and shows a broken image.
  • Wrong MIME type. data:image/png;base64,<jpeg bytes> shows nothing in most browsers. The MIME has to match the actual format.
  • Whitespace in the base64. Some encoders wrap the output at column 76 (an old MIME convention). Most browsers tolerate this in data URIs; some are strict. Strip the whitespace if rendering fails.
  • Pasting into JSX without escaping. A data URI containing + or / is fine in HTML attributes but can need escaping inside JSX template literals. Most React tooling handles this; manual concatenation can fail.

For non-image binary encoding, see file to base64. For the underlying mechanics, see base64 encode and base64 decode.