Gender Reveal QR Code
Boy or girl? The answer is encoded inside the code — not on a website, not in a post, not in a bakery order that three people already know. Everyone scans on the count of three and every scan returns the same answer. The frame is violet on purpose: the one party color that refuses to pick a team. Your browser proves the code scans before you print a single card, and if the person who types the message isn't you, even you get to be surprised.
Keepsake print checklist
- Keep the white margin around the code — it is the quiet zone scanners need, not empty space to crop.
- Size for the moment: 2 × 2 cm of code is the floor for cards and tags; photo-woven codes reward 4 cm or more; distant reveals want one tenth of the scanning distance.
- Matte paper over gloss — glare is the most common keepsake scan failure.
- Scan a test print with a real phone before the moment that matters.
A worked example, rendered by the real engine
Built when this page was built, by the same engine as the tool above — confetti frame, the code panel untouched, and the answer itself inside the modules. Scan it from the screen (no internet needed) and it says:
It's a GIRL! Team pink wins - see you in March.
Version 6 at 41×41 modules, error correction H — decoded directly from the artwork.
Read this page with its guide. Everything below applies the engine's measured rules to one preset, and dwells on what is particular to a reveal card: where the answer can show — in the modules, in the caption's ink, in the printed link — the team-colour gate and its ungated frame-colour counterpart, the version step between the registry's two answers, and the practice card. The message mechanics in full — why bare text gives a phone nothing to act on, how a reveal link carries the words, what the self-contained reveal page is — are set out in Message keepsakes and reveal links. The baby-reveal page starts on the same confetti-framed style and already works through its cell-by-cell anatomy, the frame's construction and the fragment's compressed codec, so this page refers to it rather than repeating it. The rules every occasion shares live in the guides and on the methodology page, which this page never contradicts.
What the gender-reveal preset encodes
Every occasion on this site is a preset in the engine's occasion registry, and the registry
entry fixes where the generator begins: the Confetti frame style; a
hidden message as the payload — text, not a link or a contact card — so the answer
itself is what the modules hold; the heart-module toggle starting
off; the caption, link and message placeholders; a frame colour of
#7c3aed, a violet the registry chooses deliberately because it
belongs to neither team; a heart colour of #5b21b6 for the bare
Heart modules style; and the fictional example rendered above, with its caption “Boy or girl? Scan on three!”. All of it stays editable; the preset only sets where you begin.
A text payload reaches the encoder exactly as typed. The engine's text builder rejects an empty message and otherwise changes nothing, so the bytes a scanner recovers are the bytes that were entered. The worked example above is fictional and encodes 47 characters at error-correction level H, which the encoder fits in a version 6 symbol of 41 × 41 modules — 1681 cells, 172 of them finder and alignment landmarks that no style may redraw — and 49 modules across with the 4-module quiet zone the engine always draws on every side. Which cells are landmarks, which are timing tracks and where the alignment pattern falls for a symbol of this version is counted out on the baby-reveal page and in Why decorated QR codes still scan; the figures here are read from the model the engine returned when the page was built, not typed.
The registry carries two fictional answers for this occasion — the example above and the message field's placeholder, “It's a BOY! See you in February, little one.” — and encoding both shows how the symbol tracks the message. The example is 47 characters; the placeholder is 44. Symbol size moves in steps, not smoothly: a version holds a range of payload lengths and the encoder steps up a version only when the next range is needed, so the 3-character difference between them crosses a step: the placeholder needs version 5 at 37 × 37 modules against version 6 for the example. Where that step falls was measured when this page was built by encoding a filler of lowercase letters — outside the QR alphanumeric set, so in byte mode like both answers — one character longer at a time: a message of up to 44 characters fits version 5 at level H, and the 45th pushes the encoder to version 6. The two answers, at 44 and 47 characters, sit one on each side of it.
What the step does not track is which team the message names. Swap only the team words in the example — “It's a BOY! Team blue wins - see you in March.”, a second made-up answer derived from the first — and the message is 46 characters, which the encoder fits at version 6, 41 × 41 modules: the same symbol as the example, because the 1-character difference stays inside the version's range. For messages like these — each carries characters outside the QR alphanumeric set, so each is encoded in byte mode — the encoder sees byte count, not words, and a card's size follows the length of its answer within a version's range and nothing else about it. The character set matters as well: the methodology shows that restricting the words to the QR alphanumeric set changes the encoding mode rather than the version, and that fewer characters fit when a message carries emoji or accents.
Level H or level Q: the one choice a frame opens
Level H is the engine's rule for every style that redraws modules: level H gives roughly 30% recovery, and that recovery margin is what decoration spends, so the heart-module and photo styles reject a model encoded at anything lower outright. A frame never alters a module, so the frame composer accepts level Q as well as H and rejects anything below Q. The generator offers Q only as the opt-in “Smaller code (less error correction)” setting, on a framed style with the heart toggle off, and a Q-encoded frame still has to pass the same 2-of-3 decode verification as every other render before it can be downloaded. On the example message, level H needs version 6, 49 modules across with the quiet zone and a minimum print of 24.5 mm; requested at level Q, the model came back at level Q, as requested — version 5, 45 across and 22.5 mm: 1 version smaller, 2.0 mm narrower at the engine's working minimum. The same comparison for the reveal-link form of a message, and how many characters each level allows before a card outgrows the comfortable size, are measured on the baby-reveal page.
What matters on a reveal card is what the choice does not change. The payload, the frame, the caption and the quiet zone are the same at either level; only the symbol's redundancy, and therefore its size, differ. The model the engine returns records the level it actually encoded — the encoder never lowers a requested level and may raise one when that costs no version — so the preview's readout states Q or H for the card as rendered rather than as requested.
Where the answer can show: modules, ink and the printed link
The modules always carry it. After every render your browser rasterises the finished artwork — frame, panel, caption and code together — and runs a real decoder, jsQR, on the pixels at 3 raster sizes, earning the “Verified scannable” badge when at least 2 of them decode to an exact byte match and otherwise keeping the downloads locked; the mechanism, and why the rule is not all-or-nothing, is the subject of Decode verification: how the badge is earned. For a reveal card the badge proves one precise thing and its converse: this artwork, at screen resolution, decodes back to exactly these words as an offline note or exactly this link in reveal-link mode, at level H or Q alike — and so it decodes for anyone who points a camera at it. The engine offers no secrecy beyond the paper; a QR code hides its content from eyes, not from a scanner. What verification cannot see — the printer, the paper, the phone that will do the scanning, and whether that phone displays the words at all — is the same here as on every page.
The caption is the one place the engine could set the answer in ink. A framed code carries a caption under its panel, set by the frame composer in the frame colour. The composer enforces two limits that behave differently: a caption longer than 200 characters is refused outright and nothing is rendered — a ceiling the generator's caption field stops short of, so it cannot be reached by typing — while a caption whose text wraps past 4 lines is cut at the last line and marked with an ellipsis rather than spilling into the artwork. On a framed message keepsake — this preset's confetti card — the generator applies the methodology's rule that the message is “also printed under the code as its caption”: a caption you type always wins, and only when the field is left empty does the message itself go under the code, cut to 200 characters, so a keepsake that fails to scan still says what it was made to say. On a reveal card that courtesy prints the secret. The example's 47 characters are well inside that cut, so the whole answer would be set in ink; the worked example avoids it by captioning the card with the preset's prompt — “Boy or girl? Scan on three!”, 27 characters — so the ink asks the question and the modules hold the answer. The bare Heart modules style has no caption at all: nothing is set in ink there, and the answer lives in the modules alone.
The frame says only what the registry chose. Its primary is
#7c3aed, violet; recolouring it touches the art and the caption's
ink and nothing inside the panel, because the rendered code is nested verbatim on an opaque
panel drawn above the frame art, quiet zone included. How the panel, the confetti scatter and
the 5 templates fit together is shown on the baby-reveal page and in Framed codes, explained.
The printed link, in reveal-link mode, shows the address and not the words.
Every reveal link this site builds begins with the same 29 characters —
https://KEEPSAKECODES.NET/M/#, the scheme, host and path up to and including the # —
and differs only in the fragment after it. The fragment spells the message's bytes in base32, not
in letters a reader can read off the card; the reveal page decodes them for whoever opens the link,
which is the point of the format and the reason it offers no secrecy either.
Team colours and the contrast gate
The frame can be any colour; the modules cannot — not inside a frame. There, the one way to
restyle them is the “Heart-shaped modules inside the frame” toggle, which redraws the dark
cells among the example's 1509 non-landmark cells as hearts while the 172
landmark cells stay square, and it takes no colour: a framed code with hearts switched on is handed
to the heart renderer with no colour supplied, so framed hearts come out in the renderer's default,
read here from its output as #881337 at 9.57:1 against
white, as the baby-reveal page also derives. A team colour in
the modules therefore means the bare Heart modules style, where the heart-colour field appears,
seeded with the preset's #5b21b6 — and that is where the gate applies.
Heart-shaped modules are measured against the background with the WCAG contrast formula and any pair below 4.5:1 is rejected — rejected, not warned about — because scanners binarise the image. Measured against white when this page was built, with illustrative colours chosen for this page:
- the heart renderer’s own default, which framed hearts use,
#881337— 9.57:1, accepted - the preset’s default for the bare Heart modules style,
#5b21b6— 8.98:1, accepted - a pale team pink,
#f9a8d4— 1.81:1, rejected - a pale team blue,
#93c5fd— 1.80:1, rejected - a deep pink,
#be185d— 6.04:1, accepted - a deep blue,
#1d4ed8— 6.70:1, accepted
Handed the example model and the pale pink, the heart renderer returns an error rather than a render, and this is its exact message: Artistic styles require at least 4.5:1 contrast (got 1.81:1) — decoration already spends decode margin. Nothing is drawn, so nothing can be verified or downloaded. The deep pink and deep blue clear the gate; the pale team shades do not, and no setting lowers the threshold. Inverted codes — light modules on a dark background — are rejected as well.
The same pale pink has an ungated counterpart. Handed to the frame composer as the confetti
palette's primary, with the example inside it, #f9a8d4 rendered without objection
when this page was built — because the frame colour never meets the gate, frame art never touching
a module — and the code on the panel stayed the plain renderer's black on white, which the renderer
measured at 21.00:1. Team colour on the frame is ungated; team colour in
the modules is gated at 4.5:1, and the pale shades measured above
fall below it. The gate, with more pairs on either side of it, is worked through in Heart-module codes, explained.
Reveal link or offline note: what a phone does with the answer
A hidden message can leave the generator in two forms, and the preset's text payload is the input to both. The difference is entirely about what a phone does when it sees the result. A code containing bare text carries no scheme, so a phone has nothing to act on. Apple's Camera and Google's ML Kit recognise links, phone numbers, email addresses, contact cards, calendar events and Wi-Fi joins — and no plain-text type. Faced with bare text, an iPhone offers to copy or search it and Google Lens runs a web search; Samsung phones and dedicated scanner apps do display it. A keepsake cannot depend on which phone opens it.
The offline note accepts that caveat in exchange for needing no connection, ever:
the words are written into the code, which is exactly what the worked example is — scan it and the
decoder returns the text. The reveal link instead encodes an ordinary URL to the
reveal page at /m/ on this site (the printed link carries the host and path
in uppercase, and the site serves the uppercase path as well, because some scanners change the case
of what they read), a link being a type those cameras recognise, with the message carried in the
URL's fragment — the part after the
#. Per RFC 3986 a fragment is stripped before a request is made, so it never
reaches this site's servers, a CDN or any log; the page decodes it on the reader's device. The
fragment's format and the self-contained HTML reveal page that decodes it with no network and
no website at all are set out in
Message keepsakes and reveal links.
Built from the example message exactly as the generator builds it — with no compressor — the
link is:
https://KEEPSAKECODES.NET/M/#AJF2CO4ZAMEQEOSKSJQQSAVDFMFWSA4DJNZVSA53JNZZSALJAONSWKIDZN52SA2LOEBGWC4TDNAXAX
Its fragment carries flag A (A marks UTF-8 bytes), a
76-character base32 body and the checksum character X
— 78 characters from a 47-character message,
inside the
300-character limit. Encoded at level H, the link needs a
version
10 symbol of 57 × 57 modules,
65 across with the quiet zone, against 49 for the offline note of
the same words. That is the whole trade: the link needs a signal at the moment of scanning and the
note needs nothing, while the note accepts the display caveat above and the link does not. The format's
second codec, flag B for compressed bytes, is one the generators do not
use today — every link they emit carries flag A, as this one does, and the reveal
page parses either — and what a compressor would and would not save on a message of this kind
is measured on the baby-reveal page.
Printing and test-scanning the cards
The methodology's print guidance is short, and it is the whole of what this page will claim: print at least 2 × 2 cm of code for arm's-length scanning, keep the quiet zone uncropped, and scan a test print with a real phone before the moment that matters. The engine adds two measured numbers. It treats 0.5 mm as the working minimum for a printed module, so the example as an offline note at level H — 49 modules across with its quiet zone — should be printed at least 24.5 mm (0.96 in) wide; the same note at level Q, 45 across, at least 22.5 mm; and the reveal-link version of the same message, at 65 modules, at least 32.5 mm (1.28 in). And it treats 65 total modules as the point past which a code stops fitting the objects keepsakes go on: the note's 49 is within that ceiling and the link's 65 is within it. The 4-module quiet zone is part of the symbol and is drawn inside the panel, so cutting a card flush to the panel's edge keeps it and cutting into the panel removes it — a failure verification cannot catch, because it saw the uncropped artwork. The raster sizes the PNG download offers, how large each prints, and the quiet-zone mechanism in full are in Printing and scanning a keepsake.
A practice card lets the phone and the paper be tested without the answer leaving the generator. Encoding “Not yet! Snacks first.” — a made-up practice message written for this page — gives version 3, 29 × 29 modules, 37 across with the quiet zone and a minimum print of 18.5 mm: a smaller symbol than the reveal card itself. A code decodes to exactly its own content and nothing else, so a practice scan of that card proves the phone can read a print of this frame at that size and says nothing about the answer. Because the practice card is a different symbol, the methodology's test-print step still applies to the real card: it is the real card's modules that have to survive the printer.
Common misreadings on a reveal card
Leaving the caption empty. On a framed message keepsake — this preset's confetti card — an empty caption field means the generator sets the message itself under the code, cut to 200 characters. On any other keepsake that is a courtesy; on a reveal card it prints the answer in ink next to the code that was meant to hide it. The preset's caption placeholder, “Boy or girl? Scan on three!”, is a prompt, not the answer — so leaving the field at its placeholder is not the same as leaving it empty. The bare Heart modules style has no caption and sets no ink.
Expecting the framed heart toggle to take a team colour. It does not: framed hearts
are rendered in the heart renderer's default, #881337. A pink or blue
heart means the bare Heart modules style, where the colour field appears — and where the pale
shades measured above are rejected before anything is drawn.
Ticking “Smaller code” with hearts on. The setting is level Q, which the engine accepts for a frame around an untouched symbol and for nothing that redraws modules; the generator applies it only on a framed style with the heart toggle off. With hearts on, the card encodes at level H and prints at the level-H minimum, 24.5 mm for the example, not the 22.5 mm the level-Q figure above promises.
Gender reveal code FAQ
Can we stay surprised ourselves?
The generator encodes, draws and decode-verifies the code in the browser of whoever types the answer; nothing is transmitted, so the answer exists only in that browser, in the downloaded file and on whatever is printed. One generator behaviour to know about: on a framed message keepsake — this preset’s confetti card — the words are also set in ink under the code as its caption, the methodology’s rule that the message is “also printed under the code as its caption”. A caption you type always wins, and only when the field is left empty does the message itself become the caption. Type the prompt into the caption — the worked example uses “Boy or girl? Scan on three!” — and the printed words are the question, not the answer. The bare Heart modules style has no caption at all, so nothing is set in ink there.
Can someone scan the code early and spoil it?
Yes, if they can point a camera at it: verification proves the artwork decodes, and a code that decodes for the party decodes for anyone. The engine offers no secrecy beyond the paper the code is printed on. The preset’s #7c3aed violet frame is chosen in the occasion registry as the one party colour that belongs to neither team, so the artwork gives away nothing — but the modules give away everything to a scan.
Does the reveal need internet at the party?
Only in reveal-link mode, which encodes a link to this site’s reveal page with the answer carried in the URL fragment. The offline note writes the words into the code itself and needs no connection ever — with the caveat that a code of bare text has no scheme for a phone to act on: Apple’s Camera and Google’s ML Kit recognise links, phone numbers, email addresses, contact cards, calendar events and Wi-Fi joins and no plain-text type, so an iPhone offers to copy or search the text and Google Lens runs a web search, while Samsung phones and dedicated scanner apps display it. The guide on message keepsakes sets out both modes.
What should the message say?
The engine does not judge wording; it measures length. A text payload is passed to the encoder unchanged, and the symbol’s version and module count grow in steps as the message lengthens — a version holds a range of payload lengths, and the encoder steps up only when the next range is needed. The 47-character example fits a version 6 symbol of 41 × 41 modules; the registry’s other fictional answer for this occasion, 44 characters, needs version 5 at 37 × 37, a 3-character difference crossing a step. Swapping the team words in the example gives a 46-character message that encodes at version 6 — the same symbol. The reveal link built from the example needs version 10 at 57 × 57. A reveal message is capped at 300 characters before encoding. More modules mean a larger minimum print — 0.5 mm per module, quiet zone included — so a shorter message prints smaller for the same reliability.
Is the answer uploaded anywhere before the party?
No. Encoding, rendering and verification run in the browser, and nothing is transmitted or posted. In reveal-link mode the message rides in the URL fragment, which per RFC 3986 is stripped before any request is made, so even when a guest scans it the words never reach this site’s servers, a CDN or a log; the reveal page decodes them on the guest’s phone. In offline-note mode the words never leave the code at all.
Why is the reveal-link code denser than the offline note for the same answer?
Because the link carries the whole address as well as the message. Built as the generator builds it — no compressor, flag A — the example’s 47 characters become a 78-character base32 fragment (flag, payload and checksum), and the full link is 107 characters, of which the first 29 are the same on every reveal link this site builds. The encoder therefore needs version 10 at 57 × 57 modules where the bare note fits version 6 at 41 × 41. The published format’s second codec, flag B for compressed bytes, is one the generators do not use today; what a compressor would and would not save on a message of this kind is measured on the baby-reveal page.
Can I use team-pink or team-blue heart modules instead of the violet frame?
Only on the bare Heart modules style, and only if the colour passes the engine’s contrast gate. Inside a frame the heart toggle hands the modules to the heart renderer with no colour of its own, so framed hearts come out in the renderer’s default, #881337, at 9.57:1; the heart-colour field appears on the bare style, seeded with the preset’s #5b21b6 (8.98:1, accepted). Heart-shaped modules are measured against the background with the WCAG contrast formula and rejected below 4.5:1 — the engine refuses rather than warns, because scanners binarise the image. Against white, the pale pink #f9a8d4 measures 1.81:1 (rejected) and the pale blue #93c5fd measures 1.80:1 (rejected), while the deep pink #be185d at 6.04:1 is accepted and the deep blue #1d4ed8 at 6.70:1 is accepted. The frame colour is never gated, because frame art never touches a module: the same pale pink rendered without objection as the frame colour when this page was built, with the code inside it at 21.00:1.
Does the “Smaller code” setting work with heart modules switched on?
No. Hearts redraw modules, so they encode at level H without exception; the smaller code is level Q, which the engine accepts only for a frame that leaves the symbol untouched, and the generator applies it only on a framed style with the heart toggle off. On the example message, level Q is 1 version smaller: version 5 at 37 × 37 modules against version 6 at 41 × 41 for level H, a minimum print of 22.5 mm against 24.5 mm. A level-Q render still has to pass the same 2-of-3 decode verification before it can be downloaded.
What gets printed under the code if I leave the caption empty?
On a framed message keepsake — this preset’s confetti card — the answer itself. The generator takes the caption from the caption field, and when that field is empty on a framed card it sets the message under the code instead, cut to 200 characters, so a keepsake that fails to scan still says what it was made to say. On a reveal card that rule prints the secret in ink; the worked example avoids it by captioning the card with the prompt, “Boy or girl? Scan on three!”. The bare Heart modules style has no caption, so nothing is set in ink there and the answer lives in the modules alone.
After the party, announce the arrival with a baby reveal code — the news hidden the same way. Or run the whole party as a QR treasure hunt that ends at the reveal, and weave the first ultrasound photo into a photo keepsake code.