URL encode and decode
This URL encode and decode tool converts ordinary Unicode text into RFC 3986 percent-encoded form and reverses correctly encoded values back into readable text.
Run — free
Choose encode when text must travel safely as a URL component, or decode when logs, redirects, query values, and copied links contain percent escapes. The operation is deterministic, keeps no state, and rejects malformed percent sequences instead of silently producing misleading output. It runs directly in the browser for interactive work, while the same behavior is available through the API for $0.002 per item.
When to percent-encode a value
URLs use a small set of characters as structure: slashes separate path segments, question marks begin queries, ampersands separate parameters, equals signs divide names from values, and hash signs introduce fragments. When one of those characters belongs to the data rather than the surrounding URL, it must not be confused with that structure. Encoding converts the input to UTF-8 and writes every byte that is not an RFC 3986 unreserved character as a percent sign followed by two hexadecimal digits. Letters, digits, hyphens, periods, underscores, and tildes remain readable. Spaces become <code>%20</code>, not a plus sign, and reserved punctuation is escaped because this capability treats the supplied string as a value rather than as a complete URL. That behavior is useful for query parameter values, individual path segments, redirect targets placed inside another URL, and identifiers containing non-ASCII characters. Encode only the data component you are inserting; encoding an already assembled URL would also escape its structural delimiters.
How strict decoding protects your data
Decoding scans the entire input before returning a value. Every percent sign must be followed by exactly two hexadecimal digits, so inputs such as <code>%</code>, <code>%2</code>, and <code>%GG</code> fail with an invalid-input error. After that structural check, the escaped bytes must form valid UTF-8. A syntactically plausible sequence can still be invalid text, and accepting it with replacement characters would hide corruption in a log, callback, signature base string, or imported dataset. The tool therefore reports an error instead. Decoding does not turn plus signs into spaces: that substitution belongs to the HTML form encoding convention, while this capability follows RFC 3986 percent encoding. It also performs one decoding pass only. For example, <code>%2520</code> becomes <code>%20</code>, not a space. A second pass must be requested explicitly, which helps prevent accidental double decoding and makes each transformation visible and reproducible in automated workflows.
Using the result safely in applications
Select the mode deliberately and pass the exact string that represents one logical value. In encode mode, store or insert the returned result without applying another URL encoder, because double encoding changes each percent sign into <code>%25</code>. In decode mode, treat the returned text as data, not as trusted markup, a filesystem path, or an instruction. Percent decoding restores characters but does not validate their meaning for a later destination. This distinction matters when a service receives callback parameters, examines access logs, normalizes imported links, or compares canonical identifiers. The algorithm is deterministic and has no network access, randomness, clock dependency, or retained state, so identical inputs produce identical outputs. Interactive browser use is convenient for debugging a single troublesome value; the API is better for repeatable validation in tests, ingestion pipelines, and developer tooling. A request costs $0.002 per item through the API, while the browser execution uses the same pure transformation logic.
What you can do with it
Prepare a query parameter
Encode user-supplied text so spaces, ampersands, Unicode characters, and other reserved punctuation remain part of one parameter value.
Inspect encoded logs
Decode a captured path or parameter to read its original Unicode content while detecting damaged percent escapes.
Test integration behavior
Create stable encoded fixtures and verify that callbacks, redirects, and ingestion pipelines decode exactly one RFC 3986 layer.
FAQ
What does the API request cost?
Each item costs $0.002 through the API. Interactive browser execution is available on the page.
Does encoding preserve slashes and question marks?
No. The input is treated as one value, so reserved URL punctuation is percent-encoded along with spaces and non-ASCII bytes.
Are spaces encoded as plus signs?
No. RFC 3986 percent encoding represents a space as %20. Plus-to-space conversion is specific to HTML form encoding.
What happens with a malformed percent escape?
Decode mode returns an invalid-input error for incomplete escapes, non-hexadecimal escapes, or byte sequences that are not valid UTF-8.
Will the tool decode a value more than once?
No. Each request performs exactly one pass, which avoids hidden double decoding. Submit the intermediate result again only when a second pass is intentional.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/web/url-encode-decode \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"hello world/café?x=1","mode":"encode"}'const res = await fetch("https://api.kit.forhosting.com/web/url-encode-decode", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"text": "hello world/café?x=1",
"mode": "encode"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/web/url-encode-decode",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"text": "hello world/café?x=1",
"mode": "encode"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/web/url-encode-decode", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"text":"hello world/café?x=1","mode":"encode"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"text":"hello world/café?x=1","mode":"encode"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/web/url-encode-decode", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"text": "hello world/café?x=1",
"mode": "encode"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "web.url_encode_decode",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
timeout_sec | 30 |
max_crawl_pages | 25 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |