jsguides

decodeURI()

decodeURI(encodedURI)

The decodeURI() function decodes a Uniform Resource Identifier (URI) previously created by encodeURI(). It restores special characters (such as spaces, symbols, and non-ASCII characters) back to their original form.

Syntax

decodeURI(encodedURI)

Parameters

ParameterTypeDescription
encodedURIstringA complete, encoded URI string.

Return Value

Returns a new decoded string. The original input is never modified.

decodeURI() takes a single string argument and returns a new decoded string. It does not modify the original input. The following example shows the basic operation: percent-encoded sequences like %20 are replaced with their decoded characters, while structural characters that belong to the URL stay untouched.

Examples

Decoding an Encoded URI

decodeURI("https://example.com/path%20with%20spaces");
// "https://example.com/path with spaces"

decodeURI("%3F%3D%26");
// "?&"

The basic decoding works on any percent-encoded string, but its real purpose is round-tripping with encodeURI(). When you encode a URI for transmission and later decode it, you should get back the original characters — including non-ASCII text like Chinese characters or emoji — without disturbing the URI structure.

Working with full URLs

const original = "https://example.com/search?q=JavaScript教程";
const encoded = encodeURI(original);
// "https://example.com/search?q=JavaScript%E6%95%99%E7%A8%8B"

decodeURI(encoded);
// "https://example.com/search?q=JavaScript教程"

Not every percent-encoded character gets decoded by decodeURI(). Characters that have structural meaning in a URL — the hash, the ampersand, the slash, and the question mark — are deliberately preserved. This prevents the function from accidentally turning a valid URL into something the browser or server would misinterpret.

What decodeURI() does not decode

This function preserves certain characters that have special meaning in URIs:

decodeURI("%23");
// "#" - hash is preserved

decodeURI("%26");
// "&" - ampersand is preserved

decodeURI("%2F");
// "/" - forward slash is preserved

decodeURI("%3F");
// "?" - query string delimiter is preserved

For full decoding including these characters, use decodeURIComponent() instead.

decodeURI() appears most often in two practical scenarios: displaying a URL to a user in a readable form, and decoding data that arrives from an API already percent-encoded. The examples below illustrate both patterns.

Common use cases

Processing query parameters

// When you receive a URL-encoded query string
const params = "name%20=%20John%20Doe&age%20=%2030";
decodeURI(params);
// "name = John Doe&age = 30"

Some APIs return JSON responses where the body itself is percent-encoded — a common pattern in legacy systems or when data passes through multiple encoding layers. Applying decodeURI() to the raw string recovers the original JSON without affecting the structural braces and colons.

Decoding API responses

// Some APIs return encoded data
const apiResponse = "%7B%22status%22%3A%22ok%22%7D";
decodeURI(apiResponse);
// "{\"status\":\"ok\"}"

decodeURI() is the inverse of encodeURI(), not encodeURIComponent(). Knowing which function to use on each end of the pipeline prevents subtle bugs where a URL’s structure gets corrupted. The key difference is what each encoding function preserves and what it percent-encodes.

encodeURI vs encodeURIComponent

The key difference is what each function encodes:

// encodeURI preserves: A-Z a-z 0-9 - _ . ~ ! ( ) * ; : @ & = + $ , / ? #
encodeURI("https://example.com/?q=hello world");
// "https://example.com/?q=hello%20world" - only space encoded

// encodeURIComponent encodes everything except: A-Z a-z 0-9 - _ . ~ ! * ( )
encodeURIComponent("?q=hello world");
// "?q=hello%20world" - encodes the ? and everything else

decodeURI() restores percent-encoded characters in a complete URI back to their original form. It reverses only the encodings that encodeURI() applies — spaces (%20), non-ASCII characters, and a few other characters — while leaving the structural characters of the URI intact.

The function is useful when displaying a URL to a user (unencoded URLs are more readable), logging URLs in human-readable format, or processing the full URL string after receiving it from an encoded source.

decodeURI() vs decodeURIComponent()

The two functions differ in which percent-encoded sequences they decode:

decodeURI() leaves structural URI characters encoded — it does not decode %23 (#), %2F (/), %3F (?), %26 (&), and other characters that have special meaning in a URL. This is correct when decoding a complete URI, because decoding those characters would change the URL’s structure.

decodeURIComponent() decodes everything except letters, digits, and a small set of unreserved characters (-, _, ., !, ~, *, ', (, )). Use it when decoding individual query parameter values or path segments, not complete URLs.

const encoded = 'https://example.com/search%3Fq%3Dhello%20world';

decodeURI(encoded);
// 'https://example.com/search%3Fq%3Dhello world' — %3F stays encoded

decodeURIComponent(encoded);
// 'https://example.com/search?q=hello world' — %3F decoded (breaks structure!)

Applying decodeURIComponent to a full URL can corrupt it by decoding characters that the browser needs to parse the URL correctly.

Error handling

decodeURI() throws a URIError if the input contains an incomplete percent-encoding sequence (e.g., a % not followed by two hex digits). Wrap calls in a try/catch when processing user input:

function safeDecodeURI(str) {
  try {
    return decodeURI(str);
  } catch {
    return str; // return original if decoding fails
  }
}

When not to use decodeURI()

Avoid decodeURI() when you are working with an individual URL component such as a query parameter value or a path segment — use decodeURIComponent() instead. The key distinction is scope: decodeURI() assumes its input is a complete URI and deliberately preserves the characters that give a URL its structure. Decoding a path segment or query value with decodeURI() may produce incorrect results if that segment contains characters like %2F (a literal slash) that should remain encoded in context.

See Also