Skip to main content
In-browser tool — no account, no upload

Zero motorcycle log reader

Drop the .bin your bike or your dealer gave you and read it as plain text — here, now, in this tab. Then download the .txt.

Your file is never uploaded. It is decoded by JavaScript in your browser.

Open developer toolsPress F12 and select the Network tab.
Drop your logUse the reader below as you normally would.
Watch the request listYour file never appears in it. Decoding issues no request at all.

You will see some traffic, and it is worth knowing what it is: the page loads its own scripts and fonts, quietly prefetches a few of its own pages (the cookie and privacy notices), and loads Google Analytics if you accepted analytics cookies. That is the site, and none of it carries your log. The decoder itself contains no fetch, no XMLHttpRequest, no WebSocket and no beacon: your file is read with File.arrayBuffer(), decoded in memory, and written to a blob: URL — an in-memory handle, not a request — when you download it. Close the tab and it is gone. Nothing about your bike is stored, and there is no account to create.

The other half of privacy is what you publish yourself, so this page starts with Mask identifiers already ticked: the VIN and the board serial are replaced with X in the result, in the decoded text, in the .txt and in the name that file is saved under — a Zero export is named by its VIN, so the file name alone identifies the bike. Untick it to read your own log in full; nothing is withheld from the decode itself.

A valid Gen3 log can contain no rides at all. Gen3 writes into a ring buffer that overwrites itself oldest-first: a parked bike wakes about once an hour and writes a median of 31 entries, so the buffer fills in roughly 3.1–3.3 parked days — faster still while riding or charging, when the boards write several times as often. Anything older than that is already gone from the file you just decoded — not lost by this tool, overwritten by the bike. Why your Gen3 log shows no rides covers how to recognise it and how to export before it happens. Keeping history means keeping the files: an account stores each export and stitches overlapping ones into one continuous timeline per VIN. This decoder stays free and complete either way.

What comes out, and what does not

Three of the four log families Zero has shipped decode here, with the same field maps the server-side pipeline uses. The fourth is identified and handed to the right tool. The reader tells you which one you dropped, and why it decided that, before you read a single entry.

Log familyBikesHereWhat you get
Gen3 MBBCypher III: SR/F, SR/S, DSR/X, FXEDecodedText events, the state machine, state of charge, four temperatures. No electrical telemetry — on this platform that lives in the BMS log.
Gen3 BMSCypher III battery boardsDecodedCell minimum and maximum, state of charge, pack current and voltage, pack temperature, the BMS state machine and the full-charge-capacity register.
538XX-firmware MBBGen2-era bikes carrying the Gen3-style bodyDecodedThe one MBB that does carry pack voltage, current, speed and motor/controller temperatures alongside the odometer.
Gen1 / Gen2Cypher II / SDS: S, SR, DS, DSR through 2023, and the FX/FXS/FXE light bikesIdentifiedRecognised and identified — header, VIN and board come back — but the entries are not decoded here. See below for what to do with one.

Why Gen1/Gen2 is not decoded here

Gen2 spreads the telemetry this port reads across four record types — 0x2c, 0x3c, 0x2d and 0x33 — and the browser port reads one of them. Its typed events (Riding, Charging, Discharge level, SOC Data) need a message table this port does not carry.

Shipping that anyway would recover 0.73% of pack-voltage rows, 0.96% of current, 1.12% of state of charge and nothing at all from a BMS file — measured, not estimated. A decode that thin, labelled as support, is worse than an honest refusal.

Two things do read these files: zero-log-parser, which runs on your own machine as a command-line tool, and the full analyser here, which runs that same engine server-side — upload the file and it is read properly.

It reports what it could not read

Every decode prints its own diagnostics, never behind a toggle: the framing strategy, how many 0xB2 delimiters were found, how many became records, and — separately — why the rest did not. An erased flash slot is not a torn record, and a decoder that reported them as one number would be hiding the difference.

Measured on a real 256 KB 538XX log: 7,776 delimiters, 6,458 records framed, 1,211 erased flash slots, 106 timestamps outside the window, one record too short and one with an implausible length. Also printed: a record-type histogram, and every field value a physical range check refused rather than guessed.

The same decode was validated field-for-field against the Python parser that runs our server pipeline, over 352 real log files and 1,190,446 entries, with zero divergences. That is a portability guarantee, not a correctness one: where the server decoder is wrong, this one is wrong identically — which is exactly what makes it a useful cross-check.

A valid Gen3 log can contain no rides at all

