An extended public key, or xpub, is one string from which a wallet can calculate every receiving and change address of an account, without being able to spend from any of them. Its first four letters hint at the address type: a ypub or a zpub is the same key as an xpub with different version bytes, added so that a wallet would know whether to make addresses that start with 3 or with bc1q. This guide explains what is inside an extended key, which prefix belongs to which address type, how to convert between them, where wallets show yours and why it should stay private. The keys come from your seed phrase through a derivation path.
In a BIP32 wallet, every key in the tree comes with a 32-byte chain code. A public key plus its chain code is an extended public key, and it is enough to derive that key's non-hardened children: the account key at m/84'/0'/0' produces the receiving addresses at …/0/0, …/0/1 and so on, and the change addresses at …/1/i. That is why one xpub can stand for a whole account.
So an xpub is what you give to software that only needs to watch: a watch-only wallet on your phone, a payment server that creates a fresh address for each invoice, or the coordinator of a multisig wallet that needs every cosigner's public key.
BIP32 defined one mainnet version for public keys, which encodes as xpub, and one for private keys, xprv (tpub and tprv on testnet). It said nothing about address types, so a wallet given an xpub had to guess. SLIP-132 registered more version bytes so that the prefix would tell:
| Prefix | Version bytes | Address type | Standard | Addresses start with |
|---|---|---|---|---|
| xpub | 0488b21e |
Legacy (P2PKH) or P2SH | BIP44 | 1 or 3 |
| ypub | 049d7cb2 |
Nested SegWit (P2WPKH in P2SH) | BIP49 | 3 |
| zpub | 04b24746 |
Native SegWit (P2WPKH) | BIP84 | bc1q |
| Ypub | 0295b43f |
Multisig, nested SegWit (P2WSH in P2SH) | — | 3 |
| Zpub | 02aa7ed3 |
Multisig, native SegWit (P2WSH) | — | bc1q |
On testnet the same pattern gives tpub, upub and vpub (Upub and Vpub for multisig), and other coins registered their own, such as Ltub and Mtub for Litecoin. Each public prefix has a private twin: xprv, yprv and zprv. Those are full private keys for the account and deserve the same protection as the seed phrase. Taproot accounts (BIP86) have no prefix of their own and use a plain xpub.
BIP32 serializes an extended key as 78 bytes and encodes them in Base58Check, which adds a 4-byte checksum, so the string always has 111 characters. Here are the fields of the native SegWit account key of the public test phrase (abandon abandon … about):
| Field | Bytes | In the example |
|---|---|---|
| Version | 4 | 04b24746 (zpub) or 0488b21e (xpub) |
| Depth | 1 | 03: three steps below the master key, m/84'/0'/0' |
| Parent fingerprint | 4 | 7ef32bdb: identifies the parent key, m/84'/0' |
| Child number | 4 | 80000000: account 0, hardened |
| Chain code | 32 | 4a53a0ab21b9dc95… |
| Public key | 33 | 02707a62fdacc26e…, a compressed secp256k1 key |
Only the first four bytes differ between the xpub and the zpub of an account. Because they come first, though, the whole Base58 string changes, and the two look like unrelated keys.
These are the account keys of the BIP39 test phrase, whose master key fingerprint is 73c5da0a. The phrase is public, so never send funds to it. Each key derives, on its own, the first receiving address of its standard, the same addresses as in our derivation path guide:
| Standard | Account path | Prefix used | First address, …/0/0 |
|---|---|---|---|
| BIP44 | m/44'/0'/0' |
xpub | 1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA |
| BIP49 | m/49'/0'/0' |
ypub | 37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf |
| BIP84 | m/84'/0'/0' |
zpub | bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu |
| BIP86 | m/86'/0'/0' |
xpub | bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr |
BIP44 xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj
BIP49 ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP
= xpub6C6nQwHaWbSrzs5tZ1q7m5R9cPK9eYpNMFesiXsYrgc1P8bvLLAet9JfHjYXKjToD8cBRswJXXbbFpXgwsswVPAZzKMa1jUp2kVkGVUaJa7
BIP84 zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs
= xpub6CatWdiZiodmUeTDp8LT5or8nmbKNcuyvz7WyksVFkKB4RHwCD3XyuvPEbvqAQY3rAPshWcMLoP2fMFMKHPJ4ZeZXYVUhLv1VMrjPC7PW6V
BIP86 xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ
The BIP84 and BIP86 keys are the official test vectors of those BIPs, and SLIP-132 lists the same xpub, ypub and zpub in its own test vectors; we derived all of them again with the @scure/bip32 library. The seed phrase to private key converter shows the account extended keys of any test phrase, always with the xpub prefix.
SLIP-132 has no prefix for Taproot: BIP86 accounts use a plain xpub, as the table above shows. Instead of adding prefixes, wallets moved to output script descriptors, which write the address type, the key origin and the key in one line:
wpkh([73c5da0a/84h/0h/0h]xpub6CatWdiZiodmUeTDp8LT5or8nmbKNcuyvz7WyksVFkKB4RHwCD3XyuvPEbvqAQY3rAPshWcMLoP2fMFMKHPJ4ZeZXYVUhLv1VMrjPC7PW6V/0/*)
tr([73c5da0a/86h/0h/0h]xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)
Descriptors are defined in BIP380 to BIP386: pkh() and sh() in BIP381, wpkh() in BIP382 and tr() in BIP386. Bitcoin Core has supported them since version 0.17. BIP380 calls extra version bytes a layer violation, because key derivation should stay separate from the script type, and its key expressions accept only BIP32's own xpub and xprv encodings. Bitcoin Core therefore rejects a ypub or zpub in a descriptor: convert it to an xpub first. BTCPay Server follows the same idea with its own notation. A plain xpub means native SegWit, xpub…-[p2sh] nested SegWit and xpub…-[legacy] legacy addresses, and a ypub or zpub you enter is converted to an xpub when the wallet is set up.
Since only the version bytes differ, converting is a matter of decoding the Base58Check string, swapping the first four bytes and encoding it again; the key and the addresses stay the same. Electrum does it from the command line or its console: electrum -o convert_xkey <key> p2wpkh re-encodes a key as a zpub, p2wpkh-p2sh as a ypub and standard as an xpub (in the Console tab, convert_xkey('zpub…', 'standard')). Sparrow shows both forms of a SegWit key and has a button to switch between them. Convert only public keys, and never paste an xprv, yprv or zprv into a website.
A plain xpub does not carry its address type with it. If you import the xpub of a native SegWit account, tell the wallet: choose Native Segwit in Sparrow, use a wpkh() descriptor in Bitcoin Core, or convert the key to a zpub for Electrum, which reads the type from the prefix. Otherwise the wallet derives legacy addresses that hold nothing.
Each wallet below was checked against its latest release in October 2026:
| Wallet | Where to find it | What it shows |
|---|---|---|
| Electrum 4.8 | Wallet → Information → Master Public Key | xpub, ypub or zpub by script type; Ypub or Zpub for multisig |
| Sparrow 2.5 | Settings → Keystores → the keystore's xpub field | xpub, with a switch to show a SegWit key as ypub or zpub |
| BlueWallet 8 | Wallet → … → Show Wallet XPUB | zpub (BIP84), ypub (BIP49), xpub (legacy); Taproot as a tr() descriptor |
| Trezor Suite | Account → Details → Public key (XPUB) → Show public key | A descriptor with zpub, ypub or xpub; Taproot as tr() with an xpub |
| Ledger Wallet | Account → settings icon (Edit account) → Advanced | Always xpub, with a note naming its address type |
| Bitcoin Core | listdescriptors in the console (Window → Node window) |
Plain xpubs inside descriptors |
A few details matter when you move a key between them:
importdescriptors in a wallet with private keys disabled; the descriptor sets the address type.A watch-only wallet built from your xpub shows balances and creates receiving addresses while the private keys stay on your hardware wallet or offline computer. To spend, you build the transaction in the watch-only wallet and sign it with the device that holds the keys, usually as a PSBT. Three settings decide whether the balance appears:
tr() descriptor.An xpub cannot move funds, but it takes away your privacy: whoever has it can list every address of the account, past and future, see every balance and payment, and follow you as you receive coins. Give it only to software you control or trust, such as your own payment server or watch-only wallet.
There is also a security catch. BIP32 warns that knowing a parent extended public key plus any non-hardened private key that descends from it is equivalent to knowing the parent extended private key. If your account xpub has leaked and you export the private key of a single address, for example to import it into another app, an attacker who gets that key can compute the private keys of the entire account. Keep both secret, and prefer moving funds with ordinary transactions over exporting keys.
Not with the xpub alone: it holds no private key. It reveals every address and balance of the account, and together with any one private key from the same account it gives away all of them, so keep it private.
Wallets that follow SLIP-132 put the address type into the prefix: Electrum and BlueWallet show a zpub for a native SegWit account. Ledger Wallet, Bitcoin Core and, by default, Sparrow show a plain xpub and store the address type separately. Both are the same key, as the test vectors above show.
No. SLIP-132 registered none, and BIP86 accounts use a plain xpub. A tr() descriptor records that the key is meant for Taproot.
The xprv is the private half: it contains the private key and can derive every private key of the account, so it can spend. The xpub can only derive public keys and addresses.
Yes, because they are different seeds. So does the same phrase with a BIP39 passphrase: each passphrase leads to a different master key and a different set of xpubs.