%23 is a hash

%23 is a hash, also called a number sign or pound sign.

Character"#"
NameHash
Encoded%23
ReservedYes — it has a special meaning in a URL

Why it breaks things

A hash marks the start of a URL's fragment, the part that tells the browser where to scroll to on the page it has just loaded. The fragment is the last part of a URL, and it works differently from everything before it: a browser strips it off before the request is even sent. The server only ever receives the path and query string.

That is a bigger deal than it sounds. A stray ? or & still reaches the server, just parsed in a way you did not intend. A stray # means the rest of the URL never arrives at all. Put a color code straight into a query value, like ?accent=#ff5733, and the server receives an empty accent parameter — ff5733 never left the browser.

The same happens to issue numbers and hashtags. A support link like ?ticket=#4521 arrives at the server with no ticket number, because #4521 was treated as a fragment and dropped before the request was sent. Writing it as %234521 keeps the whole value in the query string where the server can see it.

Real examples

Without encoding

https://example.com/theme?accent=#ff5733

With encoding

https://example.com/theme?accent=%23ff5733

Everything from # onward is stripped off by the browser before the request is sent. The server receives accent with an empty value; ff5733 never leaves the browser at all.

Without encoding

https://example.com/support?ticket=#4521

With encoding

https://example.com/support?ticket=%234521

Same mechanism as the color example: 4521 becomes part of the fragment, not the query string, so the support page loads with no ticket number and no request for ticket 4521 ever reaches the server.

Decode something

History

    Nothing yet.

    History stays in this browser. It is never sent to our server.

    Common questions

    Does the server ever see what comes after the #?
    No, never. The fragment is stripped off by the browser before the HTTP request is built, so it never appears in a server log, a backend route, or anything else the server can see. This is different from ? and &, whose contents do reach the server, even if parsed incorrectly.
    Why did my link jump to the wrong spot on the page instead of loading properly?
    A # in a URL tells the browser to scroll to an element with a matching id after the page loads. If the value after # does not match any id on the page, the browser just does nothing extra — it does not report an error, so the link can look broken with no obvious cause.
    Is %23 the same kind of divider as %3F?
    Both mark a boundary, but with very different consequences. %3F starts the query string, which the server receives and parses. %23 starts the fragment, which the server never receives at all.
    Can a URL have more than one #?
    Only the first # starts the fragment. Any # after that is just a literal character inside the fragment text, which matters only to the browser — by that point, the server has already stopped listening, because the fragment was never sent to it in the first place.