Data URI generator
Encode an image, font or text as a data: URI, or decode one, with Base64 and percent-encoding measured against each other. Runs in your browser.
data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%232563eb'%20stroke-width='2'%3E%3Ccircle%20cx='12'%20cy='12'%20r='9'/%3E%3Cpath%20d='M8%2012.5l2.5%202.5%205-6'/%3E%3C/svg%3E
Percent-encoding is shorter here: 255 characters against 272, saving 17.
Sizes
- Source bytes
- 174
- URI, Base64
- 272
- URI, percent-encoded
- 255
A file inside a URL
A data URI is a whole file written out as a URL. Instead of pointing at a resource the browser has to go and fetch, it carries the bytes themselves, so an icon can live inside the stylesheet that uses it and a small image inside the HTML that shows it. RFC 2397 defined the scheme in 1998 and it has been supported everywhere for two decades.
The grammar is short. After the scheme comes an optional media type with optional parameters, then an optional base64 flag, then a comma, then the data. Everything before the comma is the header and everything after it is the payload — which is why the browser splits at the first comma and why a comma inside the payload is harmless.
data:[<mediatype>][;base64],<data> data:,hello text/plain;charset=US-ASCII data:text/plain;charset=utf-8,hello the same bytes, spelled out data:image/png;base64,iVBORw0KGgo= binary, Base64 encoded data:image/svg+xml,%3Csvg%20... markup, percent-encoded
An empty header is legal and means text/plain;charset=US-ASCII, which is the one default the specification hands you. This page reports that it applied it rather than showing a media type you never wrote.
Two encodings, and which one is shorter
The RFC defines two ways to write the payload, and the choice is not a style preference — for a given file one of them is meaningfully shorter, and which one depends entirely on what the file contains.
Base64 rewrites every three bytes as four characters from a 64-character alphabet. The cost is fixed and predictable: exactly a third more, plus padding. It works for anything, which is why it is the form people reach for by default.
Percent-encoding leaves any character that is legal in a URL exactly as it is and spends three characters on every one that is not. For a payload that is mostly plain ASCII — an SVG, a small stylesheet, a JSON blob — most bytes pass through untouched and the result is shorter than Base64, often by twenty to thirty per cent. For a PNG or a font, where nearly every byte has to be escaped, it is close to three times the original and far worse than Base64.
How much is escaped is itself a choice, and this page offers both answers:
- The strict set escapes every byte outside the unreserved characters of RFC 3986 — letters, digits, hyphen, period, underscore and tilde. The result is safe in any context at all, at the cost of escaping punctuation that did not need it.
- The minimal set keeps everything the data URI grammar actually permits, which includes the slashes, colons, equals signs, quotes and parentheses that markup is full of. This is where percent-encoding wins, and it is why an SVG written with single quotes around its attributes encodes so much better than one written with double quotes.
- The destination adds one more rule. Inside an HTML attribute a bare ampersand starts a character reference, so choosing the img destination escapes it too. Nothing else changes: the double quote, the angle brackets and the backslash are outside the permitted set already and are escaped at both levels.
- A percent sign is always escaped, at every level. It introduces an escape sequence, so a literal one has to be written as %25 or the next two characters are read as hex.
Rather than making you guess, the page encodes the payload both ways and reports the two lengths and the difference. Pick whichever wins, or set the encoding by hand if you have a reason to.
The 33% is a pre-compression number
Almost every discussion of data URIs repeats that Base64 adds a third to the file size. That is arithmetically true and practically misleading, because the number describes the bytes before they reach the wire and every server compresses text on the way out.
Base64 does not add information; it spreads the same information across more characters, using only 64 of the 256 values a byte can hold. That is exactly the sort of redundancy gzip and Brotli exist to remove. On an already-compressed payload — a PNG, a JPEG, a WOFF2 font — the compressor cannot touch the underlying data but it can pack the Base64 back down to something very close to the original size. The famous third mostly disappears.
So this page measures it instead of asserting it. It compresses three things with the browser’s own gzip implementation: the payload as a separate file would be served, the document holding it as Base64, and the document holding it percent-encoded. Those three numbers are the honest version of the size argument, and they often show that the real cost of inlining is not size at all.
The real costs are elsewhere. An inlined file cannot be cached on its own, so it is downloaded again with every copy of the document that carries it, and it can never be shared between two pages. It also blocks: a stylesheet does not finish parsing until it has read the whole URI sitting in the middle of it. HTTP/2 removed most of the per-request penalty that made inlining attractive in the first place. For a tiny icon that appears on every page it is still a reasonable trade; past a few tens of kilobytes it usually is not, which is why this page starts warning at thirty.
The type comes from the bytes
A data URI is only useful if the media type is right. Get it wrong and the browser refuses to render the image, applies the wrong parser, or — for anything served with a type it does not recognise — offers a download instead.
When you drop a file in, the browser reports a type of its own, but that report is derived from the file extension and nothing else. Rename a JPEG to .png and the browser will call it a PNG. This page reads the first bytes instead. Nearly every binary format begins with a signature: PNG starts with a byte that cannot appear in ASCII followed by the letters PNG, JPEG with three fixed bytes, PDF with a percent sign and the word PDF, WOFF and WOFF2 with their own four-character tags. When the signature and the extension disagree, the signature wins and the disagreement is reported.
The list is deliberately short — the formats people actually inline, not everything a browser can sniff. If nothing matches and the bytes are valid text, the type is text, with SVG and XML separated by looking at what the markup opens with. If nothing matches at all the answer is application/octet-stream, and the field stays editable, because a wrong guess is worse than an admitted one.
For textual payloads the charset matters too. The specification’s default is US-ASCII, which is not what anyone means today, so a text media type is offered with charset=utf-8 attached. Leaving it off does not corrupt the bytes but it does change how they are read back.
Reading one back
The other half of the job is the one that comes up more often: you have found a data URI in a stylesheet, a DOM dump or a saved page, and you want to know what it is. Paste it and the page takes it apart — the media type, its parameters, which encoding was used, how many bytes it decodes to against how many characters it costs, and what those bytes look like independently of what the header claims. An image is rendered, text is shown, anything else gets its first bytes in hex.
Decoding is strict, because a pasted URI is untrusted input and a plausible wrong answer is worse than an error. A missing comma, a malformed media type, a percent sign not followed by two hex digits, a character outside the Base64 alphabet: each fails with the position of the problem rather than being quietly repaired.
Two things are tolerated, because every browser tolerates them and a URI copied out of a wrapped stylesheet would otherwise be unusable. Whitespace inside the payload is removed, and missing Base64 padding is supplied. Both are reported, so you know the URI you have is not quite the URI that works everywhere.
One thing that looks similar is refused outright. The URL-safe Base64 alphabet, which replaces plus and slash with hyphen and underscore, is what JSON Web Tokens use — and it is not what a data URI takes. Accepting it silently would mean decoding to different bytes than a browser would, so it is rejected by name, with the position of the offending character.
Where it runs
Everything happens in your browser. The file you choose is read with the local file API and never uploaded; the encoding, the compression measurement and the decoding all run on your own machine, and nothing is stored or logged. That matters here more than on most pages, because the files people turn into data URIs are often internal assets, and the URIs people paste in to inspect come out of production pages.
Frequently asked questions
- Is my file uploaded anywhere?
- No. The file is read locally with the browser’s own file API, encoded on your machine and never sent anywhere. The same is true of a URI you paste in to decode.
- Should I use Base64 or percent-encoding?
- Whichever is shorter for your payload, which the page measures for you. As a rule of thumb: percent-encoding for SVG, CSS, JSON and other text, Base64 for images, fonts and anything already compressed. The difference is often twenty to thirty per cent in either direction.
- Does Base64 really make a file 33% bigger?
- Before compression, yes: four characters for every three bytes. On the wire, mostly not. Base64 uses only 64 of 256 possible byte values, and that redundancy is exactly what gzip removes, so the compressed size is usually close to the compressed size of the original file. The page measures both so you can see it.
- How big can a data URI be?
- Modern browsers do not impose a hard limit on a URI inside a document, though old versions of Internet Explorer capped it at 32 KB. Size is a performance question rather than a legal one: an inlined file cannot be cached separately and is re-downloaded with every copy of the document. This page encodes up to a megabyte and warns above thirty kilobytes.
- Why does my SVG data URI break in CSS?
- Almost always an unescaped character. A hash — from a colour like #2563eb — starts a fragment identifier and truncates the URI at that point. A double quote ends the CSS string it sits in. Write the SVG with single quotes around its attributes and use the minimal escape set, which escapes the hash and the double quote and leaves everything else short.
- Can I use a data URI for a script or an iframe?
- You can, but treat it as a security question rather than a convenience. A data URI inherits no origin, and browsers already block top-level navigation to one for that reason. A Content Security Policy that allows data: in script-src or frame-src gives up most of what the policy was protecting; allowing it in img-src or font-src is ordinary.
- Why was my URL-safe Base64 rejected?
- Because a data URI takes standard Base64. The URL-safe alphabet swaps plus and slash for hyphen and underscore, which are different characters that decode to different bytes. Accepting it would mean this page decoded your URI differently from the browser that will actually load it.
- The browser says my file is one type and this page says another. Which is right?
- The page. A browser reports the type it infers from the file extension, so a renamed file is reported wrongly. This page reads the signature at the start of the file, which is what the format itself declares. The field stays editable if you have a reason to override it.