How to compress with zlib and encode as Base64
- Type or paste the text, or drop a file.
- Format starts on zlib (deflate). Switch to Raw deflate when the receiver wants the bare stream, or to gzip.
- Optionally tick URL-safe (- _) or Wrap at 76.
- Copy output, or download the Base64
.txtor the binary.zz/.deflatefile.
Swap sends the output to the Decompress side to confirm the round trip.
The same text in three wrappers
Hello, world! (13 bytes), compressed at the default level:
| Format | Bytes | Base64 |
|---|---|---|
| raw deflate | 15 | 80jNycnXUSjPL8pJUQQA |
| zlib | 21 | eJzzSM3JyddRKM8vyklRBAAgXgSK |
| gzip | 33 | H4sIAAAAAAAAA/NIzcnJ11Eozy/KSVEEAObG5usNAAAA |
The deflate stream is the same 15 bytes in all three, yet the Base64 looks different because the 2-byte and 10-byte headers shift where each byte falls in the 3-byte groups. zlib’s header is 78 9C at the default level, which is why zlib Base64 begins eJ. At level 9 it is 78 DA, Base64 eN.
Which call produces which format
Most “deflate” bugs come from two sides using the same word for different wrappers:
| Language | zlib (RFC 1950) | raw deflate (RFC 1951) | gzip |
|---|---|---|---|
| Python | zlib.compress() | zlib.compressobj(wbits=-15) | gzip.compress() |
| Node.js | zlib.deflateSync() | zlib.deflateRawSync() | zlib.gzipSync() |
| Browser | CompressionStream("deflate") | CompressionStream("deflate-raw") | CompressionStream("gzip") |
| PHP | gzcompress() | gzdeflate() | gzencode() |
| Java | new Deflater() | new Deflater(level, true) | GZIPOutputStream |
| .NET | ZLibStream (.NET 6+) | DeflateStream | GZipStream |
| Go | compress/zlib | compress/flate | compress/gzip |
Note the traps: .NET’s DeflateStream and Go’s compress/flate are raw, while Node’s and the browser’s “deflate” are zlib. A C# service and a Node client that both “use deflate” will not understand each other without a change on one side.
Where each wrapper appears
- zlib: PDF
FlateDecodestreams, PNG image data, Git objects, many binary protocols and game save formats. - raw deflate: the SAML HTTP-Redirect binding (the SAML decoder handles it), entries inside ZIP files, WebSocket
permessage-deflate. - gzip: files, HTTP, logs. The gzip page covers it.
Zlib + Base64 in code
import base64, zlib
packed = base64.b64encode(zlib.compress(b"Hello, world!")).decode()
# 'eJzzSM3JyddRKM8vyklRBAAgXgSK'
text = zlib.decompress(base64.b64decode(packed))
// Node.js: raw deflate for a SAML-style payload
const zlib = require("zlib");
const packed = zlib.deflateRawSync(Buffer.from("Hello, world!")).toString("base64");
// '80jNycnXUSjPL8pJUQQA'
To read such strings back, use the Base64 gzip and zlib decoder, which detects all three wrappers. More in Python and Node.js.
Common problems
incorrect header check: zlib decoder, raw or gzip data. Match the wrapper.invalid stored block lengthsorinvalid block type: raw-deflate decoder fed zlib data; the two header bytes are read as deflate blocks.- The result is longer than the input: short strings do not compress. Below roughly 50–100 bytes, plain Base64 is shorter.
- Output does not match another tool byte for byte: the compression level and the library both change the bytes, and any correct decompressor returns the same original from either.
FAQ
What is the difference between zlib and deflate?
Deflate is the compression algorithm. Raw deflate is the bare compressed stream; zlib adds a 2-byte header and a 4-byte Adler-32 checksum around it; gzip adds a 10-byte header and an 8-byte trailer with CRC-32. The compressed data in the middle is identical.
What causes 'incorrect header check'?
The decompressor expected a zlib header and got something else, most often raw deflate or gzip. Use the matching call (zlib.decompress(data, -15) in Python for raw deflate) or re-encode with the format the receiver expects.
Is HTTP Content-Encoding: deflate raw deflate or zlib?
The HTTP spec says zlib. Some old servers sent raw deflate under that name, which is why gzip is the safer choice for HTTP.