This is the failure that looks like a broken tool and is not one. Each Gen3 board keeps its own ~128 KB ring buffer holding roughly 2,300 entries. A parked bike is not idle: the MBB wakes about once an hour and writes a measured median of 31 entries per wake-up, so a bike left alone fills its buffer with hibernation in about three days — 3.25 at the measured median rate — and everything older is overwritten, oldest first.

So a file exported a week after your last ride can decode perfectly and still hold nothing but hibernation. The rides were gone before you dropped the file. Export within a day or two of riding to keep them, and read why your Gen3 log shows no rides for how to recognise a buffer that has already wrapped.

What an account adds

Nothing above is held back for it. The reader gives you every entry it can decode, the full diagnostics and the complete .txt, with no sign-up and no cap. An account exists for the one thing a single file cannot give you: a single file is a three-day window on a parked Gen3, because the bike overwrites it — not us.

History across files

Every export you keep is stitched into one continuous timeline per VIN, with overlapping files deduplicated instead of double-counted.

Rides and charges

Sessions are detected from the telemetry — distance, energy, duration — including charges the current sensor was too sparse to record directly.

Battery health and faults

Usable pack capacity measured from real charges against the nameplate figure, cell imbalance over time, and error codes grouped into findings.

Uploaded logs are also read by an AI pass that explains faults and the state of the pack in plain language — and, unlike the reader on this page, the full pipeline reads Gen1/Gen2 files too.

Frequently asked questions

Is my log file uploaded anywhere?

No. The decoder is JavaScript running in your own tab. Your file is read with the browser file API, decoded in memory and rendered from a blob URL when you download it. There is no fetch, no XHR, no WebSocket and no beacon in the decoder or in the decoding library, so there is no request to intercept. Open your browser developer tools, select Network, then drop the file: your log never appears in the list. Any traffic you do see is the site loading its own scripts and prefetching its own pages, never your file.

Which Zero log files can this reader decode?

Gen3 MBB, Gen3 BMS and the 538XX-firmware MBB variant decode in full, with the same field maps the server-side pipeline uses. Gen1/Gen2 logs (Cypher II / SDS) are recognised and identified but not decoded in the browser. Of the 352 real log files this decoder was validated against, 67 decode here, for 317,124 entries.

My Gen3 log decoded but shows no rides. Is the tool broken?

No — the rides were already gone from the file. Gen3 boards write into a fixed ring buffer that overwrites itself oldest-first. A parked bike wakes about once an hour and writes a median of 31 entries, so roughly three days of standing fills the buffer with hibernation and pushes everything older out of it. Export within a day or two of a ride to keep the ride in the file.

Can I read a Gen1/Gen2 log (S, SR, DS, DSR, FX) here?

The reader identifies it and tells you what it is, but it does not decode the entries. Gen2 stores type-tagged variable-length messages rather than the 0xB2 ring buffer this port reads. Run the upstream zero-log-parser project locally, or upload the file to the full analyser here, which runs that engine server-side.

Does the firmware build date in the header tell me whether my log will decode?

No, and it is worth saying so because it looks like it should. Across the 352-file corpus, 135 files carry a build date in the header. No cut-off year separates the files that decode from the ones that do not: the best threshold still misclassifies eleven of them, because a Gen2 bike can carry firmware built in 2024 and a Gen3 bike can carry firmware built in 2019. The reader decides by looking at the file itself, and tells you which rule fired, in about twenty milliseconds.

Do I need an account to use this?

No. There is no sign-up, no cap on file size beyond a 32 MB refusal that protects your own browser, no watermark and no truncated output. An account exists for the things one file cannot give you — history stitched across several exports per VIN, sessions, battery health, faults and AI analysis — not for this conversion.

What is in the .txt file I download?

A header block (source file, size, log kind, VIN, model, board, firmware, serial), then every decoded entry as a timestamped table, then a decode summary listing the framing strategy, how many 0xB2 records were framed, why the rest were not, a record-type histogram and the values each plausibility gate refused. Timestamps are UTC exactly as stored in the record, with no timezone applied. "Mask identifiers" starts ticked on this page, so the VIN and the board serial are replaced with X in the header block, in the entry text, and in the file name the download is saved under. Untick it to get the log in full.

How large is the decoded text?

Measured on real logs: a 128 KB Gen3 MBB export with 2,535 entries produces about 226 KB of text, a 128 KB Gen3 BMS export with 899 entries about 81 KB, and a 256 KB 538XX MBB export with 4,269 entries about 732 KB. A Gen1/Gen2 file produces a 1.3 KB identification report instead of an entry table.