Skip to main content
VVertex Solutions
All toolsPDF ToolsImage ToolsText ToolsCalculatorsDeveloperBlog
VVertex Solutions

Browse tools for merging and compressing PDFs, resizing and converting images, formatting text and JSON, running calculators, and working with code.

Popular Tools

  • Mortgage Calculator
  • GPA Calculator
  • Tip Calculator
  • BMI Calculator
  • Percentage Calculator
  • EMI Calculator
  • Merge PDF
  • JSON Formatter

Categories

  • All tools
  • PDF Tools
  • Image Tools
  • Text Tools
  • Calculators
  • Developer Tools

Company

  • About
  • About the Author
  • Editorial Standards
  • How We Verify Tools
  • How Data Is Processed
  • Calculator Comparisons
  • Disclaimer
  • Privacy Policy
  • Cookie Policy
  • FAQ
  • Accessibility
  • Changelog
  • Terms of Service
  • Contact
  • Blog
  • RSS Feed

© 2026 Vertex Solutions. All rights reserved.

Free tools. No signup. Privacy first.

  1. Home
  2. Blog
  3. URL Encoding and Decoding: A Developer Guide
Developerinformational8 min readPublished 2026-04-17 · Last updated 2026-10-23

URL Encoding and Decoding: A Developer Guide

Why URLs need percent-encoding, what each component requires, how plus signs behave in query strings, and a safe encode and decode workflow for APIs and forms.

By Rehan Baqir

Learn more

  • URL encode
  • URL decode

Quick answer

Percent-encoding replaces an unsafe or reserved URL character with % and the hex of its UTF-8 bytes, such as %20 for a space or %26 for &. Encode each query value with encodeURIComponent or URLSearchParams. Encoding the whole URL string, or encoding a second time, turns %20 into %2520.

Percent-encoding is a one-time substitution, and it does not hide the query string from history, logs, or referrers. It replaces an unsafe or reserved character with % and two hex digits. Encode each component once, when you build the URL. Encoding the finished string, or encoding again, turns a space that was already %20 into %2520. Try a value in the URL encoder or the URL decoder. While you are debugging a payload, the JSON formatter shows control characters that survived the decode, and the regex tester is there if you are matching those sequences in a log line.

A search link that shows q=hello%2520world and returns no results has usually been encoded twice. One layer turned the space into %20. The next layer turned the percent sign into %25, leaving %2520.

Two rules cover most of the bugs: encode individual components, and encode exactly once at the boundary where you assemble the URL. Encoding the whole string after you have already joined it also encodes the ?, =, and & that the URL needs as structure.

URL anatomy: encode the right piece

https://example.com:443/path/to/page?name=John+Doe&tag=c%2Fa#section
|_____|   |_________|_|____________| |______________| |__|
scheme     host     port    path          query       fragment

Each component has different reserved characters:

| Component | Encode? | Notes | |-----------|---------|-------| | Scheme | No | https is fixed | | Host | Rarely | Internationalized domains use punycode | | Path | Sometimes | / is a delimiter, and it stays unencoded between path segments | | Query values | Yes | &, =, +, and spaces need care | | Fragment | Sometimes | The server does not receive it; client routing still uses it |

Encoding the entire URL as one string breaks those structural characters. Encode each parameter value, then assemble the URL.

What percent-encoding does

An unsafe character becomes % plus two hex digits of the UTF-8 byte:

| Character | Encoded | |-----------|---------| | space | %20 | | & | %26 | | = | %3D | | + | %2B | | / | %2F | | ? | %3F | | # | %23 | | é | %C3%A9 (UTF-8 bytes) |

The name "percent-encoding" comes from the % prefix.

Use the URL encoder to see how a specific string changes.

encodeURI and encodeURIComponent

encodeURI is for a full URL. It leaves :/@?#[] and similar characters in place.

encodeURI("https://example.com/a b");
// https://example.com/a%20b

encodeURIComponent is for a query parameter value. It encodes / and ? along with the rest.

encodeURIComponent("a/b?c");
// a%2Fb%3Fc

Use encodeURIComponent for values. Use encodeURI only when you already have a full URL, which is uncommon if you build URLs with URLSearchParams.

The plus sign

In application/x-www-form-urlencoded (HTML forms), a space becomes +.

In URL paths, and in strict RFC 3986 encoding, a space becomes %20.

