JSON ↔ CBOR
CBOR is the binary JSON that standards bodies actually reference: WebAuthn credentials, COSE signatures, CoAP payloads and most constrained-device protocols are CBOR underneath. Paste JSON to see the bytes it becomes, or paste the hex out of a debugger and read it back.
How to use it
- Paste JSON. The output pane shows the encoded bytes and the status line compares them with the minified JSON.
- Pick the view you need — hex to paste into a test, base64 for a config or a header, byte array for source code.
- Download writes the real binary as
data.cbor, not the hex view of it. - Going the other way, switch Direction to decode and paste hex or base64 — it works out which one you gave it.
How CBOR writes a value
Every item starts with one byte split in two: the top three bits are the major type and the bottom five are an argument. Arguments 0–23 are the value itself; 24, 25, 26 and 27 mean "the next 1, 2, 4 or 8 bytes hold it"; 31 means "indefinite length, read until a break byte".
- 0 and 1 — integers. Positive and negative are separate types, and a negative is stored as
−1 − n, so-1is0x20and costs one byte. Values 0–23 fit entirely in the first byte. - 2 and 3 — byte strings and text strings. Length prefix, then the bytes. Text is UTF-8, with nothing escaped: a string full of quotes and backslashes encodes to exactly its own bytes.
- 4 and 5 — arrays and maps. A count, then that many items (twice that many for a map). No brackets, no commas, no colons.
- 6 — tags. A number that changes how the next item should be read: 0 and 1 are date-times, 2 and 3 are arbitrary-precision integers.
- 7 — the rest.
false,true,null,undefined, and the three float widths.
The parts JSON has no word for
Decoding CBOR into JSON runs into three things JSON cannot express, and each is handled explicitly rather than quietly dropped:
- Byte strings become
{"$bytes":"01020304"}— hex, so the value survives a trip through a text pane instead of being mangled by a lossy decode. - Bignums (tags 2 and 3) are decoded to exact JavaScript
BigInts and written out as decimal digits. A 64-bit-plus integer keeps every digit rather than rounding to the nearest double. - Half-precision floats — CBOR's cheapest float, two bytes — are decoded by hand, including the subnormal range and the infinities. Nothing else in this network emits them, and plenty of embedded senders do.
- Indefinite lengths — arrays, maps and strings written as a stream of chunks ending in a break byte — are read as ordinary values. Streaming senders use them constantly.
Options
float32 where exact
A non-integer number is float64 by default: nine bytes. Ticked, values that survive a round
trip through single precision unchanged are written as float32 instead, halving that.
1.5 qualifies; 0.1 does not, and stays 64-bit rather than losing
precision to save four bytes.
Canonical map order
RFC 8949 §4.2.1 defines a deterministic encoding where map keys are sorted by their
encoded bytes — which means shorter keys first, and only then bytewise. That is not
alphabetical: z sorts before aa. Tick this when the bytes have to
be reproducible across implementations, which is the case whenever they are going to be
signed or hashed. Leave it off and insertion order is preserved.
Drop null-valued keys
Omits keys whose value is null before encoding. Useful against a schema where absent and null mean the same thing, and destructive where they do not.
CBOR or MessagePack?
They solve the same problem and are close in size — usually within a byte or two of each other on the same document. Choose CBOR when a specification tells you to: it is an IETF standard with a defined deterministic encoding, a tag registry, and an extension model that other standards build on (COSE, CWT, WebAuthn). Choose MessagePack when you are picking for yourself and want the widest set of mature libraries. Encode the same document in both and compare the byte counts in each status line — on your data, not on a benchmark.
Limits
- Encoding starts from JSON, so it emits only the types JSON has. It will not produce byte strings, tags or half floats — it reads all of them.
- Integers beyond 2^53 arriving as JSON have already lost precision before this tool sees them; JSON numbers are doubles. Decoding to JSON keeps them exact, because that path can use BigInt.
- Only the first item in a byte sequence is decoded. Trailing bytes are counted and reported rather than silently ignored — a CBOR sequence is several documents, not one.
- Duplicate map keys collapse, because a JSON object cannot hold two of the same key. CBOR permits them and deterministic encoding forbids them.