Data URI Generator
Turn any file or text into a self-contained data: URI — MIME sniffed or chosen, Base64 or percent-encoded, entirely on this device.
- Raw
- <img>
- CSS
Going the other way? Base64 to Image decodes data URIs back into files.
Press ? for shortcuts
Do it offline:$ printf 'data:%s;base64,%s' "$(file -b --mime-type photo.png)" "$(base64 -w 0 photo.png)"
How to use it
- Pick a source pane: Text for anything typeable, File for a drop zone and picker. Reading a dropped file happens in place and triggers no network request.
- Leave MIME on Auto to take the detected type — magic bytes for files, plain text for typing — or enter any type/subtype by hand; a datalist offers 28 common values to save the spelling.
- Choose the encoding. Auto measures the complete URI both ways and keeps the shorter form; Base64 or Percent forces one. A chip under the output names the pick with both character counts.
- Copy what you need: the accent button takes the bare URI, the snippet rows wrap it as an <img> tag or a CSS url() value. For non-image types the <img> row stays, disabled, and says why.
- Download the URI as data-uri.txt with ⌘/Ctrl + S, or share a permalink — typed text rides inside the link fragment; file bytes never travel in a link.
Drop a file or type text, keep the MIME type the byte signature detected or set your own, and the finished data: URI is ready to copy — as a raw string, an <img> tag, or a CSS url() value. The readout counts source bytes against URI characters for both encodings, so you see what inlining costs before pasting it anywhere. Assembly runs entirely in this tab.
How it works
Every data: URI is assembled from the same four slots: the data: scheme, an optional mediatype such as image/png, an optional ;base64 flag, then a comma and the payload — and the comma is required even when the payload is empty. Leave the mediatype slot blank and RFC 2397 fills in text/plain;charset=US-ASCII, which is why data:,A%20brief%20note — the RFC's own example — reads back as plain text. This form is that grammar with one control per slot.
The two payload encodings trade differently. Base64 always spends 4 characters per 3 source bytes, regardless of what the bytes are. Percent-encoding keeps each RFC 3986 unreserved character — letters, digits, hyphen, period, underscore, tilde — as itself but spends 3 characters on every other byte as an uppercase %XX escape, so plain ASCII text stays near raw size while binary data can triple. Auto counts the complete URI under both encodings, keeps the shorter one, and declares the arithmetic in a chip; an exact tie goes to Base64.
The percent encoder here escapes every byte outside that unreserved set — stricter than encodeURIComponent, which leaves characters like ' ( ) alone. Quotes, ampersands, angle brackets and # therefore never appear raw in a generated URI, so the <img> and url() snippets paste into HTML attributes and stylesheets without further escaping. On the text path, a text/* type whose content holds non-ASCII characters gains ;charset=utf-8 automatically, because without the parameter RFC 2397 makes US-ASCII the assumed charset.
Inlining is a trade, not a free win. An embedded asset arrives with the document and saves one request — good for a tiny icon or a placeholder image. In exchange, the bytes are re-sent inside every page that embeds them instead of being cached once under their own URL, the document grows by the encoding overhead, and a Content-Security-Policy must allow data: in the matching directive (img-src, font-src, style-src) before the browser loads the resource. Past 2,000 characters the readout marks the URI long — the zone where attributes, diffs and log lines get unwieldy — without pretending any universal browser limit exists.
Examples
Hello, data URIs!data:text/plain;base64,SGVsbG8sIGRhdGEgVVJJcyE=Forcing Base64 spells the sample's 17 bytes as 24 payload characters inside a 47-character URI. The rest is the fixed data:text/plain;base64, prefix — the reason tiny payloads show startling overhead figures: this one reports +176%, nearly all of it prefix.
pixel.png — a 67-byte 1×1 PNGdata:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR42mNgAAAAAgAB5Sfe/AAAAABJRU5ErkJggg==
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR42mNgAAAAAgAB5Sfe/AAAAABJRU5ErkJggg==" alt="">A real file drop: the signature scan reads the PNG magic bytes, so the MIME field fills itself. Auto compares 114 URI characters as Base64 against 176 percent-encoded and keeps Base64 — binary bytes escape terribly. Because the type is image/*, the <img> snippet unlocks, its alt attribute left empty for you to fill.
café menu ☕data:text/plain;charset=utf-8,caf%C3%A9%20menu%20%E2%98%95The edge case: é and ☕ are non-ASCII, so ;charset=utf-8 is appended automatically and a chip says so — declared UTF-8 instead of assumed US-ASCII. Fourteen source bytes become a 58-character URI; the two multi-byte characters alone account for five %XX escapes.
See the release notesdata:text/plain,See%20the%20release%20notesLeft on Auto, the picker reports: Auto encoding picked percent-encoding — 43 URI characters vs 51 as Base64. Short ASCII text usually lands this way, which also keeps the payload readable wherever the URI ends up.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
Empty input still emits a valid URI
With nothing to encode the output pane holds data:text/plain, — sixteen characters, zero payload bytes, and no ;base64 flag even when Base64 is forced, since a flag on an empty payload is noise. The trailing comma survives because RFC 2397 requires one in every data: URI, payload or not.
A # in your content is escaped, never lost
In a hand-assembled URI a raw # starts the URL fragment, and consumers cut the payload there — the parser in this family chips that removal and suggests writing %23. The builder never leaves you exposed: percent output escapes # like any other reserved byte, and the Base64 alphabet cannot produce one.
Your MIME override wins — and gets fact-checked
Enter any valid type/subtype and the URI carries it even when the byte signature disagrees; an override is treated as a decision, not a typo. The disagreement is still recorded: a chip names both types and confirms the URI keeps yours. An entry that fails the RFC 2045 token grammar is refused with a pointed message instead of being silently corrected.
The ;base64 flag is case-insensitive on the way in
URIs from other tools sometimes arrive spelled ;BASE64 or ;Base64. The family parser accepts any casing and notes the spelling in a chip, matching how RFC 2397 consumers behave — but generation always emits lowercase ;base64, the one spelling nothing mishandles.
Charset Never states its risk out loud
Switch the charset toggle to Never and non-ASCII text/* output ships without a parameter — sometimes wanted for byte-exact compatibility with an existing consumer. A warning spells out the consequence: readers may assume US-ASCII for text/* payloads. Auto restores the safe behavior.
2,000 characters is a warning, not a wall
At 2,000 URI characters the length band flips to long and the warning prints the measured count. Nothing refuses: RFC 2397 sets no maximum, and real ceilings belong to whatever consumes the URI. Generation continues until the 16 MB input cap, where a typed refusal names the limit instead of letting the tab stall.
Common errors
MIME type 'image png' is missing the '/' between type and subtype — for example image/png.- The MIME field wants the bare two-part form from RFC 2045: a type, one slash, a subtype, no parameters. A space, a missing slash or an empty half stops the build until fixed — the URI would otherwise be malformed for every consumer that reads it.
Not a data: URI — input begins with 'https' instead of 'data:'. A data URI starts with data: followed by an optional media type, an optional ;base64 flag, a comma and the payload.- This one comes from the family's parser, not the builder: it fires when something that should be a data: URI — a share link payload, a pasted snippet in the decoding tools — starts with any other scheme. To go the reverse direction and read a URI back into bytes, use the Base64 to Image converter for pictures or the Base64 decoder for everything else.
The data URI is 2159 characters long — data URIs this large bloat HTML and may hit tool limits. Consider linking the file instead.- The long-length warning, captured here at 1,600 source bytes of Base64. It reports the measured character count and stays a warning — the build completes, the copy buttons work, and whether the size is acceptable stays your call.
MIME type is set to text/plain, but the bytes carry the image/png signature — the URI keeps text/plain. Switch MIME to Auto to use the detected type.- The fact-check chip for manual MIME entries. It fires on a byte-signature match — or on the one scanned verdict, SVG, where the chip says an <svg> marker was found rather than claiming a signature — and never argues from the text heuristic or the octet-stream fallback. The URI always keeps the type you chose.
Input is larger than the 16 MB limit for this tool. For bigger payloads use the CLI: printf 'data:%s;base64,%s' "$(file -b --mime-type photo.png)" "$(base64 -w 0 photo.png)"- A typed refusal rather than a stalled tab: source input caps at 16 MB in every mode. The printed command assembles the same URI in a shell — file -b --mime-type supplies the mediatype and base64 -w 0 the unwrapped payload (GNU coreutils; BSD base64 on macOS writes one line by itself as base64 -i photo.png).
FAQ
Is it a data URI or a data URL?
Both names are in live use for the same strings. RFC 2397 is titled The "data" URL scheme, and the WHATWG Fetch standard processes data: URLs; URI is RFC 3986's umbrella term covering them. Every consumer treats the two labels identically, so use whichever your style guide prefers.
What is the maximum length of a data URI?
RFC 2397 sets none, and no single number covers real software — each browser, server, editor and log pipeline enforces its own ceiling, so test the system the URI must pass through. This page warns once a URI crosses 2,000 characters, where long values turn unwieldy, and refuses input past its own 16 MB cap.
Should I embed an image as a data URI or link to the file?
Embed when the asset is tiny and appears in one place — a blur-up placeholder, an email signature mark, a single-page icon — because it arrives with the document and costs no second request. Link when it repeats across pages or grows past a few kilobytes: a linked file is cached once under its URL, while an embedded copy re-downloads inside every document carrying it, plus encoding overhead each time.
Why is the Base64 form larger than my file?
Base64 maps each 3 bytes to 4 output characters, so the payload runs about a third over the source before the data:mediatype;base64, prefix is counted — the readout splits those two costs apart. Percent-encoding can be cheaper on ASCII-heavy text, one character per unreserved byte, but reaches 3 per byte on binary data. That comparison is exactly what the Auto setting measures for you.
How do I decode a data URI back into a file or image?
Reading URIs is the reverse workload with its own pages: the Base64 to Image converter previews and downloads image payloads, and the Base64 decoder handles arbitrary bytes. The whole family shares one parser, so pasted URIs get the same declared tolerances everywhere — wrapped lines, odd flag casing and stray fragments surface as chips, never silent fixes.
Does my file upload anywhere while it converts?
No — the file is read by the browser in this tab and the URI is assembled by script on this page; the Network panel in DevTools stays quiet through a drop, a build and a copy. Typed text is kept in this browser's local storage so a return visit can restore it, file bytes are never stored at all, and a permalink carries text state only when you create one.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Re-run the build with the current source, MIME and encoding.
- ⌘/Ctrl + S
- Download the current URI as data-uri.txt instead of saving the page.
- ⌘/Ctrl + C
- Copy the finished data URI while no text is selected; a real selection copies only itself.
- ⌘/Ctrl + Shift + C
- Copy the data URI even while a selection exists.
- ? or ⌘/Ctrl + /
- Open the keyboard shortcut overlay.