Decoders in most frameworks accept + as a space in query values. Do not rely on + in a path.

When a space works locally and fails in production, check whether one layer decodes + and another does not.

The URL decoder shows both forms side by side.

Building query strings

This breaks when query contains & or =:

const url = `/search?q=${query}`;  // breaks if query contains & or =

Build the string with URLSearchParams instead:

const params = new URLSearchParams({ q: query, page: "1" });
const url = `/search?${params.toString()}`;

URLSearchParams encodes each key and each value.

If you assemble the string yourself, encode each value with encodeURIComponent and join with &:

/search?q=hello%20world&tag=node%2Fjs

Decode once, at the layer that consumes the value

Servers and frameworks decode query parameters on their own. The usual failure is a chain:

  1. The client encodes
  2. The server decodes
  3. The application encodes again before storage
  4. The display decodes again

Each layer should encode outbound data once and decode inbound data once.

Use the URL decoder to see the string after one decode pass.

Encoding twice

Original: 100% done

First encode: 100%25%20done

Second encode: 100%2525%2520done

Links that pass through several systems (email, then a CRM, then a redirector) can pick up another encoding layer at each hop. The symptom is a search term that looks right in the address bar and matches the wrong row in the database.

Decode in a loop until the string stops changing, or compare against a known double-encoded pattern such as %25 standing in for %.

Paths with special characters

A file path in a URL needs each segment encoded:

/files/2024/Q1 Report.pdf  ❌ (spaces)
/files/2024/Q1%20Report.pdf  ✓

A slash inside one path segment (a filename that contains /) has to be encoded:

encodeURIComponent("a/b") → a%2Fb

Leave the slashes that separate path segments alone.

Unicode and international URLs

Browsers may display https://example.com/café as Unicode. On the wire, the domain may be punycode and the path may be percent-encoded:

/caf%C3%A9

UTF-8 encode the character before you percent-encode the bytes. A Latin-1 assumption breaks emoji and CJK text.

Base64 in a URL is a different encoding

Binary stuffed into a URL sometimes uses Base64url, which swaps in - and _ for + and /. That is an alphabet change. It is separate from percent-encoding.

A JWT in a URL needs Base64url. Running encodeURIComponent over the whole token is the wrong step.

APIs and redirect URLs

An OAuth redirect_uri has to match the registered value byte for byte. An encoding difference produces redirect_uri_mismatch.

Common misses:

  • A trailing slash encoded in one place and left raw in the other
  • http on one side and https on the other
  • Query parameter order, which some providers compare strictly

Log the exact bytes you send, and keep the pretty-printed version for reading only.

HTML links and JavaScript URLs

<a href="/search?q=hello world">  ❌ ambiguous
<a href="/search?q=hello%20world">  ✓

A template engine may escape & in attributes on its own. Check View Source. The rendered DOM can hide what was actually written.

Server-side decoding

Most frameworks provide a decoder:

  • decodeURIComponent (JavaScript)
  • urllib.parse.unquote (Python)
  • url.QueryUnescape (Go)

Form parsers also turn + into a space in query values.

Leave the raw URL encoded if it is part of a signature, such as webhook verification or AWS SigV4. Decoding before that middleware runs changes the bytes the signature was computed over.

Security

  • Open redirects: check the decoded redirect target against an allowlist
  • Log injection: a decoded %0A newline in a parameter can break a log format
  • SSRF: an encoded http://127.0.0.1 can slip past a filter that only looks at the raw string. Decode, then validate
  • XSS in a reflected parameter: URL encoding and HTML escaping are different steps. Escape again at the output layer

Values you pull out and send to a JSON API should go through the JSON formatter while you debug, so embedded control characters are visible.

Debugging checklist

| Symptom | Check | |---------|-------| | + appears as a literal plus | The decoder left + as a plus in the query | | %20 is visible in the UI | The value was encoded an extra time, or the display never decoded it | | Slashes in the path are broken | encodeURIComponent ran on the full path, not on each segment | | Unicode looks like mojibake | The wrong charset was used before percent-encoding | | OAuth redirect fails | Compare the encoded redirect_uri byte for byte |

Framework differences

Axios and fetch do not share one params serializer. Axios may encode differently from URLSearchParams. When a partner integration disagrees, log config.paramsSerializer output. The library default is a guess until you see that string.

In Ruby on Rails, CGI.escape and ERB::Util.url_encode treat spaces differently (+ versus %20). Mixing the helpers in one codebase shows up as redirect bugs.

