Analyzing web server request logs, troubleshooting frontend routing parameters, or inspecting API payloads often requires translating percent-encoded characters back into readable plain text. In this guide, you will learn how URL decoding works in JavaScript and how to handle malformed URL errors safely.
How Percent-Decoding Works
URL decoding (or percent-decoding) scans a string for percent signs (%). Whenever a % is encountered, the subsequent two hexadecimal digits are parsed as an 8-bit byte value. Multi-byte UTF-8 sequences (such as %F0%9F%8C%BF for the herb emoji 🌿) are grouped together to reconstruct the original UTF-8 characters.
Decoding in JavaScript: decodeURI vs. decodeURIComponent
Similar to the encoding functions, JavaScript provides two decoding utilities:
decodeURI(encodedUri): Decodes general characters in a full URI, but leaves reserved structural characters like%23(#),%2F(/), and%3F(?) encoded to preserve URL anatomy.decodeURIComponent(encodedString): Decodes all percent-encoded octets, making it ideal for query string parameters, form payloads, and individual path segments.
Code Examples in JavaScript
// 1. Decoding URL query parameters
const encodedQuery = "category=data%20science%26limit%3D10";
const decodedQuery = decodeURIComponent(encodedQuery);
console.log(decodedQuery);
// Output: "category=data science&limit=10"
// 2. Decoding full URLs containing international characters
const fullUrl = "https://example.com/search?q=%E6%97%A5%E6%9C%AC";
console.log(decodeURI(fullUrl));
// Output: "https://example.com/search?q=日本"
Handling the "URIError: URI malformed" Exception
A frequent error encountered when calling decodeURIComponent() is URIError: URI malformed. This happens when a percent sign is not followed by valid hexadecimal characters (e.g. %2 or %ZZ), or when a multi-byte UTF-8 sequence is incomplete. Here is a resilient decoding function with fallback handling:
function safeUrlDecode(str) {
try {
// Standard UTF-8 decoding
return decodeURIComponent(str.replace(/\+/g, ' '));
} catch (err) {
// Resilient fallback: replace lone percent signs
console.warn("Malformed URI detected. Running resilient fallback.");
return unescape(str.replace(/\+/g, ' '));
}
}
console.log(safeUrlDecode("discount=20%25%20off")); // "discount=20% off"
console.log(safeUrlDecode("invalid%percent")); // Handled without crash
Decode URLs and Query Strings Online
Need to parse an encoded callback URL, query parameter, or server log entry quickly? Use Sylvaera's URL Decoder. It decodes any percent-encoded string instantly in-memory, ensuring your query logs and private parameters are never exposed.