How to decode a gzip Base64 string
- Paste the Base64 into the input, or drop a
.gz,.zzor.deflatefile. Whitespace and line breaks are ignored. - Leave Format on Auto-detect. The status names what it found, for example “Detected gzip”.
- Text output appears in the output pane, and JSON is pretty-printed. Binary output gets its file type detected and a Download button.
- For gzip input the meta also shows the original file name and modification time, when the sender stored them.
Telling gzip, zlib and deflate apart
All three use the same DEFLATE compression and differ only in the wrapper, which shows in the first Base64 characters:
| Starts with | Format | Typical source |
|---|---|---|
H4sI | gzip (1F 8B 08) | gzip, GZIPOutputStream, HTTP bodies, CloudWatch Logs |
eJ | zlib, default level (78 9C) | zlib.compress(), PHP gzcompress(), PDF streams |
eNo–eNr | zlib, best compression (78 DA) | level 7–9 |
eAE–eAH, eF4–eF7 | zlib, fastest and low levels (78 01, 78 5E) | level 1 to 5 |
| no fixed prefix | raw deflate | SAML Redirect binding, PHP gzdeflate(), ZIP entries |
SDRzSU | gzip Base64-encoded twice | Helm release Secrets |
Raw deflate has no signature, so auto-detect tries it after gzip and zlib fail. Brotli has no signature either and is tried last, when the browser supports it.
Real-world payloads
AWS CloudWatch Logs subscription events reach Lambda as {"awslogs": {"data": "H4sI…"}}. Paste the data value to read the JSON with logGroup, logStream and logEvents.
Helm 3 release Secrets hold Base64 of gzipped JSON, which Kubernetes Base64-encodes again. From the shell:
kubectl get secret sh.helm.release.v1.myapp.v3 -o jsonpath='{.data.release}' \
| base64 --decode | base64 --decode | gunzip | jq -r .manifest
In the browser, decode the outer layer with the Kubernetes Secret decoder or the Base64 decoder, then paste the H4sI… result into this page.
SAML Redirect messages are raw deflate. They decode here too, but the SAML decoder also URL-decodes them and summarizes the XML.
Decoding in Python and Node.js
import base64, zlib
raw = base64.b64decode(s)
text = zlib.decompress(raw, 47).decode() # 47 = 32 + 15: accept gzip or zlib
const zlib = require("zlib");
const text = zlib.unzipSync(Buffer.from(s, "base64")).toString(); // gzip or zlib
For raw deflate use zlib.decompress(raw, -15) in Python and zlib.inflateRawSync() in Node. See Base64 in Python and Base64 in Node.js.
Errors and limits
- “This is valid Base64, but not gzip, zlib or raw deflate data.” The string was never compressed. Try the Base64 decoder, or Base64 to file for binary.
- “This is not valid gzip data, or it is truncated.” Part of the string is missing, often cut by a log line limit. Copy it again from the source.
- “Extra bytes after the compressed stream were ignored.” Something was appended after the end of the stream. The data before it is kept.
- “The decompressed data is larger than 256.0 MB, so decompression stopped (possible zip bomb).” Output is capped as a guard against decompression bombs. Use
gunziplocally for anything that large. - Multi-member gzip files (several gzip streams concatenated) are not supported.
FAQ
What does H4sI mean at the start of a Base64 string?
It is the Base64 form of 1F 8B 08, the gzip signature with the deflate method byte. A string starting H4sI is gzip data: Base64-decode it and gunzip the bytes.
How do I decode Base64 gzip on the command line?
echo 'H4sI…' | base64 --decode | gunzip on Linux and macOS. For zlib data (eJ…) gunzip refuses the header; use python3 -c 'import sys,zlib; sys.stdout.buffer.write(zlib.decompress(sys.stdin.buffer.read()))' after the Base64 step.
Why do I get binary output after Base64 decoding?
The data was compressed before it was encoded, so a plain Base64 decoder hands you the compressed bytes. Paste the string here and it is decoded and decompressed in one step.
Can this open .zip or .tar.gz files?
A .tar.gz decompresses to the .tar archive, which you can download. ZIP archives are a different container; use Base64 to ZIP to list and save them.