In PHP, urlencode() and rawurlencode() split the same way: space as +, or space as %20. RFC 3986 prefers rawurlencode for path segments.

In Java, URLEncoder.encode uses + for spaces, which is the application/x-www-form-urlencoded style. Use URI builder classes when the path has to follow RFC 3986.

When a stack trace shows encoding in more than one layer, sketch the encode and decode boundaries. Framework middleware often decodes before your handler runs, and the handler then encodes again before storage.

Internationalized domain names

A hostname with Unicode, such as münchen.de, uses punycode on the wire (xn--mnchen-3ya.de). Punycode is separate from path and query percent-encoding, and both show up in URLs people copy from a browser. Leave punycode hostnames to a URL parser that accepts the Unicode display form.

Limitations

Percent-encoding does not conceal sensitive data. Query parameters still appear in browser history, server access logs, and referrer headers.

URL length limits still apply. Encoding makes the string longer, and many servers and CDNs reject URLs past 2,000 to 8,000 characters. Put a large payload in a POST body.

Related articles

  • Understanding Base64 encoding: Base64url and percent-encoding side by side
  • Understanding regular expressions: parsing log lines that contain encoded parameters
  • JSON formatting guide: API payloads that include encoded fields

Where the bugs come from

URL encoding turns a character that would break URL structure into a %XX sequence. Encode each component when you build the URL, decode once when you consume it, and know whether + means a space in that context. Most broken production links come from a second encode pass, or from encodeURI where the value needed encodeURIComponent.

Related Tools

Free browser-based tools referenced in this article.

URL Encoder
URL encoder using encodeURIComponent for query values. Decoding is a separate page.
URL Decoder
URL decoder using decodeURIComponent, with an error when the percent-encoding is invalid.
Featured
JSON Formatter
JSON formatter to pretty-print or minify JSON. Use JSON Validator when you only need the error.
Featured
Regex Tester
Regex tester for JavaScript RegExp, with flags and match indexes. Other engines can differ.

Key takeaways

  • Use URLSearchParams or encodeURIComponent on each query value so &, =, and / cannot break the URL.
  • HTML form encoding turns spaces into + in query strings. RFC 3986 path encoding uses %20.
  • Watch for double-encoding (%2520 where you expected %20) when a URL passes through more than one redirector or middleware layer.

Frequently Asked Questions

Common questions answered to help you get the most from this tool.

Percent-encoding replaces a reserved or unsafe character with a percent sign and two hexadecimal digits for that character's byte value. A space is %20.

encodeURI encodes a full URL and leaves structural delimiters such as :, /, ?, &, and = in place. encodeURIComponent encodes one query key or value, and it escapes /, ?, &, and = so that user input cannot change the URL structure.

HTML form submission (application/x-www-form-urlencoded) has long encoded spaces as +. In a URL path, a space should be %20. Decoders often accept both in query values.

A second pass turns % into %25, and the link breaks. Encode each component once, at the boundary where you build the URL.

Yes. A non-ASCII character becomes UTF-8 bytes, and each byte is percent-encoded. Modern browsers do this. Hand-built URLs need the same care.

About the author

Rehan Baqir is the founder & editor of Vertex Solutions. He builds browser-based tools and writes guides about PDF workflows, calculators, image tools, and developer utilities. Article pages show their publication and update dates when available. Read the editorial standards and tool-testing method for the site's stated approach to content and verification.

More about Rehan Baqir →

urlencodingdecodingpercent-encodingdeveloperapis
Back to all articles

On this page

  • URL anatomy: encode the right piece
  • What percent-encoding does
  • encodeURI and encodeURIComponent
  • The plus sign
  • Building query strings
  • Decode once, at the layer that consumes the value
  • Encoding twice
  • Paths with special characters
  • Unicode and international URLs
  • Base64 in a URL is a different encoding
  • APIs and redirect URLs
  • HTML links and JavaScript URLs
  • Server-side decoding
  • Security
  • Debugging checklist
  • Framework differences
  • Internationalized domain names
  • Limitations
  • Related articles
  • Where the bugs come from

Related Articles

  • PHP security vulnerabilities: 10 flaws attackers exploit, and how to fix each one
  • UUID v4 vs v7: Sortable IDs in New Projects
  • Understanding Regular Expressions: Patterns, Engines, and Mental Models