proto2json

Decode protobuf to JSON, encode JSON back to binary, read raw wire bytes with no schema, draft a .proto from a JSON sample, understand .proto schemas in plain language, generate typed clients, share any result as a link. 100% in your browser — nothing gets uploaded.

Decode binary → JSON
Explain .proto
Typed client gen
Encode JSON → binary
JSON → .proto
Raw decode (no schema)

JSON output

Decoded with standard protobuf JSON mapping (camelCase optional — toggle below). gRPC responses decode as-is — the 5-byte frame header is detected and stripped automatically, including streaming responses with several frames.

…

Plain-language schema

…

Client code

…
Drop a .proto or .json file here, or click to browse

Binary output

Wire-format bytes. Base64 or hex — pick yours.

…

Reads the protobuf wire format directly: every field number, wire type, and a best-effort reading of the value. Field names are unknown without the schema, but this is usually enough to figure out what a message is.

Wire format

Field by field, with a hex view of the input. Numbers show signed, unsigned, and float readings. Fields that hold a nested message are expanded below as a tree.

…

Nested messages

Any field whose bytes parse as a valid sub-message is expanded into a tree. Field names are still unknown — the shape is what you're looking for.

…

No schema? Paste a sample of your API's JSON and we'll draft a .proto that matches it. Give us a few records if the list can grow — one record can't tell us a field is repeated.

Drop a .json file here, or click to browse

Drafted .proto

Best-effort mapping of JSON types to protobuf: strings→string, small ints→int32, big ints / 64-bit→int64, decimals→double, booleans→bool, lists→repeated, objects→nested messages. Field numbers are assigned in order — adjust to taste before you commit it.

…

FAQ

How do I decode a protobuf binary to JSON?
Paste your .proto file and the binary — as Base64 text or by dropping a .bin file — pick the message type, click Decode. Output follows the standard protobuf JSON mapping (camelCase by default; toggle snake_case in one click). It all runs in your browser via protobufjs; nothing is uploaded.
Can I turn JSON into protobuf binary?
Yes — the Encode tab is the reverse of Decode: paste your .proto and a JSON object, and it hands you the wire bytes as Base64 or hex, with a one-click .bin download. Same standard JSON mapping as the decoder, so decode → edit → re-encode is a clean round trip. Handy when you're hand-building gRPC or HTTP/2 request payloads.
Can I turn a JSON sample into a .proto file?
Yes — the JSON → .proto tab drafts a schema from your JSON. Paste an object, or an array of a few records (so it can tell which fields are repeated), and it maps strings to string, small integers to int32, 64-bit integers to int64, decimals to double, booleans to bool, lists to repeated, and nested objects to their own message types. Field numbers are assigned in the order you see them — tweak them to taste before you commit. Good for reverse-engineering a shape when the original .proto is lost.
Does my .proto or binary leave the page?
No. Parsing and decoding happen entirely in your browser. The library is bundled with the page (a CDN copy is the only fallback) — your data is never sent to a server.
What is protobuf (protocol buffers)?
Protocol Buffers is Google's compact binary serialization format. Raw .pb/.bin files look like gibberish without the schema — the Explain tab walks your .proto field by field in plain language, and Decode turns the binary back into readable JSON.
Can it generate typed client code?
Yes — the Generate tab turns a .proto into TypeScript interfaces, Python dataclasses, Go structs with protobuf tags, prost-style Rust, or JSON Schema (draft 2020-12), ready to paste into your project. Handles repeated fields, map fields, message references, and enums.
Can it convert a .proto to JSON Schema?
Yes — pick JSON Schema in the Generate tab. It follows the official protobuf JSON mapping: int64/uint64 come out as integer-or-string, bytes as Base64 strings, enums as named constants, and messages as $defs references. Copy it or save it as generated.json.
Can I download the generated code?
Yes — after generating, the Download file button saves it with the right extension for the target (generated.ts, .py, .go, .rs). Same code as the Copy button, just saved to disk.
Can I share a conversion?
Yes — hit Share link on any tab. It copies a URL with your inputs in the address bar; opening it re-runs the conversion in their browser. The data lives in the link, not on a server, so sharing never uploads anything.
I don't have the .proto file — can I still read the binary?
Yes — the Raw decode tab reads protobuf wire bytes with no schema at all. It lists every field number, the wire type, and a best-effort reading of the value (UTF-8 text where it looks like text, Base64 for bytes, plus signed/unsigned and float readings of numbers). Field names are unknown without the schema, but this is often enough to identify what a message is.
What if the binary contains nested messages?
The Raw decode tab expands them. Any field whose bytes parse as a clean sub-message is broken down into a tree below the flat list, and Copy JSON exports the whole structure — nested fields included — so you can see the shape of a message you didn't author.
Can I drop in my files instead of pasting?
Yes — drag and drop. On the Decode tab drop your .proto into the definition area or your .bin/.pb into the binary drop zone; on the Encode tab drop a .proto or a .json file. Files are read locally in your browser, so nothing is uploaded.
My .proto imports google/protobuf files — will it work here?
Yes. import "google/protobuf/timestamp.proto" (and the other well-known types — Duration, Struct, Any, wrappers, FieldMask, Empty) are bundled in, so your file resolves without pasting in the imports. The Generate tab maps them to their real packages: timestamppb.Timestamp in Go, string in TypeScript, and a native timestamp type in Python's output.
I have a raw gRPC response body — do I have to strip the header first?
No. gRPC wraps each payload in a 5-byte frame (1 compression flag + 4 big-endian length), and the Decode tab detects that header and strips it for you. Paste the frame as Base64 or hex, pick the message type, and the output is the message JSON — the note above the result tells you the frame was detected and how many payload bytes it carried. Streaming responses work the same way: paste several frames concatenated and each one is decoded to its own entry in a JSON array. If the frames were gzip-compressed (compression flag 1), each one is gunzipped before decoding, so a body straight off the wire just works.
I need to build a gRPC request body — can it add the frame header?
Yes. On the Encode tab, tick Wrap as a gRPC request after encoding and it prepends the 5-byte gRPC frame header (1 compression flag + 4 big-endian length) to the message. Choose gzip for a compressed frame (flag 1) or none for plain — the output is the exact body a gRPC client sends, so you can hand it to a server or paste it into the Decode tab to confirm it decodes back to your JSON.
My .proto has map fields — do they work?
Yes. Decode renders maps as JSON objects, Encode accepts JSON objects and writes the entries to the wire, Explain describes them in plain words (a lookup table from text to whole numbers), and Generate emits the right type per language — a record in TypeScript, Dict[str, int] in Python, map[string]int32 in Go.
I don't have a .proto — can you draft one from my JSON? How do I know it's right?
The JSON → .proto tab drafts a .proto from a JSON sample (or a few records, so repeated fields are detected), and Verify round-trip proves it: it encodes your sample with the drafted schema into binary, decodes it back, and diffs every field. Zero differences means the schema carries your data. It also flags the normal protobuf behavior of dropping zero/false/empty values on the wire, so you don't mistake that for a bug.
Is it free?
Free and unlimited. No accounts, no paywall, no watermarks.