Base64 to TSV

Paste the string, read the table. Most decode failures come from three fixable things: a URL-safe alphabet, stripped padding, and a data URI prefix nobody removed. This page repairs all three, then shows you where the tabs landed.

Nothing decoded yet. Paste a string, drop a file on the box, or load one of the samples below.

Input reading

    The decoded table appears here, one column per tab.

    0Input chars
    0Decoded bytes
    0Rows
    0Columns
    0Ragged rows
    noneLine endings
    Try a string

    Read the failure before you edit the string

    A decoder gives you one of three outcomes, and each points at a different repair. Knowing which one you have saves you from rewriting a string that was never broken.

    Refuses to decode

    The string holds characters outside the alphabet, or its length is not a multiple of four once padding is counted. Hyphens and underscores mean a URL-safe encoder produced it. Spaces sitting where plus signs belong mean a form or a URL decoder ate them. Both are mechanical fixes, applied here before the decode runs.

    Decodes into nonsense

    The bytes were fine and the character encoding was not. Names arriving as Zürich mean UTF-8 bytes read as Latin-1 somewhere upstream. A first header cell starting with  is a byte order mark the reader failed to skip.

    Decodes into text with no tabs

    Nothing failed. The source was never TSV. Commas point at CSV, braces at JSON, an angle bracket at XML or HTML. A column meter reading 1 on a table with forty rows is the tell.

    What gets repaired without asking

    Four fixes run before decoding, and the input reading panel names each one that fired, so you learn what the original string held:

    One thing stays unfixable: a truncated string. Base64 carries no length field and no checksum, so a copy that lost its last quarter decodes without complaint into a table that stops mid-row. Check the row count against what you expected rather than trusting a green status line.

    Tabs are invisible, so the page draws them

    The whole failure mode of TSV is a separator nobody sees. The Hidden characters view marks every one:

    The ragged row meter counts rows whose column count differs from the header. Importers align by position, so a single row missing one tab shifts every later value one field to the left.

    Getting the table into a spreadsheet

    Copy the raw text, open a blank sheet, paste. Excel and Google Sheets both split pasted text on tabs, which is the one thing TSV does better than CSV. Sheets asks nothing at all. Excel occasionally opens the Text Import Wizard, where you pick Delimited and tick Tab.

    Saving to a file needs one extra thought. Excel reads a .tsv file as the system code page unless the bytes open with a UTF-8 byte order mark, so accented names and CJK text turn into mojibake. The download button writes that marker for you. Pasting from the clipboard carries text rather than bytes, so the question never comes up there.

    Numbers stored as text are the other trap. A leading zero in a product code survives the decode perfectly, then disappears when Excel reads the column as a number. Format the column as text before you paste.

    Doing the same decode in code

    Once this turns into a repeat job, move it into a script. Each version below matches what the page does, minus the automatic repairs:

    PHPstrict, URL-safe repaired
    $b64 = strtr($b64, '-_', '+/');$tsv = base64_decode($b64, true);if ($tsv === false) { throw new RuntimeException('bad base64'); }
    $rows = array_map(fn($l) => explode("\t", $l), explode("\n", trim($tsv)));
    Pythonpadding restored
    import base64, csv, io
    raw = base64.urlsafe_b64decode(b64 + '=' * (-len(b64) % 4))rows = list(csv.reader(io.StringIO(raw.decode('utf-8')), delimiter='\t'))
    JavaScriptUTF-8 safe
    const bytes = Uint8Array.from(atob(b64), c => c.charCodeAt(0));const tsv = new TextDecoder('utf-8', {fatal: true}).decode(bytes);
    Shellcoreutils
    echo "$B64" | base64 --decode > export.tsv
    column -t -s $'\t' export.tsv | head

    The JavaScript line is where people slip. atob returns a binary string whose characters are single bytes, so treating the result as text mangles anything outside ASCII. The TextDecoder step turns those bytes into real characters, and fatal: true throws on invalid UTF-8 instead of filling your table with replacement diamonds.

    Base64 is an encoding, not a lock. A string sitting in a log file, a URL, or a support ticket is readable by anyone who pastes it into a decoder, this page included. Treat an encoded customer export with the same care as the plain file. If a string someone sent you turns out to hold personal data, that data was never protected in transit.

    Where this page stops

    Decoding, the shape check, and file reading all happen in this tab. Nothing is uploaded and nothing is stored, so closing the page discards the lot.

    File input is capped at 2 MB of Base64, roughly 1.5 MB of decoded table. Bigger exports belong on the command line, where base64 --decode finishes in a moment and no textarea has to hold the result.

    Only text comes out. A string holding a zip, an image, or a spreadsheet binary decodes to bytes that are not valid UTF-8, and the status says so rather than showing you garbage. Base64 to file handles those.

    No delimiter guessing happens. Semicolon and pipe separated data decodes fine and reports one column, because a tab is the only separator the table view reads.

    The table view renders every decoded row, which turns slow in the browser past a few thousand of them. The raw text view stays responsive at any size the file cap allows.

    Nearby pages

    Going the other direction, TSV to Base64 encodes a table and checks its shape first. When the decoded text turns out to be comma separated, Base64 to CSV fits better. Base64 validator checks a string before you decode it at all, and TSV to JSON turns the decoded rows into records once you have them.

    Questions that come up mid-decode

    What people ask once a real string is in the box.

    The string has hyphens and underscores. Is it broken?

    No, it uses the URL-safe alphabet from RFC 4648 section 5, where hyphen and underscore stand in for plus and slash so the string survives a query parameter. JWTs and signed links use it. This page translates the characters back before decoding, and the input reading panel says when that happened.

    Why does my decoder complain about the length?

    Base64 packs three bytes into four characters, so the length has to be a multiple of four once padding is counted. Many encoders drop the trailing equals signs because most decoders work the length out anyway. Strict ones refuse, including PHP base64_decode with the strict flag. Padding is restored here before decoding.

    The text decoded but the accents are wrong. What happened?

    The bytes are intact and the character encoding is not. Zurich arriving as Zürich means UTF-8 bytes were read as Latin-1 at an earlier step. Load the Latin-1 sample to see what that looks like. The fix belongs wherever the file was written, since the damage predates the encoding.

    My table shows one column. Where did the tabs go?

    Either the source was never tab separated, or the tabs became spaces before encoding. Check the raw view: commas mean CSV, runs of spaces mean a form or a chat client reformatted the text. Base64 preserves whatever it was handed, so a single column means the tabs were already gone at encode time.

    Can I decode part of a string?

    Only on a four character boundary, and the result still starts mid-row. Base64 carries no length marker and no checksum, so a truncated string usually decodes without error into a table that simply ends early. Compare the row count against what you expected.

    What if the decoded bytes are not text?

    The status reports invalid UTF-8 rather than filling the table with replacement characters. That usually means the string holds a zip, an image, or a spreadsheet binary. Base64 to file handles those, since a table view has nothing useful to show for them.

    Will the downloaded file open correctly in Excel?

    Copy and paste works with no setup, because Excel and Google Sheets both split pasted text on tabs. A saved file needs a UTF-8 byte order mark or Excel reads it as the system code page and mangles accented characters, so the download button writes that marker.

    Is anything sent to a server?

    No. Decoding and the shape check run in JavaScript in this tab, and nothing is stored. Keep in mind that Base64 is not encryption, so a string sitting in a log or a URL was already readable by anyone who found it.