%28 is an open parenthesis
%28 is an open parenthesis. It is legal raw in a URL, and most encoders leave it exactly as typed.
| Character | "(" |
|---|---|
| Name | Open Parenthesis |
| Encoded | %28 |
| Reserved | Yes — it has a special meaning in a URL |
Why it breaks things
An open parenthesis is an RFC 3986 sub-delimiter, the same group as the comma and the exclamation mark — no fixed job in the generic syntax. Browsers and servers pass a raw ( straight through. JavaScript's encodeURIComponent does too, on purpose: verified, encodeURIComponent("(") returns ( unchanged, not %28. encodeURI leaves it alone as well.
That is not universal. Python's urllib.parse.quote, with default settings, encodes the same character to %28 — verified. Its safe list is much shorter than JavaScript's, covering little beyond letters, digits and a slash. Whether a parenthesis survives encoding depends on which function did the encoding, not on any rule about the character itself.
The trouble shows up downstream, once a legal, unencoded value reaches something stricter than a browser. Some web application firewalls flag a raw ( and ) in a query value as suspicious, since that shape also appears in function-call injection attempts, like alert(1). A search for Smith (Accounts) can get blocked at that layer, not because anything is malformed, but because parentheses read as a warning sign to a filter built for a different threat.
Real examples
Without encoding
https://example.com/directory?q=Smith (Accounts)
With encoding
https://example.com/directory?q=Smith%20%28Accounts%29
The raw parentheses are legal here and reach the server unchanged; only the space needs encoding for encodeURIComponent to touch this string at all. Encoding the parentheses anyway is harmless, and can help clear a security filter further down the chain that treats raw ( ) as suspicious.
Without encoding
https://example.com/search?tag=web(dev)
With encoding
https://example.com/search?tag=web%28dev%29
A tag using parentheses as a grouping mark, common in tagging systems. Nothing in the URL standard requires encoding this, and most servers accept it as-is — some API gateways and firewalls are stricter, and reject or flag it purely because of the function-call shape.
Decode something
Result
Breakdown
| Part | Value | Copy |
|---|
History
Nothing yet.
History stays in this browser. It is never sent to our server.
Common questions
- Do I need to percent-encode parentheses in a URL?
- Not for the URL itself. RFC 3986 lists ( and ) as sub-delimiters, legal to use unencoded, and browsers and servers pass them straight through. Encoding them anyway can help with stricter infrastructure further down the chain.
- Why doesn't encodeURIComponent touch my parentheses?
- Because JavaScript's built-in encoder treats them as part of its safe set, alongside characters like ! ~ and *, and never escapes them. This is deliberate, not a bug — it matches the set of characters the URL standard treats as always safe to write literally.
- Why did my search get blocked by a security filter when nothing looks wrong?
- Some web application firewalls flag literal parentheses in a query value, because the shape resembles a function call used in injection attempts, such as alert(1). The value can be entirely legal by the URL standard and still trip a rule written for a different threat.
- Does every encoder leave parentheses alone like JavaScript does?
- No. Python's urllib.parse.quote, for example, encodes a parenthesis to %28 by default, because its safe list is much narrower than JavaScript's. Which functions touch a given character varies by language and library, not by one universal rule.