albert.walickihire me
← all solutions
html

How to display a base64 image in HTML?

Show a base64 encoded image with a data URL in an img tag, in CSS or from JavaScript, pick the right MIME type, and know when base64 is a bad idea.

Put the base64 string into a data URL and use it as the src of an <img>. A data URL is data:, the image's MIME type, ;base64, and then the encoded data.

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." alt="Logo">

The MIME type has to match the actual format of the image: image/png, image/jpeg, image/gif, image/webp or image/svg+xml. Browsers sometimes show a raster image with the wrong type anyway, but SVG only works with image/svg+xml, so don't rely on it. If you don't know the format, the first characters of the string usually tell you:

  • iVBORw0KGgo is a PNG.
  • /9j/ is a JPEG.
  • R0lGOD is a GIF.
  • UklGR is a WebP (strictly, any RIFF file, but for images that means WebP).

Here's a complete example you can paste into the console to try: a 1×1 transparent GIF, a common placeholder.

const pixel =
  'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';

const img = document.createElement('img');
img.src = `data:image/gif;base64,${pixel}`;
img.alt = '';
document.body.append(img);

In CSS

The same data URL works anywhere CSS takes an image:

.hero {
  background-image: url('data:image/png;base64,iVBORw0KGgo...');
}

From an API in JavaScript

APIs often return only the base64 data, without the data: prefix. Add it yourself:

const response = await fetch('/api/users/42/avatar');
const { data } = await response.json(); // "/9j/4AAQSkZJRg..."

const img = document.querySelector('.avatar');
img.src = `data:image/jpeg;base64,${data}`;

If the API sends the MIME type as well, use it instead of hardcoding image/jpeg. And if the string contains - or _, it's base64url, a URL-safe variant. Replace - with + and _ with / before putting it in a data URL.

SVG doesn't need base64

SVG is text, so you can put it in a data URL as URL-encoded text instead of base64:

const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
  <circle cx="8" cy="8" r="8" fill="#16a34a" />
</svg>`;

img.src = `data:image/svg+xml,${encodeURIComponent(svg)}`;

When you write an SVG data URL by hand in CSS, keep it on one line, use single quotes inside the SVG, and encode # as %23. An unencoded # in a color like #16a34a starts the URL fragment and cuts the image off. Encoding < and > as %3C and %3E is a common extra precaution.

When not to use base64

Base64 images are handy, but they have costs:

  • They're about 33% bigger than the original file, because every 3 bytes become 4 characters. The 42-byte GIF above is 56 characters.
  • They aren't cached on their own. The image is part of the HTML or CSS file, so it's downloaded again whenever that file changes. Inline in HTML, every page that uses it downloads it again.
  • They bloat the file they're in. A large image inside a CSS file delays everything that waits for that CSS, like the first render.

Use them for tiny images: small icons, a blurred placeholder while the real image loads, or an image in a single HTML file that has to work on its own. For everything else, a normal image file with its own URL is faster.

Binary data from fetch

If you fetch an image yourself, for example because the request needs an authorization header, you don't need to convert it to base64 at all. Turn the response into a Blob and create an object URL:

const response = await fetch('/api/private/photo.jpg', {
  headers: { Authorization: `Bearer ${token}` },
});
const blob = await response.blob();

img.src = URL.createObjectURL(blob);

The object URL points to the data in memory, with no 33% overhead. Call URL.revokeObjectURL() with it once you no longer need the image.

more solutions
work with me

Got something that needs building?

Frontend builds, full-stack features in Django, design-system work. Available for work.

See my workGet in touch