What you can decode here
- A QR code image
- PNG, JPG, JPEG, GIF, BMP or WebP. Drag it in, click to browse, or paste it with Ctrl+V. A screenshot works, and so does a photo of another screen — useful when the app blocks screenshots.
-
An
otpauth://URL -
Paste the link itself, for example
otpauth://totp/ACME:john@example.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME. - A raw Base32 secret
-
Something like
HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ. Spaces, dashes and lowercase letters are fine — they get normalised. - A Google Authenticator export QR
-
The
otpauth-migration://offline?data=format, which holds several accounts in one code. All of them are decoded at once.
For every account you get a live six-digit code with a
countdown, the Base32 secret, the full
otpauth:// URL, and a
freshly generated QR code you can scan into another app.
How to decode a Google Authenticator export QR code
- Export from the app. In Google Authenticator, open the ⋮ menu → Transfer accounts → Export accounts, then pick the accounts you want. Google packs at most ten accounts into one QR code; with more, it produces several codes in sequence.
- Capture the code. On Android the export screen blocks screenshots, so the reliable way is to photograph the screen with a second phone or a camera. That photo decodes here just fine.
-
Decode it.
Drop the photo or screenshot above — or, if you
already have the string, paste
otpauth-migration://offline?data=…directly. -
Import where you need it.
Each account gets its own QR code and
otpauth://URL, so you can add them to another authenticator one at a time.
The export QR code won't scan
A code carrying ten accounts is dense, and dense codes fail to read — especially from a photo taken at an angle or in poor light. The fix that reliably works is exporting in smaller batches of about four accounts: each code becomes sparser and scans on the first try. Repeat the export as many times as you need.
What is inside an otpauth-migration URL
The data parameter is
base64url-encoded protobuf. Inside sits a
MigrationPayload message
with a repeated list of
OtpParameters — one entry
per account, each holding the raw secret bytes, the
label, the issuer, and the algorithm, digit and type
enums. This page parses that structure locally and
re-encodes each secret to Base32.
Move your 2FA codes to a new phone or another app
Decode the export first, store the secrets somewhere you trust, then verify that you can actually log in to two or three accounts from the new device. Only after that should you remove anything from the old phone or wipe it — a secret you never tested is not a backup.
The otpauth:// URLs and
per-account QR codes import into Aegis, Ente Auth, 2FAS,
Bitwarden, 1Password, KeePassXC, Proton Pass and most
other authenticators — one code at a time.
Two things this tool cannot help with, to save you the
attempt: Microsoft Authenticator does not export its
secrets in any readable form, and Steam Guard uses its
own format rather than an
otpauth:// QR code.
Is it safe to decode a 2FA QR code here?
The sensible default is to never paste TOTP secrets into an online service, and that advice is correct — most QR decoders on the web send your image to a server. The difference here is architectural: there is no server to send it to.
The image is read by
jsQR on a canvas in the
page, migration payloads are parsed by
protobufjs, and codes are
computed by
totp-generator. No step
makes a network request with your data. There is no
backend, no form submission, and nothing is written to
storage.
Verify it yourself
- Open DevTools → Network, clear it, then decode something. No request carries your QR contents.
- Turn off your network after the page has loaded. Decoding keeps working.
- Read the source: github.com/VizzleTF/TOTP_decoder.
- Save the page and its bundle, then open the file from disk with no connection at all.
One honest caveat: the page does load an anonymous visit counter (Vercel Analytics), which reports the URL and nothing else. It has no access to your QR contents, secrets or generated codes — but it is a network request, so you will see it in DevTools and you should know what it is.
When to use an offline tool instead
Your trust here rests on the code being delivered honestly over HTTPS. That is a real assumption: whoever controls the hosting could in principle serve different JavaScript. For high-value secrets — corporate accounts, crypto exchanges — run a local tool on a machine that is offline, such as scito/extract_otp_secrets or dim13/otpauth.
otpauth:// URL format reference
A complete TOTP URL looks like this:
otpauth://totp/ACME%20Co:john.doe@example.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30
| Parameter | Required | Values | Default |
|---|---|---|---|
| type | yes | totp | hotp | — |
| label | yes | Issuer:Account, URL-encoded | — |
| secret | yes | Base32, A–Z and 2–7 | — |
| issuer | no | service name | — |
| algorithm | no | SHA1 | SHA256 | SHA512 | SHA1 |
| digits | no | 6 | 8 | 6 |
| period | no | seconds, TOTP only | 30 |
| counter | HOTP only | integer | — |
Many authenticators quietly ignore
algorithm and
digits and just assume
SHA-1 with six digits, which is why a code can look
wrong even when the secret is right. Unrecognised
parameters should simply be ignored by whatever reads
the URL.
Base32 secrets: length and common errors
Secrets are usually 16, 26 or 32 characters. The Base32
alphabet is A–Z plus the digits 2–7 only, so if your
string contains
0,
1,
8 or
9, it is not Base32 —
that is the usual cause of an "invalid secret" error.
Trailing = padding is
optional, and case does not matter.
FAQ
Does my QR code or secret get uploaded anywhere?
No. Decoding happens in your browser and there is no backend to receive anything. The only network request after page load is an anonymous visit counter that sees the URL and nothing else.
Can I decode an export QR with several accounts at once?
Yes. A
otpauth-migration://
payload holds up to ten accounts and all of them
are listed separately, each with its own code,
secret and QR.
Why can't I screenshot the export QR code?
Google Authenticator marks the export screen as secure on Android, which blocks screen capture. Photograph the screen with another device and upload the photo instead.
My export QR code won't scan. What do I do?
Export fewer accounts per code — around four is a good target. The resulting QR is much less dense and reads reliably from a photo.
How long should a TOTP secret be?
In practice 16 to 32 Base32 characters, which is 80 to 160 bits. Anything shorter than 16 characters is unusually weak; anything using digits outside 2–7 is not Base32 at all.
My code is rejected even though the secret is right. Why?
Usually the device clock has drifted — TOTP is
time-based, so even a minute of skew breaks it.
Otherwise check that
period,
digits and
algorithm match
what the service actually expects.
Can I use this to move codes into Bitwarden, Aegis or 1Password?
Yes — each account here produces a standard
otpauth:// URL
and a scannable QR code, which is exactly what
those apps accept.
Does it work with Microsoft Authenticator?
No. Microsoft Authenticator has no way to export its TOTP secrets or show them as a QR code, so there is nothing to decode.
Does it work with Steam Guard?
No. Steam stores its shared secret in its own
file format rather than an
otpauth:// QR
code, so this tool does not apply.
Is this open source?
Yes, MIT licensed. The full source is at github.com/VizzleTF/TOTP_decoder.