Encode and decode a URL
café becomes caf%C3%A9, a space becomes %20 and & becomes %26: encode text so it travels safely inside a link, or decode percent signs back into readable words, with accents and other scripts handled correctly. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Text
- café & té/2?x=1
- Encoded value
- caf%C3%A9%20%26%20t%C3%A9%2F2%3Fx%3D1
A single misplaced ampersand or unescaped space in a URL can silently break a redirect, a tracking pixel or an entire integration test suite.
Why encoding rules feel inconsistent
Addresses on the web were designed for a narrow set of plain characters, and percent-encoding was formalized so they could safely carry anything else: spaces, ampersands, accents and non-Latin scripts. Over the decades, different specifications, such as the rules for addresses and the rules for submitting HTML forms, drifted apart, and most libraries implement only one of them well. That is why JavaScript and PHP disagree on spaces, and why plus signs and tildes come out differently from one language to another. A single misplaced ampersand or unescaped space can quietly break a redirect or a tracking pixel. This encoder applies one rule set, the one RFC 3986 describes, so the same text always gives the same result.
How it works and when it helps
The encoder walks through the text byte by byte. Unsafe or reserved characters become a percent sign followed by two hexadecimal digits, and decoding turns those sequences back into readable text. Characters that take more than one byte, common in names, addresses and international content, are handled properly instead of turning into question marks: é becomes %C3%A9, a space %20 and an ampersand %26. Typical jobs are decoding links pulled from CSV exports or old databases to recover the original address, encoding search terms or file names that people type before placing them in redirect links and analytics tags, and making the addresses recorded in server logs readable during an incident.
Why percent-encoding still trips people up
Every language ships a built-in encode function, yet developers keep hitting the same wall: JavaScript's encodeURIComponent treats spaces differently than PHP's urlencode, and neither agrees on what a query string versus a path segment actually requires. Reserved characters like plus signs and tildes end up handled inconsistently across runtimes.
What the encoder actually does
Under the hood it walks the input byte by byte, converting unsafe or reserved characters into their %XX percent-encoded form on the way out, or resolving %XX sequences back into readable text on the way in. Multi-byte UTF-8 characters, common in names, addresses and international content, are handled natively rather than mangled into question marks.
A brief note on where this format comes from
Percent-encoding predates most of today's web frameworks; it was formalized to let URLs, originally designed for a narrow ASCII character set, safely carry arbitrary bytes like spaces, ampersands and non-Latin scripts. That legacy is exactly why encoding rules feel inconsistent today: different specifications, URI syntax versus HTML form submission, diverged over decades, and most libraries only implement one of them well.
What you can do with it
Cleaning scraped or imported links
Decode double-encoded URLs pulled from CSV exports or old databases to recover the original, human-readable address before re-storing it.
Normalizing user-submitted forms
Percent-encode search terms or file names entered by users so they can be safely embedded in redirect links and analytics tags.
Fixing malformed log data
Decode raw request URIs captured in server logs to make them readable during incident investigation or traffic analysis.
FAQ
What is the difference between URL encoding and URL decoding?
Encoding converts unsafe characters, like spaces, ampersands and accented letters, into %XX sequences so a URL is transmitted safely; decoding reverses that process back to readable text.
What happens if my request fails?
The task is retried automatically up to three times. If it still fails, you receive a clear error and are not charged.
Why does é turn into two codes, %C3%A9?
Because in UTF-8 the letter é takes two bytes, and each byte is written as a percent sign followed by two hexadecimal digits. Accented letters and other scripts therefore produce several codes in a row.
Should a space become %20 or a plus sign?
Here a space becomes %20, as in the example. Some tools write a plus sign instead because HTML form submission follows a different specification from address syntax, which is why results differ between languages.
How do I fix a link that was encoded twice?
Run it through the decoder. Links pulled from CSV exports or old databases are often encoded twice, and decoding them recovers the original, readable address before you store it again.
Related tools
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/dev/url-encode \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"a b&c"}'const res = await fetch("https://api.kit.forhosting.com/dev/url-encode", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"text": "a b&c"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/dev/url-encode",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"text": "a b&c"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/dev/url-encode", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"text":"a b&c"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"text":"a b&c"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/dev/url-encode", 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": "a b&c"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "dev.url_encode",
"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.
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. |
Technical notes
This URL encode API percent-encodes and decodes strings exactly the way RFC 3986 expects, so query parameters, path segments and form data survive the trip intact.
Why percent-encoding still trips people up
Our dev.url_encode endpoint removes that ambiguity by applying one deterministic rule set, so the same input always produces the same output no matter which stack called it.
What the endpoint actually does
POST /dev/url-encode accepts a string and a direction, either encode or decode, and returns a task_id immediately since the job runs asynchronously.
Where it fits in a pipeline
Teams call this endpoint before building outbound webhook URLs, when normalizing user-submitted links for storage, or when cleaning malformed query strings pulled from log files and third-party exports. Because results arrive by signed webhook or a signed link valid for 24 hours, you can drop it into a batch job that processes thousands of URLs without holding a connection open or polling for each one.
Reliability without the guesswork
Each request is billed only on success; a failed task is retried up to three times automatically and never charged if it still fails, so you are not stuck babysitting encoding edge cases from rare byte sequences. At $0.002 per request, running it across an entire URL dataset costs a predictable, published amount with no tiers to negotiate and no trial to expire.
Integration use cases
Building outbound webhook URLs
Encode dynamic query parameters, like customer emails or free-text tags, before appending them to a callback URL so the receiving server parses them correctly.
Technical questions
Is there a free tier for the URL encode API?
The tool above runs free in your browser. The API is paid — each call draws from your prepaid ForHosting KIT balance: top up from $10.00 (it never expires), pay each request's published price, and a call with no balance returns HTTP 402. No subscription, no tokens, and a failed task is never charged.
How much does it cost per request?
Each call to POST /dev/url-encode costs $0.002, billed only when the task completes successfully.
Does it handle non-Latin characters like Chinese or Arabic text?
Yes. The endpoint processes UTF-8 multi-byte sequences correctly, producing valid percent-encoded output for any script rather than dropping or corrupting characters.
How do I get the result back?
Every task returns its result via a signed webhook, the recommended method for automated pipelines, or a signed link valid for 24 hours if you prefer to fetch it manually.
Can I encode a full URL or only individual parameters?
You can submit either a full URL or a single value like a query parameter; the endpoint encodes exactly the string you send without assuming structure.
Why not just use my language's built-in encode function?
Built-in functions vary by language in how they treat spaces, plus signs and reserved characters, which causes subtle bugs across mixed-stack systems; this endpoint applies one consistent rule set regardless of caller.