How to convert Base64 to WebP
- Paste the Base64 or the full
data:image/webp;base64,...URI. Code that contains one, such as a CSSurl()or an<img>tag, works too. - Check the status line for Detected WebP, then the preview and the dimensions above it. Animated WebP plays in the preview.
- Press Download file. The extension is set to
webp.
Three kinds of WebP
WebP is a RIFF container with one of three chunk types right after the WEBP tag. Because the tag sits at a fixed offset, the type shows up at a fixed place in the Base64 as well:
| Base64 starts with | Chunk | What it is |
|---|---|---|
UklGR…XRUJQVlA4I | VP8 | lossy, no transparency |
UklGR…XRUJQVlA4T | VP8L | lossless, can include transparency |
UklGR…XRUJQVlA4W | VP8X | extended: lossy with alpha, animation, ICC profile or EXIF |
The six characters between UklGR and XRUJQ encode the file size and change from file to file. XRUJQ (from WEBP) always sits at characters 12 to 16 and VlA4 (from VP8) at 17 to 20. The 21st character is the one you want: I, T or W.
The kind decides what happens when you convert the file. Lossless WebP is a good stand-in for PNG. Lossy WebP has already lost detail, so converting it to PNG makes a large file without bringing quality back. An extended file can hold several frames; converting that to a still format keeps only the first.
Check the WebP type in code
The same test in Python reads the chunk tag and, for extended files, the flag byte:
import base64
def webp_kind(b64: str) -> str:
data = base64.b64decode(b64.split(",", 1)[-1])
if data[:4] != b"RIFF" or data[8:12] != b"WEBP":
return "not WebP"
chunk = data[12:16]
if chunk == b"VP8 ":
return "lossy"
if chunk == b"VP8L":
return "lossless"
flags = data[20]
parts = ["extended"]
if flags & 0x10:
parts.append("alpha")
if flags & 0x02:
parts.append("animated")
return ", ".join(parts)
For WebP files written by Pillow it returns lossy, lossless, extended, alpha for a lossy image with transparency, and extended, animated for an animation. More in Base64 in Python.
RIFF is not always WebP
UklGR only means “RIFF”. WAV audio and AVI video start the same way and differ in the tag at bytes 8 to 11. The decoder checks that tag, so a WAV pasted here is reported as “This looks like WAV, not WebP” with a button to save it as .wav. Base64 to Audio plays it.
Where WebP Base64 turns up
- Canvas exports with
toDataURL("image/webp", quality). Check the result: browsers without a WebP encoder quietly return PNG. - Image APIs and CDNs that serve WebP to any client that accepts it. If a browser fetched the image, even a field named
thumbnail_jpgmay contain WebP. - Inline placeholders and icons in HTML and CSS, where WebP gives a shorter string than PNG or JPEG.
- Chat stickers, which are often WebP, sometimes animated.
When an older program refuses the saved file, compare the SHA-256 shown here with the file it received. If they match, the program does not read WebP, and a PNG or JPEG copy is the way out.
FAQ
Is my Base64 WebP lossy or lossless?
Look at character 21 of the string. I after VlA4 means a lossy VP8 image, T a lossless VP8L image, and W the extended format, which a lossy image with transparency or an animation uses.
Can I save the decoded WebP as PNG or JPG?
Not by renaming it; the bytes stay WebP. Download the .webp, then use WebP to Base64 with Convert to PNG or JPEG and decode the new string on Base64 to PNG.
Why did canvas.toDataURL('image/webp') give me a PNG?
Browsers that cannot encode WebP, Safari in particular, silently return a PNG data URI instead. Paste the result here: if it says PNG, that is what happened.
Why does the preview fail on an older Mac or iPhone?
Safari 14 and 15 show WebP only on macOS 11 Big Sur or later, and Safari before 14 not at all. There the preview says the browser cannot display the image, but Download file still saves a valid .webp.