LazyTools

🔒 Every tool runs in your browser, the files and values you enter are never uploaded to any server. How it works

🧬 Protobuf Decoder (decode_raw)

Paste protobuf bytes (hex or base64) to decode the message into its fields, numbers, wire types and values, with nested messages expanded.

Decoded fields

1varint150 · sint 75
2len"testing"
3lenmessage (3 bytes)
1varint150 · sint 75

Paste a Protocol Buffers message as hex or base64 to decode its structure, like protoc --decode_raw. The wire format is self-describing for field numbers and types, so you get each field's number, wire type and the plausible readings of its value (a length-delimited field is shown as a nested message when it parses, otherwise as a string or raw bytes). Without the .proto schema, field names and exact types (int vs sint, string vs bytes) can't be recovered, that's a property of the format, not a limit of the tool. 🔒 Decoded entirely in your browser.

Rate this tool:
Anonymous, no account, no identifier

How the protobuf decoder (decode_raw) works

Protocol Buffers encode each field as a varint "tag" that packs the field number and a wire type, followed by the value. Because that structure is self-describing, you can decode a message without its .proto schema, exactly what protoc --decode_raw does. This tool reads the bytes (hex or base64), walks the fields, and for each shows the field number, the wire type (varint, 64-bit, 32-bit or length-delimited) and the plausible readings of the value: a varint as unsigned, zigzag-signed and boolean; fixed 32/64-bit as integer, float/double and hex; and a length-delimited field as a nested message when its bytes parse cleanly, otherwise as a UTF-8 string or raw bytes. It uses BigInt so 64-bit values stay exact.

What a schema-less decode cannot recover is the field names and the exact declared types, protobuf does not store them in the message, so field 1 is "1", not "userId", and a length-delimited field could be a string, bytes or a sub-message. The tool makes the standard best-guess (nested message first, then string) just like decode_raw; treat the readings as candidates, not certainties. This is genuinely useful for inspecting an API response, a gRPC payload or a COSE/WebAuthn structure when you don't have the .proto handy. Everything is decoded in your browser, so the payload, which may be sensitive, is never uploaded.

Frequently asked questions

Can I decode protobuf without the .proto file?

Yes, that's exactly what this does. The wire format encodes each field's number and type, so the structure and values decode without a schema. You just won't get the human-readable field names or the exact declared types, which aren't stored in the message.

What is protoc --decode_raw?

A protobuf command that dumps an unknown message's fields by number and wire type without a schema. This tool is a browser equivalent: paste the bytes as hex or base64 and get the same field-by-field breakdown, with nested messages expanded.

Why is a field shown as a number instead of a name?

Because protobuf messages carry only field numbers on the wire, not names, names live in the .proto schema, which isn't transmitted. Without that schema, field 1 can only be shown as "1". Match the numbers to your .proto to recover the meaning.

How do I know if a value is a string or a nested message?

Length-delimited fields (wire type 2) can be strings, raw bytes or embedded messages, and the wire format doesn't distinguish them. The tool tries to parse the bytes as a nested message first (as decode_raw does) and falls back to a UTF-8 string or hex, so the reading is a best guess.

Can I paste base64 as well as hex?

Yes, paste the message as spaced or unspaced hex (with or without 0x), or as standard/URL-safe base64. The tool detects the format and decodes it the same way.

Is my payload uploaded?

No, decoding runs entirely in your browser with no network calls, so an API or gRPC payload never leaves your device. It works offline too.

Related developer tools

From the blog