Percent encoding writes one character as three: a percent sign, then exactly two hexadecimal digits, with no space and nothing between them.
The shape
The rule has no exceptions worth remembering. Wherever a percent sign appears inside a link, the next two characters must be hex digits, which means the ten digits and the letters a to f. Either case is allowed for those letters, so %2f and %2F mean the same thing, and mixed case within one escape is legal if untidy.
Escapes live in the parts of a link that come after the host: the path, the query and the fragment. They exist because some characters have jobs in a link, and a character doing its job cannot also be a plain character sitting in a value. A slash separates path segments, so a slash that is meant to be part of a name has to be written some other way. Percent encoding is that other way.
- Fixed part
- one
% - Variable part
- exactly two characters, both hex digits
- Total width
- three characters for every one character encoded
- Case
- either, in the hex digits only
- Where it appears
- path, query and fragment
- Spacing
- none; a space anywhere inside an escape breaks it
%20 a space
%2F a forward slash
%3A a colon
%3F a question mark
%23 a hash
%40 an at sign
%00 the character numbered zero, which ends a string in some softwareA percent inside a percent
The percent sign is itself a character with a job, so it too has an escape: %25. Substitute that into an ordinary escape and you get the doubled form. Writing %252F is writing %25 followed by the two plain characters 2F. Read once, it produces the text %2F. Read a second time by something further along, that text produces a slash.
The reason this matters to a reader is not that double encoding is inherently sinister. It is that the number of times a string will be decoded is not visible in the string. A link can carry a value that is harmless after one pass and something quite different after two, and the difference between those two futures is three characters near the front of an escape. Look for %25 specifically. It is the only escape whose presence tells you a second reading is expected.
%2F one pass gives /
%252F one pass gives %2F two passes give /
%25252F and so on, three characters at a time25 after the leading percent sign, so the layers can be counted by eye without decoding anything.How to check it by eye
Two digits after every percent sign
- Find every
%in the line. Take them one at a time, left to right. - For each one, cover the percent sign and read the next two characters. Both must be digits or letters in the range
atof. - If either character is outside that range, or if the line ends before two characters arrive, the escape is incomplete and the line has been damaged or truncated.
- Note any escape whose two digits are
25. That marks a layer, and the layers are worth counting before you decide what the value says. - Finally, read the line as if every escape were absent, to see the underlying shape. Escapes can make a short value look long and an ordinary word look technical.
What a wrong shape means
A lone percent sign, meaning one not followed by two hex digits, is the ordinary failure. It usually appears because a percent sign was typed as a percent sign, in a sentence about a discount or a proportion, and the sentence was later pasted into a field that treats its contents as a link. It also appears when a line was cut, since truncation lands mid escape as often as anywhere else.
Software disagrees about what to do with an incomplete escape. Some pass it through untouched, some refuse the whole string, and some silently drop it. That disagreement is the reason a broken escape is worth noticing even though its cause is nearly always innocent: the same broken string can behave differently in two places, and the difference is not visible in the text.
Complete escapes
/search?q=example%20text%2Fmore
two escapes, each with two hex digitsBroken escape
/search?q=example%20text%
one escape short of its digits, one with nothing after itThe second line has a percent sign followed by a single digit and then a letter, and another percent sign at the very end with nothing behind it. Both are the signature of a string that was cut, not of a string that was crafted.
What a correct shape does not prove
Every escape counted, every pair valid, every layer noted. The following is still entirely outside what you have established.
- What the decoded value does. Reading the characters is a transcription exercise, and the far end decides what to do with them.
- How many times the value will be decoded. The string carries no statement about that, and the layers you counted are a hint about intent rather than a count of passes.
- That the encoding was necessary. Any character may be escaped, including ordinary letters, so a value written entirely in escapes is unusual but not invalid.
- That the link is the one you were given. Escapes sit inside the path and query, which are chosen by whoever built the link, and none of that touches the host.
- That nothing is hidden. Encoding disguises the shape of a value from a quick glance, and a quick glance is what most people give a long link.
What this card is not
The frame around these escapes, meaning which part of a link is the path and which is the query, is set out on the mirror link card, and reading this card without that one is doing the work in the wrong order. Escapes are not the same as characters that imitate other characters, which are on the lookalike host card. A value inside a query that turns out to be a credential rather than a page reference belongs to the link with a token card.
Questions people send about this shape
Is %20 the same as a plus sign?
In the query part of a link, both are commonly used for a space, and software has treated them as interchangeable there for a long time. In the path they are not the same, and a plus sign in a path is an ordinary plus sign. If you are reading a value and the choice matters, note which part of the link you are in before you translate anything.
Do the hex letters have to be upper case?
No. Upper and lower case hex digits are equally valid, and you will see both, sometimes in the same link. Case is worth noticing only as a fingerprint of whatever produced the string, since a single generator tends to be consistent. Mixed case inside one link often means two systems each escaped part of it.