01The opcode
| Property | Value |
|---|---|
| Opcode | OP_IF = 0x63 |
| Companions | OP_NOTIF (0x64), OP_ELSE (0x67), OP_ENDIF (0x68) |
| Disabled siblings | OP_VERIF (0x65), OP_VERNOTIF (0x66) — fail script if encountered, even inside an unexecuted branch |
| Semantics | Pop top of stack. If non-zero, execute <then>; otherwise execute <else> if present. OP_NOTIF inverts. |
| Activated | Original Bitcoin Script (block 0, January 2009) |
| Tapscript change | BIP 342 §"MINIMALIF": the popped value must be exactly the empty array (false) or 0x01 (true). Arbitrary truthy values fail at consensus, not just relay. |
OP_IF is the foundational branching primitive in Bitcoin Script. Every script that admits more than one spending path uses OP_IF or its sibling OP_NOTIF.
02Pattern catalog
The 12 distinct production patterns that use OP_IF on Bitcoin mainnet — from a 2-byte plain conditional to the 853-byte tapscript leaves carrying every Ordinal inscription.
<witness chooses 1 or empty> OP_IF <branch A — pubkey + OP_CHECKSIG> OP_ELSE <branch B — different pubkey or hash check> OP_ENDIF
The spender selects which branch executes by pushing 1 (or any truthy value) or an empty bytestring before the script runs. This is the foundational pattern; everything below is a specialization.
The single most consequential OP_IF pattern in Bitcoin's history. An HTLC says: "Either the recipient produces the preimage of a known hash and takes the funds, or after a timeout the sender can reclaim them."
OP_IF OP_SHA256 <H = SHA256(preimage)> OP_EQUALVERIFY <recipient_pubkey> OP_CHECKSIG OP_ELSE <expiry> OP_CHECKLOCKTIMEVERIFY OP_DROP <sender_pubkey> OP_CHECKSIG OP_ENDIF
Powers:
- Atomic swaps (Bitcoin ↔ Litecoin, Bitcoin Cash, etc.) — same preimage on two chains, different recipients on each side
- Submarine swaps (on-chain ↔ Lightning) — Loop, Boltz
- Pre-Lightning payment channels (Spillman, Decker–Wattenhofer)
- Cross-chain bridges that don't require federations
to_local outputEvery commitment transaction in every Lightning channel ever opened has one of these. Encodes "either the counterparty proves I cheated and steals everything (revocation), or I wait to_self_delay blocks and take my own money (delayed self-spend)."
OP_IF # Revocation: counterparty has the secret if we breached <revocationpubkey> OP_ELSE # Honest delayed self-spend <to_self_delay> OP_CHECKSEQUENCEVERIFY OP_DROP <local_delayedpubkey> OP_ENDIF OP_CHECKSIG
Witness paths:
- Revocation: push
<revocation_sig>then<1>to take theOP_IFbranch. - Self-spend: push
<local_delayed_sig>then<>(empty) to takeOP_ELSE.
When a Lightning node forwards a payment, the outgoing-direction HTLC output has a nested OP_IF/OP_NOTIF. Three spending paths in one script.
OP_DUP OP_HASH160 <RIPEMD160(SHA256(revocationpubkey))> OP_EQUAL OP_IF OP_CHECKSIG # Path 1: revocation OP_ELSE <remote_htlcpubkey> OP_SWAP OP_SIZE 32 OP_EQUAL OP_NOTIF # Path 2: HTLC-timeout (we reclaim after timelock) OP_DROP 2 OP_SWAP <local_htlcpubkey> 2 OP_CHECKMULTISIG OP_ELSE # Path 3: peer claims with preimage OP_HASH160 <RIPEMD160(payment_hash)> OP_EQUALVERIFY OP_CHECKSIG OP_ENDIF OP_ENDIF
Mirror of Pattern 4 for the receiving side of a forwarded payment. Same nested-OP_IF shape with paths reversed:
OP_DUP OP_HASH160 <RIPEMD160(SHA256(revocationpubkey))> OP_EQUAL OP_IF OP_CHECKSIG # revocation OP_ELSE <remote_htlcpubkey> OP_SWAP OP_SIZE 32 OP_EQUAL OP_IF # HTLC-success (we provide preimage) OP_HASH160 <RIPEMD160(payment_hash)> OP_EQUALVERIFY 2 OP_SWAP <local_htlcpubkey> 2 OP_CHECKMULTISIG OP_ELSE # Peer reclaims after timeout OP_DROP <cltv_expiry> OP_CHECKLOCKTIMEVERIFY OP_DROP OP_CHECKSIG OP_ENDIF OP_ENDIF↳ txbook · ch18 §18.5
Uses OP_IFDUP + OP_NOTIF (the sibling family). Anchor outputs let either party CPFP the commitment transaction without needing both signatures.
<funding_pubkey> OP_CHECKSIG OP_IFDUP OP_NOTIF OP_16 OP_CHECKSEQUENCEVERIFY OP_ENDIF
Reads as: "if you own the funding key, spend immediately; otherwise wait 16 blocks." OP_IFDUP keeps the value on the stack only when truthy — the trick that fits this in 30-something bytes.
A general two-path pattern: 2-of-3 multisig or 1-of-1 after timeout. Used by Bisq escrow, OpenBazaar, Lightning Loop, hosted-custody services with timeout fallback.
OP_IF # Cooperative — any 2 of {buyer, seller, arbiter} 2 <buyer> <seller> <arbiter> 3 OP_CHECKMULTISIG OP_ELSE # Buyer alone after timeout <expiry> OP_CHECKLOCKTIMEVERIFY OP_DROP <buyer> OP_CHECKSIG OP_ENDIF↳ txbook · ch16 Exercise C1
Proposed but not activated as of 2026. Vaults use OP_IF to express "either trigger the unvault delay path, or sweep to cold storage immediately."
OP_IF <unvault_template_hash> OP_CHECKTEMPLATEVERIFY OP_DROP <unvault_delay> OP_CSV OP_DROP <hot_pubkey> OP_CHECKSIG OP_ELSE <cold_pubkey> OP_CHECKSIG OP_ENDIF
Status: BIP 119 (OP_CHECKTEMPLATEVERIFY), BIP 345 (OP_VAULT), and related covenant proposals are in active discussion. None has activated.
OP_FALSE OP_IFThe most surprising use of OP_IF in Bitcoin: it's the load-bearing structure of every Ordinals inscription, every BRC-20 token, every recursive inscription, every Runestone commitment that uses Tapscript-based metadata.
<inscriber_pubkey> OP_CHECKSIG OP_FALSE OP_IF OP_PUSH "ord" OP_PUSH 0x01 OP_PUSH "image/png" # MIME type OP_PUSH 0x00 OP_PUSH <…content bytes…> OP_ENDIF
The trick: OP_FALSE ensures the OP_IF branch is never executed. But the Script parser still reads the bytes inside to find the matching OP_ENDIF. So all the data pushes are syntactically present but semantically dead. The transaction signature only needs to satisfy OP_CHECKSIG at the top — the envelope is purely a witness-data carrier.
Why this works only inside Tapscript: the inscription is the script-path leaf of a Taproot output (P2TR, BIP 341/342). The witness discount means each byte costs 1 WU instead of 4 WU, making it economically viable to carry kilobytes of data. Pre-Taproot scripts have a hard 10,000-byte size limit and no witness discount.
↳ txbook · ch19 §19.2Post-Taproot, many multipath conditions migrate from OP_IF to Taproot script-tree leaves — different leaves of the merkle tree replace different OP_IF branches, and the whole tree commitment is the merkle root. This is better than OP_IF for privacy: only the leaf actually spent gets revealed; unused branches stay hidden.
OP_IF still gets used inside individual leaves when the branching isn't worth its own leaf (e.g., a small revocation path bolted onto a single leaf).
DLCs use OP_IF only minimally — most of the conditional logic is encoded outside the script via adaptor signatures and Contract Execution Transactions (CETs). The on-chain OP_IF usage is in the refund path:
OP_IF <2-of-2 between Alice and Bob> OP_ELSE <refund_locktime> OP_CLTV OP_DROP <2-of-2 same pubkeys> OP_ENDIF
The interesting part of a DLC happens off-chain in adaptor-signature land; on-chain the script is mundane.
Pre-Lightning, Mike Hearn's Spillman channels and Jeremy Spilman's CLTV refund construction:
OP_IF 2 <alice> <bob> 2 OP_CHECKMULTISIG OP_ELSE <refund_locktime> OP_CLTV OP_DROP <alice> OP_CHECKSIG OP_ENDIF
Effectively dead in practice (replaced by Lightning), but historically significant — these were the proof of concept that taught the community payment channels could work on Bitcoin without consensus changes.
↳ txbook · ch18 §18.103Sibling opcodes
Wherever OP_IF appears, you may also see:
| Opcode | Hex | Used in |
|---|---|---|
OP_IF | 0x63 | Patterns 1–5, 7–9, 11–12 |
OP_NOTIF | 0x64 | Patterns 4 (offered HTLC), 6 (anchors) |
OP_ELSE | 0x67 | All multi-branch patterns |
OP_ENDIF | 0x68 | All — required to close every OP_IF/OP_NOTIF |
OP_VERIF | 0x65 | Disabled — fails script unconditionally |
OP_VERNOTIF | 0x66 | Disabled — same |
The disabled cousins fail even inside an unexecuted OP_IF branch (per BIP 16 mandatory script flags). This is unusual: most invalid opcodes only fail when actually executed.
04Verified specimen — Inscription #0
The cleanest single example of OP_IF in production: Inscription #0, the first Ordinal ever, mined by Casey Rodarmor on December 14, 2022.
| txid | 6fb976ab49dcec017f1e201e84395983204ae1a7c2abf7ced0a85d692e442799 |
| Block | 767,430 |
| Date | 2022-12-14 20:32 UTC |
| Size | 1,040 bytes total · 1,286 WU · 321.5 vbytes |
| Output type | P2TR (Taproot) |
| Witness | 3 items: 64-byte Schnorr sig, 853-byte tapscript leaf (containing the envelope), 33-byte control block |
| Content | A 793-byte pixel-art skull (image/png), inscribed inside OP_FALSE OP_IF … OP_ENDIF |
The 853-byte tapscript leaf is structured exactly as Pattern 9 above: a <schnorr-pubkey> OP_CHECKSIG lead, then OP_FALSE OP_IF, then the Ordinals envelope ("ord" marker + content-type tag + content data), then OP_ENDIF. Every Ordinal minted since (80+ million as of 2026) follows this exact pattern.
05Where each pattern lives in the txbook
| Chapter | OP_IF use covered |
|---|---|
| ch02 — The Script Machine | Opcode introduction; minimalif rule |
| ch12 — Taproot | Tapscript MINIMALIF rule; script-tree as OP_IF alternative |
| ch13 — Tapscript | OP_IF inside leaves; Tapscript dialect restrictions |
| ch16 — Timelocks | HTLC primitive, multipath escrow exercise |
| ch18 — Lightning | All four BOLT 3 outputs (to_local, offered/received HTLC, anchor) |
| ch19 — Ordinals | The OP_FALSE OP_IF envelope |
| ch20 — Runes | Runestone commitment vs. inscription envelope |
| appA — Opcode Reference | Full OP_IF / OP_NOTIF / OP_ELSE / OP_ENDIF spec rows |
06Note on "every transaction"
Counting individual on-chain transactions containing OP_IF is intractable and not useful: the opcode is plumbing. Order-of-magnitude estimates as of April 2026:
| Pattern | Approx. mainnet usage |
|---|---|
| Lightning channel closures (commitment txs + HTLC txs) | 100,000+ |
| Ordinals inscriptions | 80M+ |
| Atomic swaps | low thousands |
| CPFP/anchor commitments | high thousands |
| Multipath escrow (Bisq, OpenBazaar) | tens of thousands |
Total OP_IF appearances on mainnet are in the tens of millions, but virtually all of them fall into one of the 12 patterns above. The thing that distinguishes them is the surrounding script — the OP_IF itself is just the conditional plumbing.
07Specifications
| Spec | Where to read it |
|---|---|
| Original Bitcoin Script | Bitcoin v0.1 source, January 2009 — script.cpp |
| BIP 16 (P2SH) | github.com/bitcoin/bips · bip-0016 — mandatory script flags |
| BIP 65 (CLTV) | github.com/bitcoin/bips · bip-0065 — used by HTLCs and vaults |
| BIP 112 (CSV) | github.com/bitcoin/bips · bip-0112 — used by Lightning to_local |
| BIP 141 (SegWit) | github.com/bitcoin/bips · bip-0141 — moves Lightning scripts into witness |
| BIP 342 (Tapscript) | github.com/bitcoin/bips · bip-0342 — MINIMALIF rule |
| BOLT 3 (Lightning) | lightning/bolts · 03-transactions — every Lightning script form |
| Ordinals protocol | docs.ordinals.com — the OP_FALSE OP_IF envelope spec |