-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathurl-encoder.html
More file actions
1301 lines (1172 loc) · 84.2 KB
/
Copy pathurl-encoder.html
File metadata and controls
1301 lines (1172 loc) · 84.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Free URL Encoder <title>Free URL Encoder & Decoder Online — RFC 3986 | FreeDevTool</title> Decoder — RFC 3986 Online | FreeDevTool</title>
<meta name="description" content="Percent-encode and decode URLs. Distinguishes encodeURI vs encodeURIComponent vs RFC 3986 modes. Free online URL encoder, no signup.">
<meta name="robots" content="index, follow, max-image-preview:large">
<link rel="canonical" href="https://freedevtool.org/url-encoder">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preload" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=DM+Sans:wght@300;400;500;600&display=swap" as="style">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=DM+Sans:wght@300;400;500;600&display=swap">
<link rel="preload" href="style.css?v=20260502-cards" as="style">
<link rel="stylesheet" href="style.css?v=20260502-cards">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/favicon.svg">
<meta property="og:image" content="https://freedevtool.org/og-image.svg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="URL Encoder & Decoder — FreeDevTool">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://freedevtool.org/og-image.svg">
<meta name="twitter:title" content="URL Encoder & Decoder — Percent Encoding">
<meta name="twitter:description" content="Encode/decode URLs with encodeURIComponent or encodeURI. Free, runs in browser, no signup.">
<!-- Google Analytics 4 -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-3L0CMH3X36"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-3L0CMH3X36');
</script>
<meta property="og:title" content="URL Encoder & Decoder — FreeDevTool">
<meta property="og:description" content="Free online URL encoder and decoder. Instant percent-encoding tool.">
<meta property="og:url" content="https://freedevtool.org/url-encoder">
<meta property="og:type" content="website">
<meta property="og:site_name" content="FreeDevTool">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "URL Encoder Decoder",
"applicationCategory": "DeveloperApplication",
"operatingSystem": "Web Browser",
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" },
"description": "Free online URL encoder and decoder tool"
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "What is the difference between encodeURI and encodeURIComponent?",
"acceptedAnswer": { "@type": "Answer", "text": "encodeURI encodes a full URI but preserves characters that have special meaning in URLs (like ://?#&=). encodeURIComponent encodes everything except unreserved characters (letters, digits, - _ . ~), making it suitable for encoding individual query parameter values. Use encodeURIComponent for values and encodeURI for complete URLs." }
},
{
"@type": "Question",
"name": "Why do URLs need to be encoded?",
"acceptedAnswer": { "@type": "Answer", "text": "URLs can only contain a limited set of ASCII characters per RFC 3986. Special characters like spaces, &, =, ?, #, and non-ASCII characters (Unicode/UTF-8) must be percent-encoded to be safely transmitted. Without encoding, these characters would be misinterpreted as URL delimiters or cause parsing errors in browsers and servers." }
},
{
"@type": "Question",
"name": "How do I encode spaces in a URL — plus sign or %20?",
"acceptedAnswer": { "@type": "Answer", "text": "Both are valid but in different contexts. %20 is the standard percent-encoding for spaces (RFC 3986) and works everywhere in a URL — path, query, fragment. The plus sign (+) represents a space only in application/x-www-form-urlencoded format, used in HTML form submissions. For general URL encoding, prefer %20. Use + only when building form-encoded POST bodies." }
},
{
"@type": "Question",
"name": "What is double encoding and how do I avoid it?",
"acceptedAnswer": { "@type": "Answer", "text": "Double encoding happens when an already-encoded string is encoded again — for example, %20 becomes %2520 because the % itself gets encoded. To avoid it: encode raw values before inserting them into a URL, never encode a full URL that already contains percent-encoded characters, or decode first then re-encode once. Look for %25 or %2520 sequences as a giveaway." }
},
{
"@type": "Question",
"name": "How do I URL encode non-ASCII and Unicode characters?",
"acceptedAnswer": { "@type": "Answer", "text": "Non-ASCII characters are first converted to UTF-8 bytes, then each byte is percent-encoded. The character é (U+00E9) becomes %C3%A9 in UTF-8 encoding. CJK characters typically use 3 bytes (e.g. 中 → %E4%B8%AD), and emojis use 4 bytes. JavaScript's encodeURIComponent handles this automatically, as does Python's urllib.parse.quote." }
},
{
"@type": "Question",
"name": "Does URL encoding affect SEO?",
"acceptedAnswer": { "@type": "Answer", "text": "Google indexes URL-encoded characters fine, but clean, human-readable URLs are preferred for SEO and click-through rate. Excessive percent-encoding makes URLs hard to read and share. Best practices: use hyphens instead of spaces, lowercase URL paths, avoid non-ASCII in paths (use ASCII transliteration), and keep encoding restricted to query parameters." }
},
{
"@type": "Question",
"name": "What is the maximum length of a URL?",
"acceptedAnswer": { "@type": "Answer", "text": "RFC 3986 sets no formal maximum, but practical limits exist. Browsers cap at around 2,000-32,000 characters (Chrome, Firefox accept long URLs but address-bar truncation begins ~2,000). Apache and Nginx default to 8 KB. Google indexes URLs reliably up to ~2,000 characters. Practical rule: keep URLs under 2,000 characters for cross-platform compatibility. For longer payloads, switch to POST body." }
},
{
"@type": "Question",
"name": "How do I encode the plus sign (+) in a URL?",
"acceptedAnswer": { "@type": "Answer", "text": "Encode + as %2B. In form-encoded URLs, a literal + is interpreted as a space. So a phone number +1 555 1234 sent raw becomes ' 1 555 1234' on the server. Always pre-encode + to %2B when sending phone numbers, email plus-tags (user+tag@example.com), or any data where + has semantic meaning. JavaScript's encodeURIComponent and PHP's urlencode both encode + as %2B correctly." }
},
{
"@type": "Question",
"name": "What is the difference between URL encoding and HTML entity encoding?",
"acceptedAnswer": { "@type": "Answer", "text": "Different contexts and syntax. URL encoding uses percent-triplets (%26 for &) and applies to URLs in transit. HTML entity encoding uses named or numeric references (& or & for &) and applies inside HTML markup to prevent characters from being parsed as tags. They're often combined: an <a href> attribute may contain URL-encoded values inside HTML-escaped attribute syntax. Mixing them causes display bugs and XSS holes." }
},
{
"@type": "Question",
"name": "How do I safely encode an entire URL string?",
"acceptedAnswer": { "@type": "Answer", "text": "Generally, do not encode the whole URL — encode at the level of individual components. Use a URL builder API: new URL() + URLSearchParams in JavaScript, urllib.parse.urlencode in Python, url.URL struct in Go. These libraries encode each component correctly without manual reserved-character handling. If you must encode a full URL string, use encodeURI() in JavaScript — it preserves URL structure while escaping illegal characters in the path." }
},{"@type":"Question","name":"Why is %20 used in URLs?","acceptedAnswer":{"@type":"Answer","text":"%20 is the percent-encoded representation of a space character (ASCII 32 = hex 20). Spaces are not allowed in valid URLs, so they must be encoded. In query strings, + is also accepted as a space (legacy form data encoding), but %20 is universal."}},{"@type":"Question","name":"What characters need to be URL encoded?","acceptedAnswer":{"@type":"Answer","text":"RFC 3986 reserves these characters: colon, forward slash, question mark, hash, brackets, at sign, exclamation, dollar, ampersand, parentheses, asterisk, plus, comma, semicolon, equals. They must be encoded when they appear as data inside a URL. Unreserved characters (A-Z, a-z, 0-9, hyphen, underscore, period, tilde) never need encoding."}},{"@type":"Question","name":"Why does my URL show + instead of spaces?","acceptedAnswer":{"@type":"Answer","text":"The + symbol means a space in form-encoded URLs (application/x-www-form-urlencoded used by HTML forms). This predates RFC 3986. When decoding, treat + as a space only in the query string component, not in the URL path."}}
]
}
</script>
<style>
.mode-select {
display: flex; gap: 8px; margin-bottom: 6px; flex-wrap: wrap;
}
.mode-select label {
display: flex; align-items: center; gap: 6px;
font-size: 12px; text-transform: none; letter-spacing: normal;
cursor: pointer; margin: 0; padding: 6px 12px;
border: 1px solid var(--border); border-radius: var(--radius);
transition: border-color .2s, background .2s;
}
.mode-select label:hover { border-color: var(--border2); background: var(--bg3); }
.mode-select input[type="radio"]:checked + span { color: var(--accent); }
.mode-select label:has(input:checked) {
border-color: rgba(0,208,132,.3); background: var(--accent-dim);
}
.char-count {
font-family: var(--mono); font-size: 11px;
color: var(--text3); text-align: right; margin-top: 4px;
}
.url-breakdown {
background: var(--bg3); border: 1px solid var(--border);
border-radius: var(--radius); padding: 12px 14px;
font-family: var(--mono); font-size: 12px;
margin-top: 12px;
}
.url-breakdown-row {
display: flex; gap: 8px; padding: 4px 0;
border-bottom: 1px solid var(--border);
}
.url-breakdown-row:last-child { border-bottom: none; }
.url-breakdown-key { color: var(--accent); min-width: 80px; }
.url-breakdown-val { color: var(--text2); word-break: break-all; }
/* Long-form article styling */
.article-section {
margin: 40px 0;
animation: fadeInUp .5s var(--ease-out) .15s both;
}
.article-section h2 {
font-size: 22px; font-weight: 600;
color: var(--text); margin-bottom: 14px;
letter-spacing: -0.015em;
padding-bottom: 8px;
border-bottom: 1px solid var(--border);
}
.article-section h3 {
font-size: 16px; font-weight: 600;
color: var(--text); margin: 22px 0 10px;
}
.article-section p {
color: var(--text2); font-size: 14.5px;
line-height: 1.75; margin-bottom: 14px;
max-width: 760px;
}
.article-section ul {
margin: 0 0 16px 22px;
color: var(--text2); font-size: 14px; line-height: 1.7;
}
.article-section ul li { margin-bottom: 6px; }
.article-section a {
color: var(--accent); text-decoration: none;
transition: color .2s;
}
.article-section a:hover { color: var(--accent2); text-decoration: underline; }
.article-section strong { color: var(--text); font-weight: 600; }
/* Comparison + reference tables */
.ref-table {
width: 100%;
border-collapse: collapse;
margin: 14px 0 18px;
background: var(--bg2);
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
font-size: 13.5px;
}
.ref-table th {
background: var(--bg3);
color: var(--text);
font-weight: 600; text-align: left;
padding: 10px 14px;
border-bottom: 1px solid var(--border);
font-size: 12.5px; letter-spacing: .3px;
}
.ref-table td {
padding: 10px 14px;
color: var(--text2);
border-bottom: 1px solid var(--border);
vertical-align: top;
}
.ref-table tr:last-child td { border-bottom: none; }
.ref-table tr:hover td { background: var(--bg3); }
.ref-table code {
font-family: var(--mono); font-size: 12px;
color: var(--accent); background: var(--bg4);
padding: 1px 6px; border-radius: 3px;
}
.ref-table .yes { color: var(--accent); font-weight: 600; }
.ref-table .no { color: var(--red); font-weight: 600; }
/* Code blocks for multi-language examples */
.lang-block {
background: var(--bg3);
border: 1px solid var(--border);
border-radius: var(--radius);
margin: 10px 0 18px;
overflow: hidden;
}
.lang-block-header {
background: var(--bg4);
padding: 8px 14px;
font-family: var(--mono); font-size: 11px; font-weight: 600;
color: var(--accent);
text-transform: uppercase; letter-spacing: 1px;
border-bottom: 1px solid var(--border);
}
.lang-block pre {
margin: 0; padding: 14px 16px;
overflow-x: auto;
font-family: var(--mono); font-size: 12.5px;
line-height: 1.65;
color: var(--text);
background: transparent;
}
.lang-block pre code { color: var(--text); background: none; padding: 0; font-size: 12.5px; }
/* Aside / callout */
.article-aside {
background: var(--accent-dim);
border-left: 3px solid var(--accent);
padding: 14px 18px;
margin: 18px 0;
border-radius: 0 var(--radius) var(--radius) 0;
color: var(--text2); font-size: 13.5px; line-height: 1.7;
}
.article-aside strong { color: var(--accent); }
/* Last-updated badge */
.last-updated {
display: inline-flex; align-items: center; gap: 6px;
font-family: var(--mono); font-size: 11px;
color: var(--text3); margin-top: 8px;
letter-spacing: .3px;
}
.last-updated::before {
content: ''; display: inline-block;
width: 6px; height: 6px; border-radius: 50%;
background: var(--accent);
box-shadow: 0 0 6px rgba(0,208,132,.6);
}
</style>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://freedevtool.org/"
},
{
"@type": "ListItem",
"position": 2,
"name": "All Tools",
"item": "https://freedevtool.org/all-tools"
},
{
"@type": "ListItem",
"position": 3,
"name": "URL Encoder / Decoder",
"item": "https://freedevtool.org/url-encoder"
}
]
}
</script>
<script src="/ga4-events.js" defer></script>
</head>
<body>
<nav>
<a class="nav-logo" href="/" aria-label="FreeDevTool home"><svg class="logo-mark" width="22" height="22" viewBox="0 0 24 24" aria-hidden="true" fill="none"><rect x="1" y="1" width="22" height="22" rx="6" fill="currentColor" opacity=".12"/><path d="M9.5 8.5L6 12l3.5 3.5M14.5 8.5L18 12l-3.5 3.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>FreeDevTool</a>
<div class="nav-links">
<div class="nav-dropdown" id="tools-dropdown">
<a href="all-tools" onclick="event.preventDefault();this.parentElement.classList.toggle('open')" aria-haspopup="true">Tools <svg class="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></a>
<div class="nav-dropdown-menu">
<a href="encoding-tools">
<div class="dd-icon">b64</div>
<div class="dd-info"><div class="dd-name">Encoding & Conversion</div><div class="dd-count">11 tools · Base64, YAML, px→rem</div></div>
</a>
<a href="generation-tools">
<div class="dd-icon">{ }</div>
<div class="dd-info"><div class="dd-name">Generation & Formatting</div><div class="dd-count">16 tools · JSON, SQL, gradients</div></div>
</a>
<a href="security-tools">
<div class="dd-icon">#</div>
<div class="dd-info"><div class="dd-name">Security & Hashing</div><div class="dd-count">3 tools · JWT, MD5, SHA</div></div>
</a>
<a href="text-tools">
<div class="dd-icon">.*</div>
<div class="dd-info"><div class="dd-name">Code & Text Tools</div><div class="dd-count">9 tools · Regex, diff, tokens</div></div>
</a>
<a href="devops-tools">
<div class="dd-icon">JS</div>
<div class="dd-info"><div class="dd-name">Optimization & DevOps</div><div class="dd-count">7 tools · Minifiers, cURL, git</div></div>
</a>
<a href="network-tools">
<div class="dd-icon">IP</div>
<div class="dd-info"><div class="dd-name">Network & Time</div><div class="dd-count">4 tools · IP, DNS, timestamps</div></div>
</a>
<a href="seo-tools">
<div class="dd-icon">SEO</div>
<div class="dd-info"><div class="dd-name">SEO & Meta Tools</div><div class="dd-count">3 tools · OG, meta, slug</div></div>
</a>
<div class="nav-dropdown-divider"></div>
<a class="dd-all" href="all-tools">
<div class="dd-icon">All</div>
<div class="dd-info"><div class="dd-name">Browse all 50 tools</div><div class="dd-count">Searchable catalog & categories</div></div>
</a>
</div>
</div>
<a href="/guides">Guides</a>
<a href="about">About</a>
<a href="privacy">Privacy</a>
</div>
</nav>
<div id="copy-toast">Copied!</div>
<div class="wrapper">
<a class="tool-back" href="/" aria-label="Back to home">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 18l-6-6 6-6"/></svg>
Back
</a>
<div class="tool-header">
<div class="tool-badge">Encoding Tool</div>
<h1>URL Encoder & Decoder</h1>
<p class="tool-description">
Encode and decode URLs with percent-encoding (<a href="https://datatracker.ietf.org/doc/html/rfc3986" rel="noopener" style="color:var(--accent)">RFC 3986</a>). Supports <code>encodeURIComponent</code>, <code>encodeURI</code>, form-style <code>+</code>-for-space, UTF-8 and Unicode. Runs in your browser — no upload, no signup.
</p>
<div class="last-updated">Last updated: May 2026 · Written by <a href="/about">Anees Ur Rehman</a>, full-stack developer</div>
</div>
<div class="tool-card">
<div class="tool-card-header">
<div class="dot dot-red"></div>
<div class="dot dot-yellow"></div>
<div class="dot dot-green"></div>
<span class="tool-card-title">url-encoder.tool</span>
</div>
<div class="tool-body">
<div class="tabs">
<button class="tab active" onclick="setMode('encode', this)">Encode</button>
<button class="tab" onclick="setMode('decode', this)">Decode</button>
</div>
<!-- ENCODE -->
<div id="mode-encode">
<label>Encoding Method</label>
<div class="mode-select">
<label><input type="radio" name="enc-method" value="component" checked onchange="doEncode()"><span>encodeURIComponent</span></label>
<label><input type="radio" name="enc-method" value="uri" onchange="doEncode()"><span>encodeURI</span></label>
<label><input type="radio" name="enc-method" value="form" onchange="doEncode()"><span>Form (+ for spaces)</span></label>
</div>
<div style="margin-top:12px">
<label>Text to encode</label>
<textarea id="encode-input" placeholder="Hello World! foo=bar&baz=qux" oninput="doEncode()" rows="4"></textarea>
<div class="char-count" id="encode-count">0 characters</div>
</div>
<div class="divider"></div>
<div class="output-label">
<label style="margin:0">Encoded Output</label>
<button class="btn btn-ghost" onclick="copyOutput('encode-output')">Copy</button>
</div>
<div class="output-block" id="encode-output" style="color:var(--text2); font-style:italic">Output will appear here...</div>
<div class="char-count" id="encode-out-count"></div>
</div>
<!-- DECODE -->
<div id="mode-decode" style="display:none">
<label>Encoded URL or string to decode</label>
<textarea id="decode-input" placeholder="Hello%20World%21%20foo%3Dbar%26baz%3Dqux" oninput="doDecode()" rows="4"></textarea>
<div class="char-count" id="decode-count">0 characters</div>
<div class="divider"></div>
<div class="output-label">
<label style="margin:0">Decoded Output</label>
<button class="btn btn-ghost" onclick="copyOutput('decode-output')">Copy</button>
</div>
<div class="output-block" id="decode-output" style="color:var(--text2); font-style:italic">Output will appear here...</div>
<div id="decode-status"></div>
<div id="url-parts" style="display:none">
<div class="divider"></div>
<label>URL Breakdown</label>
<div class="url-breakdown" id="url-breakdown"></div>
</div>
</div>
</div>
</div>
<!-- =============================================================
LONG-FORM ARTICLE — comprehensive guide for E-E-A-T + ranking.
Covers: definition, mechanics, encodeURI vs encodeURIComponent,
character reference, 8-language code examples, scenarios,
+ vs %20, double encoding, SEO best practices.
============================================================= -->
<article>
<p class="aeo-lead" style="font-size:16px;line-height:1.7;color:var(--text);max-width:760px;margin:24px auto 18px;padding:0 4px">
<strong>URL encoding</strong> (also called percent encoding, defined in RFC 3986) replaces unsafe characters in URLs with a percent sign followed by two hexadecimal digits — a space becomes <code>%20</code>, an ampersand becomes <code>%26</code>, a forward slash becomes <code>%2F</code>. Encoding is required whenever you put data into a URL: query strings, fragment identifiers, OAuth state parameters, webhook URLs. This <strong>free URL encoder and decoder</strong> shows three encoding modes side by side — <code>encodeURI</code>, <code>encodeURIComponent</code>, and strict RFC 3986 — so you can pick the right one for your context.
</p>
<section id="examples" style="max-width:760px;margin:24px auto 32px">
<h2 style="font-size:18px;margin-bottom:14px">Examples</h2>
<div style="background:var(--bg3);border:1px solid var(--border);border-radius:var(--radius);padding:16px;margin-bottom:12px">
<strong style="display:block;color:var(--accent);font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px">Spaces in a query string</strong>
<code style="display:block;font-family:var(--mono);font-size:13px;line-height:1.6">Input: hello world<br>Encoded: hello%20world</code>
</div>
<div style="background:var(--bg3);border:1px solid var(--border);border-radius:var(--radius);padding:16px;margin-bottom:12px">
<strong style="display:block;color:var(--accent);font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px">encodeURI vs encodeURIComponent</strong>
<code style="display:block;font-family:var(--mono);font-size:13px;line-height:1.6">Input: https://example.com/path?key=a&b=c<br>encodeURI: https://example.com/path?key=a&b=c<br>encodeURIComponent: https%3A%2F%2Fexample.com%2Fpath%3Fkey%3Da%26b%3Dc</code>
<p style="margin:8px 0 0;font-size:13px">Use <code>encodeURI</code> for whole URLs you want to preserve. Use <code>encodeURIComponent</code> for individual query-string values.</p>
</div>
<div style="background:var(--bg3);border:1px solid var(--border);border-radius:var(--radius);padding:16px">
<strong style="display:block;color:var(--accent);font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px">OAuth state parameter</strong>
<p style="margin:0;font-size:14px;line-height:1.6">OAuth state values often contain JSON, base64, or random bytes — always encode them with <code>encodeURIComponent</code> before adding to the authorize URL, or the callback will silently drop characters.</p>
</div>
</section>
<aside class="founder-note" style="max-width:760px;margin:24px auto 32px;padding:20px 24px;background:rgba(0,208,132,0.05);border-left:3px solid var(--accent);border-radius:6px;font-size:14px;line-height:1.7;color:var(--text2)"><div style="font-family:var(--mono);font-size:11px;color:var(--accent);letter-spacing:1.5px;text-transform:uppercase;margin-bottom:10px;font-weight:600">💡 Why I built this</div><p style="margin:0 0 12px">I built this after a coworker spent two hours debugging why their OAuth state parameter was not surviving a redirect. The problem: they used encodeURI() instead of encodeURIComponent() — the former preserves URL structure characters which broke the surrounding query string. Most online URL encoders only do one mode. This one shows all three: encodeURI, encodeURIComponent, and RFC 3986. Side by side so you can see the difference.</p><p style="margin:0;font-size:13px;color:var(--text3)">— <a href="/about" style="color:var(--accent);text-decoration:none">Anees Ur Rehman</a>, full-stack developer</p></aside>
<section class="article-section">
<h2>What is URL encoding?</h2>
<p><strong>URL encoding</strong> — also called <strong>percent-encoding</strong> — is the standard mechanism for representing characters in a Uniform Resource Locator (URL) that would otherwise be illegal, ambiguous, or unsafe. The rules are codified in <a href="https://datatracker.ietf.org/doc/html/rfc3986" rel="noopener">RFC 3986</a>, the specification that defines URI syntax for the modern web.</p>
<p>The reason encoding exists is historical: URLs were designed in 1994 around a tiny alphabet of safe ASCII characters. Anything outside that set — spaces, accented letters, emojis, Chinese characters, query-string separators when used as data — needs to be expressed using a small, universally-portable code: a percent sign (<code>%</code>) followed by two hexadecimal digits representing one byte of the original character. The character <code>A</code> (ASCII 65) becomes <code>%41</code>; a space becomes <code>%20</code>; the character <code>é</code> (which takes two bytes in UTF-8) becomes <code>%C3%A9</code>.</p>
<p>Without encoding, URLs would silently break in unpredictable places. A search query like <em>"hello world & friends"</em> embedded raw into <code>?q=hello world & friends</code> would be interpreted by the server as three separate parameters: <code>q=hello world</code>, <code>friends</code>, and an empty value. Encoded, it becomes <code>?q=hello%20world%20%26%20friends</code> — unambiguous, parseable, and safe to transmit through every router, CDN, proxy, and log on the way to your server.</p>
</section>
<section class="article-section">
<h2>How URL encoding works under the hood</h2>
<p>The percent-encoding algorithm has three steps and applies to every character that needs encoding:</p>
<ul>
<li><strong>Step 1 — Convert to bytes.</strong> The character is converted to its byte representation in <strong>UTF-8</strong> (the standard since RFC 3986 was updated in 2005). ASCII characters are 1 byte; accented Latin letters are 2 bytes; most CJK characters and emojis are 3–4 bytes.</li>
<li><strong>Step 2 — Express each byte as two hex digits.</strong> A byte has 256 possible values (0x00 to 0xFF), each representable in two uppercase hexadecimal digits.</li>
<li><strong>Step 3 — Prefix each hex pair with a percent sign.</strong> The output is a sequence of <code>%XX</code> triplets — one triplet per byte of the original character.</li>
</ul>
<h3>A worked example: encoding "café"</h3>
<p>The string <code>café</code> contains four characters but five bytes in UTF-8 (because <code>é</code> is U+00E9, encoded as <code>0xC3 0xA9</code>):</p>
<ul>
<li><code>c</code> → 1 byte (0x63) → <strong>doesn't need encoding</strong> (unreserved ASCII letter)</li>
<li><code>a</code> → 1 byte (0x61) → doesn't need encoding</li>
<li><code>f</code> → 1 byte (0x66) → doesn't need encoding</li>
<li><code>é</code> → 2 bytes (0xC3, 0xA9) → encoded as <code>%C3%A9</code></li>
</ul>
<p>Final encoded form: <code>caf%C3%A9</code>. The reverse — decoding — reads the <code>%XX</code> sequences back into bytes, then interprets the byte stream as UTF-8 to reconstruct the original characters.</p>
<div class="article-aside">
<strong>Why uppercase hex?</strong> RFC 3986 §2.1 says lowercase hex (<code>%c3%a9</code>) is technically valid, but uppercase is the canonical form. Many CDNs and caches normalize URLs to uppercase before generating cache keys — using lowercase risks cache misses on edge networks like Cloudflare and Akamai.
</div>
</section>
<section class="article-section">
<h2>encodeURI vs encodeURIComponent — which one to use?</h2>
<p>This is the single most-searched question in the URL encoding space — and getting it wrong is the most common bug in URL handling. JavaScript provides two functions with confusingly similar names but very different behavior. The right choice depends on <strong>what part of the URL you're encoding</strong>.</p>
<table class="ref-table">
<thead>
<tr><th>Aspect</th><th><code>encodeURI()</code></th><th><code>encodeURIComponent()</code></th></tr>
</thead>
<tbody>
<tr>
<td>Use case</td>
<td>Encoding a <strong>complete URL</strong></td>
<td>Encoding a <strong>single value</strong> within a URL</td>
</tr>
<tr>
<td>Preserves reserved chars (<code>: / ? # & = +</code>)</td>
<td><span class="yes">Yes</span> — leaves URL structure intact</td>
<td><span class="no">No</span> — encodes everything</td>
</tr>
<tr>
<td>Example input</td>
<td><code>https://x.com/search?q=hello world</code></td>
<td><code>hello world & friends</code></td>
</tr>
<tr>
<td>Example output</td>
<td><code>https://x.com/search?q=hello%20world</code></td>
<td><code>hello%20world%20%26%20friends</code></td>
</tr>
<tr>
<td>When to pick this</td>
<td>You have a full URL and want to make it safe to transmit (rare in practice)</td>
<td>You're building a URL piece by piece — encoding query values, path segments, or form data (most cases)</td>
</tr>
<tr>
<td>Common bug</td>
<td>Forgetting that it doesn't encode <code>&</code> or <code>=</code> — your data leaks into URL structure</td>
<td>Encoding the whole URL with this — breaks <code>://</code>, <code>?</code>, <code>&</code> separators</td>
</tr>
</tbody>
</table>
<p><strong>Rule of thumb:</strong> 95% of the time you want <code>encodeURIComponent</code>. It's the right tool for encoding individual values that you'll plug into a URL. <code>encodeURI</code> is for the rare case where you have a full, already-structured URL that just needs special-character escaping (e.g. spaces in path segments).</p>
</section>
<section class="article-section">
<h2>Reserved vs unreserved characters reference</h2>
<p>RFC 3986 splits ASCII characters into three groups: <strong>unreserved</strong> (never encoded), <strong>reserved</strong> (have special meaning in URLs — encoded only when used as data), and <strong>everything else</strong> (always encoded, including spaces, control characters, and high-ASCII).</p>
<table class="ref-table">
<thead>
<tr><th>Group</th><th>Characters</th><th>Encoded?</th></tr>
</thead>
<tbody>
<tr>
<td><strong>Unreserved</strong></td>
<td><code>A–Z</code> <code>a–z</code> <code>0–9</code> <code>-</code> <code>_</code> <code>.</code> <code>~</code></td>
<td><span class="no">Never</span></td>
</tr>
<tr>
<td><strong>Reserved (gen-delims)</strong></td>
<td><code>:</code> <code>/</code> <code>?</code> <code>#</code> <code>[</code> <code>]</code> <code>@</code></td>
<td>Only when used as data, not as URL structure</td>
</tr>
<tr>
<td><strong>Reserved (sub-delims)</strong></td>
<td><code>!</code> <code>$</code> <code>&</code> <code>'</code> <code>(</code> <code>)</code> <code>*</code> <code>+</code> <code>,</code> <code>;</code> <code>=</code></td>
<td>Only when used as data within a query value</td>
</tr>
<tr>
<td><strong>Everything else</strong></td>
<td>Space, <code>"</code> <code><</code> <code>></code> <code>\</code> <code>^</code> <code>{</code> <code>}</code> <code>|</code> <code>` </code>, all non-ASCII (UTF-8)</td>
<td><span class="yes">Always</span></td>
</tr>
</tbody>
</table>
<h3>Common encoded values cheat sheet</h3>
<table class="ref-table">
<thead>
<tr><th>Character</th><th>Encoded</th><th>When you'll see it</th></tr>
</thead>
<tbody>
<tr><td>space</td><td><code>%20</code> or <code>+</code></td><td>The most common — see "+ vs %20" section below</td></tr>
<tr><td><code>!</code></td><td><code>%21</code></td><td>Sometimes encoded, sometimes left raw — depends on the encoder</td></tr>
<tr><td><code>"</code></td><td><code>%22</code></td><td>Always encoded</td></tr>
<tr><td><code>#</code></td><td><code>%23</code></td><td>Encoded when in a query value (otherwise it's the fragment delimiter)</td></tr>
<tr><td><code>&</code></td><td><code>%26</code></td><td>Encoded inside query values to avoid splitting parameters</td></tr>
<tr><td><code>+</code></td><td><code>%2B</code></td><td>Critical — raw <code>+</code> means space in form-encoded URLs</td></tr>
<tr><td><code>/</code></td><td><code>%2F</code></td><td>Encoded only when used as data (not as path separator)</td></tr>
<tr><td><code>=</code></td><td><code>%3D</code></td><td>Encoded inside query values to avoid splitting key=value</td></tr>
<tr><td><code>?</code></td><td><code>%3F</code></td><td>Encoded inside query values (otherwise it's the query delimiter)</td></tr>
<tr><td><code>%</code></td><td><code>%25</code></td><td>Always encoded — to avoid being read as a percent-encoding prefix</td></tr>
<tr><td><code>é</code></td><td><code>%C3%A9</code></td><td>Two-byte UTF-8 character, two percent-triplets</td></tr>
<tr><td><code>中</code></td><td><code>%E4%B8%AD</code></td><td>Three-byte UTF-8 character (CJK)</td></tr>
<tr><td>😀 (U+1F600)</td><td><code>%F0%9F%98%80</code></td><td>Four-byte UTF-8 character (emoji)</td></tr>
</tbody>
</table>
</section>
<section class="article-section">
<h2>How to URL encode in 8 programming languages</h2>
<p>Every modern language has standard-library URL encoding. Here are the canonical functions for the eight most-used languages, with one-line examples you can paste straight into your project.</p>
<h3>JavaScript (browser + Node.js)</h3>
<div class="lang-block">
<div class="lang-block-header">javascript</div>
<pre><code>// Encode a query value
const value = "hello world & friends";
const encoded = encodeURIComponent(value);
// → "hello%20world%20%26%20friends"
// Decode
const decoded = decodeURIComponent(encoded);
// → "hello world & friends"
// Encode a full URL (rarely needed)
const fullUrl = encodeURI("https://x.com/search?q=hello world");
// → "https://x.com/search?q=hello%20world"
</code></pre>
</div>
<h3>Python (3.x)</h3>
<div class="lang-block">
<div class="lang-block-header">python</div>
<pre><code>from urllib.parse import quote, quote_plus, unquote, unquote_plus
# Standard percent-encoding (spaces → %20)
quote("hello world & friends")
# → 'hello%20world%20%26%20friends'
# Form-style encoding (spaces → +)
quote_plus("hello world & friends")
# → 'hello+world+%26+friends'
# Decoding
unquote("hello%20world") # → 'hello world'
unquote_plus("hello+world") # → 'hello world'
</code></pre>
</div>
<h3>PHP</h3>
<div class="lang-block">
<div class="lang-block-header">php</div>
<pre><code>// Form-style (spaces → +) — what HTML form submission uses
$encoded = urlencode("hello world & friends");
// → "hello+world+%26+friends"
// RFC 3986 percent-encoding (spaces → %20) — preferred for paths
$encoded = rawurlencode("hello world & friends");
// → "hello%20world%20%26%20friends"
// Decoding
$decoded = urldecode("hello+world"); // → "hello world"
$decoded = rawurldecode("hello%20world"); // → "hello world"
</code></pre>
</div>
<h3>Java</h3>
<div class="lang-block">
<div class="lang-block-header">java</div>
<pre><code>import java.net.URLEncoder;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
// Note: Java's URLEncoder uses form-style encoding (spaces → +)
String encoded = URLEncoder.encode("hello world & friends", StandardCharsets.UTF_8);
// → "hello+world+%26+friends"
String decoded = URLDecoder.decode(encoded, StandardCharsets.UTF_8);
// → "hello world & friends"
</code></pre>
</div>
<h3>Ruby</h3>
<div class="lang-block">
<div class="lang-block-header">ruby</div>
<pre><code>require 'cgi'
require 'uri'
# Form-style encoding (spaces → +)
CGI.escape("hello world & friends")
# → "hello+world+%26+friends"
# RFC 3986 percent-encoding (spaces → %20) — modern preferred
URI.encode_www_form_component("hello world & friends")
# → "hello+world+%26+friends"
# Decoding
CGI.unescape("hello+world") # → "hello world"
</code></pre>
</div>
<h3>C# / .NET</h3>
<div class="lang-block">
<div class="lang-block-header">csharp</div>
<pre><code>using System;
using System.Web;
// HttpUtility — form-style encoding
string encoded = HttpUtility.UrlEncode("hello world & friends");
// → "hello+world+%26+friends"
// Uri.EscapeDataString — RFC 3986 (preferred for modern code)
string encoded2 = Uri.EscapeDataString("hello world & friends");
// → "hello%20world%20%26%20friends"
// Decoding
string decoded = Uri.UnescapeDataString("hello%20world");
</code></pre>
</div>
<h3>Go</h3>
<div class="lang-block">
<div class="lang-block-header">go</div>
<pre><code>import "net/url"
// Form-style (spaces → +) — for query strings
encoded := url.QueryEscape("hello world & friends")
// → "hello+world+%26+friends"
// RFC 3986 path-style (spaces → %20)
encoded := url.PathEscape("hello world & friends")
// → "hello%20world%20&%20friends"
// Decoding
decoded, _ := url.QueryUnescape("hello+world")
</code></pre>
</div>
<h3>Bash / cURL</h3>
<div class="lang-block">
<div class="lang-block-header">bash</div>
<pre><code># cURL has built-in URL encoding for data
curl -G --data-urlencode "q=hello world & friends" https://api.example.com/search
# Sends: GET /search?q=hello%20world%20%26%20friends
# Pure bash one-liner (POSIX-compatible)
encoded=$(printf '%s' "hello world" | jq -sRr @uri)
# → "hello%20world"
</code></pre>
</div>
<p>Note: <strong>JavaScript, Python's <code>quote</code>, PHP's <code>rawurlencode</code>, Ruby's <code>URI.encode_www_form_component</code>, C#'s <code>Uri.EscapeDataString</code>, and Go's <code>PathEscape</code></strong> all produce the same RFC 3986 output. <strong>Java's <code>URLEncoder</code>, PHP's <code>urlencode</code>, and JavaScript's form mode</strong> use the older form-encoded variant where spaces become <code>+</code> instead of <code>%20</code>. Mixing these is the #1 source of "this works on my machine" bugs.</p>
</section>
<section class="article-section">
<h2>Common URL encoding scenarios</h2>
<h3>Query string parameters</h3>
<p>The most common case. When building a URL like <code>https://api.example.com/search?q=...&filter=...</code>, encode each value with <code>encodeURIComponent</code> (or your language's RFC 3986 equivalent) <em>before</em> concatenating into the query string. Never encode the whole URL after building it — you'll either miss reserved characters or corrupt the structure.</p>
<h3>Path segments</h3>
<p>If your URL paths contain user-generated slugs that may include special characters (e.g. file names with spaces, names with accents), encode each path segment individually. <code>/files/My Document.pdf</code> becomes <code>/files/My%20Document.pdf</code>. Don't encode the slashes (<code>/</code>) themselves — those are path separators, not data.</p>
<h3>Form submission (POST bodies)</h3>
<p>Standard HTML forms send data as <code>application/x-www-form-urlencoded</code>: keys and values are URL-encoded, spaces become <code>+</code> (not <code>%20</code>), and pairs are joined by <code>&</code>. Most language libraries (e.g. <code>FormData</code> in JS, <code>requests.post(data=...)</code> in Python) handle this automatically — but if you build form bodies by hand, use the form-encoding variant of your language's URL encoder.</p>
<h3>Cookie values</h3>
<p>Cookies cannot contain raw spaces, semicolons, or commas. Browsers do not encode cookie values automatically — your application must encode before <code>document.cookie =</code> and decode after reading. Most cookie libraries handle this for you.</p>
<h3>HTTP headers and OAuth signatures</h3>
<p>Some HTTP headers (notably OAuth 1.0 <code>Authorization</code> headers and certain custom headers) require RFC 3986 percent-encoding. OAuth specifically forbids the <code>+</code>-for-space variant — using the wrong encoder breaks signature verification with cryptic 401 errors. When testing API requests with encoded query strings, the <a href="/http-request-builder">HTTP request builder</a> shows the wire format your server will actually receive.</p>
<h3>URL encoding for SEO-friendly slugs</h3>
<p>The cleanest URL is one that needs no encoding at all. Lower-case ASCII letters, digits, and hyphens (the <em>unreserved set</em>) pass through every parser unchanged and look identical in browser address bars, social-card previews, and email clients. Building URLs from user input? Pass titles through the <a href="/slug-generator">URL slug generator</a> first to strip diacritics, transliterate Cyrillic/Greek/CJK to ASCII, and produce hyphenated lower-case output that bypasses encoding entirely.</p>
</section>
<section class="article-section">
<h2>+ vs %20 — the eternal confusion explained</h2>
<p>Both <code>+</code> and <code>%20</code> represent a space character — but they're not interchangeable, and using the wrong one in the wrong place causes bugs that are hard to track down. Here's the rule:</p>
<table class="ref-table">
<thead>
<tr><th>Context</th><th>Use</th><th>Why</th></tr>
</thead>
<tbody>
<tr>
<td>URL <strong>path</strong> (e.g. <code>/files/my%20doc.pdf</code>)</td>
<td><code>%20</code></td>
<td>RFC 3986 standard. Raw <code>+</code> in a path is treated as a literal plus sign, not a space.</td>
</tr>
<tr>
<td>URL <strong>query string</strong> (e.g. <code>?q=hello%20world</code>)</td>
<td><code>%20</code> preferred, <code>+</code> tolerated</td>
<td>Modern web apps accept both. <code>%20</code> is unambiguous; <code>+</code> is the legacy form-encoded convention.</td>
</tr>
<tr>
<td>HTML <strong>form submission</strong> body (POST <code>application/x-www-form-urlencoded</code>)</td>
<td><code>+</code></td>
<td>Defined by the HTML spec. The form encoder produces <code>+</code> for spaces, percent-encoding for everything else.</td>
</tr>
<tr>
<td><strong>OAuth 1.0</strong> signatures</td>
<td><code>%20</code> only</td>
<td>OAuth 1.0 spec mandates RFC 3986. Using <code>+</code> breaks the signature.</td>
</tr>
</tbody>
</table>
<p><strong>The trap:</strong> if you encode <code>"hello world"</code> using a form-style encoder, you get <code>hello+world</code>. If a downstream parser expects RFC 3986 (where <code>+</code> is a literal plus), it decodes your value as <code>hello+world</code> instead of <code>hello world</code>. Spaces become plus signs in your database. This actually happens in production constantly — usually when the front-end uses one library and the back-end uses another.</p>
</section>
<section class="article-section">
<h2>Double encoding — what it is and how to avoid it</h2>
<p>Double encoding happens when an already-encoded string is encoded again. The percent sign itself (<code>%</code>) gets encoded as <code>%25</code>, so <code>%20</code> turns into <code>%2520</code>. The result still <em>looks</em> like a URL but contains literal <code>%20</code> sequences instead of actual spaces.</p>
<p>The classic scenario: a URL is built with proper encoding by component A, then component B (which doesn't realize it's already encoded) encodes it again before passing it on. The downstream parser decodes once, gets back the half-encoded version, treats <code>%20</code> as literal text, and serves the wrong page (or a 404).</p>
<h3>How to detect double encoding</h3>
<ul>
<li>Look for <code>%25</code> sequences in URLs that should not contain literal percent signs.</li>
<li><code>%2520</code> is the giveaway — that's a double-encoded space.</li>
<li>If your URL has <code>%26amp%3B</code> instead of <code>%26</code>, an HTML escape was applied on top of URL encoding.</li>
</ul>
<h3>How to fix it</h3>
<ul>
<li><strong>Decode once, then re-encode</strong> — strip the doubled layer with a single decode pass, then encode the raw value once.</li>
<li><strong>Audit your encoding boundary.</strong> Encode at exactly one point — typically the moment you concatenate values into a URL. Document this in the code.</li>
<li><strong>Don't encode in templates AND in code.</strong> If your template engine auto-escapes URL parameters (as some MVC frameworks do), don't pre-encode the values you pass in.</li>
</ul>
<div class="article-aside">
<strong>Quick test:</strong> if you suspect double encoding, paste the URL into the decoder above and check the result. If the output still contains <code>%XX</code> sequences, you have one more encoding layer to peel off.
</div>
</section>
<section class="article-section">
<h2>URL encoding bugs in popular frameworks (2026)</h2>
<p>Most production URL-encoding bugs aren't in your code — they're in the framework's defaults differing from yours. The cheat sheet:</p>
<table class="ref-table">
<thead><tr><th>Framework / Library</th><th>Encoding default</th><th>Common gotcha</th></tr></thead>
<tbody>
<tr><td><strong>Next.js (router)</strong></td><td>RFC 3986</td><td>Dynamic routes <code>[slug]</code> auto-decode <code>%2F</code> to <code>/</code> — strict-routing config needed if your slug must contain a literal slash.</td></tr>
<tr><td><strong>Express.js</strong></td><td><code>req.query</code> uses <code>qs</code> (form-decoded)</td><td><code>+</code> in query is decoded as space. Use <code>req.url</code> + <code>URL</code> constructor for RFC 3986.</td></tr>
<tr><td><strong>Flask / Django</strong></td><td>Werkzeug / Django uses form-encoding</td><td><code>request.GET</code> turns <code>+</code> into space silently. Use <code>urllib.parse.unquote</code> with <code>plus=False</code> for path segments.</td></tr>
<tr><td><strong>Java Spring</strong></td><td>RFC 3986 in <code>UriComponentsBuilder</code></td><td><code>HttpServletRequest.getParameter</code> form-decodes; mixing the two on the same request leaks raw <code>+</code> to logs.</td></tr>
<tr><td><strong>cURL <code>--data-urlencode</code></strong></td><td>Form-encoding</td><td>Encodes <code>+</code> as <code>%2B</code> by default — opposite of what most JS encoders do. Verify with <code>--trace-ascii</code>.</td></tr>
<tr><td><strong>fetch() / Axios</strong></td><td>browser uses RFC 3986 for URL strings</td><td>If you build the body as a string yourself, no encoding happens — pass <code>URLSearchParams</code> or <code>FormData</code> instead.</td></tr>
</tbody>
</table>
<p>To inspect what your client actually puts on the wire, paste the URL into the decoder above, then build the same request through the <a href="/http-request-builder">HTTP request builder</a> — you'll see the raw query string before any framework-side reinterpretation.</p>
<h3>encodeURIComponent vs URLSearchParams in JavaScript</h3>
<p>Two ways to build a query string in 2026, and only one of them handles <code>+</code> correctly without manual escaping. <code>encodeURIComponent('a b')</code> returns <code>'a%20b'</code> (space → <code>%20</code>), while <code>new URLSearchParams({q: 'a b'}).toString()</code> returns <code>'q=a+b'</code> (space → <code>+</code>). Both are valid for the query string, but the receiving server has to know which to expect — most APIs accept either. <strong>Use <code>URLSearchParams</code> for full query objects</strong> (it handles arrays, repeated keys, and special chars correctly) and <strong>use <code>encodeURIComponent</code> for individual segments</strong> you concatenate by hand. Never use <code>encodeURI</code> on a value — it leaves reserved characters like <code>?</code>, <code>&</code>, <code>=</code> untouched, which corrupts the surrounding URL.</p>
<h3>Decoding a URL with international characters (Cyrillic, CJK, emoji)</h3>
<p>Non-ASCII characters in URLs become long percent-encoded sequences. <code>'москва'</code> encodes to <code>%D0%BC%D0%BE%D1%81%D0%BA%D0%B2%D0%B0</code> (each Cyrillic letter is 2 UTF-8 bytes → 6 hex chars). <code>'東京'</code> encodes to <code>%E6%9D%B1%E4%BA%AC</code> (each CJK char is 3 bytes → 9 hex chars). Emoji are 4 bytes (<code>%F0%9F%8C%8D</code> = 🌍). The decoder above renders all of these back to the original glyphs; <code>decodeURIComponent</code> handles the UTF-8 reassembly automatically. For URL paths that need to look readable, transliterate non-Latin scripts to ASCII first using the <a href="/slug-generator">slug generator</a> rather than letting the encoder turn every char into a 9-byte hex string.</p>
</section>
<section class="article-section">
<h2>Best URL encoder online for 2026 — what to look for</h2>
<p>"URL encoder" is one of the most generic queries in dev tooling — there are hundreds of them, and they don't all behave the same way. The differences that actually matter when you pick one:</p>
<table class="ref-table">
<thead>
<tr><th>Tool</th><th>Mode</th><th>UTF-8 / Unicode</th><th>Both encode & decode</th><th>Logs your input</th></tr>
</thead>
<tbody>
<tr><td><strong>This tool (FreeDevTool)</strong></td><td>Browser-only</td><td><span class="yes">Yes</span> — handles Cyrillic/CJK/emoji</td><td><span class="yes">Yes</span>, with auto-detect</td><td><span class="no">No</span> — no requests on encode/decode</td></tr>
<tr><td><strong>urlencoder.org</strong></td><td>Server-side</td><td>Yes</td><td>Yes</td><td>Server-side processing — input transits to their host</td></tr>
<tr><td><strong>urldecoder.org</strong></td><td>Server-side</td><td>Yes</td><td>Decode only on landing page</td><td>Server-side processing</td></tr>
<tr><td><strong>Postman / Insomnia</strong></td><td>Desktop app</td><td>Yes</td><td>Auto-encodes query params</td><td>Account-bound — workspaces sync to cloud</td></tr>
<tr><td><strong>cURL <code>--data-urlencode</code></strong></td><td>CLI</td><td>Yes</td><td>Encode only</td><td>Local</td></tr>
<tr><td><strong>Browser DevTools console (<code>encodeURIComponent</code>)</strong></td><td>Browser-only</td><td>Yes</td><td>Manual <code>decodeURIComponent</code></td><td>Local</td></tr>
</tbody>
</table>
<p>The single test that separates good encoders from broken ones: paste <code>café</code> and verify the output is <code>caf%C3%A9</code> (UTF-8 bytes, RFC 3986) — <strong>not</strong> <code>caf%E9</code> (Latin-1, the 1990s default that breaks every modern API). If the encoder above your input does not produce <code>%C3%A9</code> for that test, do not use it for anything that touches a 2026 backend.</p>
<h3>How do I URL encode a string online without uploading it?</h3>
<p>Two signals confirm a URL encoder is fully client-side: <strong>(1)</strong> the page works with your network disconnected — try it now: turn off wifi, paste a string, click encode, see the result; <strong>(2)</strong> opening DevTools → Network shows zero requests when you encode or decode. The encoder above passes both. The encoding logic is a few lines of JavaScript wrapping <code>encodeURIComponent</code>, <code>encodeURI</code>, and <code>decodeURIComponent</code> — view-source any time. For sensitive payloads (auth tokens in query params, internal API URLs), prefer a tool like this one over server-side encoders that accept your input as a POST body.</p>
<h3>What's the difference between URL encode, decode, escape, and unescape?</h3>
<p>Four near-synonyms that mean different things in different ecosystems:</p>
<ul>
<li><strong>URL encode (= percent-encode = RFC 3986)</strong> — the standard. Spaces become <code>%20</code>, non-ASCII becomes UTF-8 percent-triplets. JavaScript's <code>encodeURIComponent</code>, Python's <code>urllib.parse.quote</code>.</li>
<li><strong>URL decode</strong> — the inverse of encode. Reads <code>%XX</code> sequences as bytes, reassembles UTF-8 codepoints. JavaScript's <code>decodeURIComponent</code>, Python's <code>urllib.parse.unquote</code>.</li>
<li><strong><code>escape()</code> / <code>unescape()</code></strong> — JavaScript built-ins, deprecated since 1999. They use Latin-1 for codepoints < 256 and a non-standard <code>%uXXXX</code> for higher codepoints. <strong>Don't use them.</strong> They corrupt UTF-8 and produce output no other language can decode.</li>
<li><strong>HTML entity encode</strong> — a different problem. <code>&</code> → <code>&amp;</code>. Applies inside HTML markup, not URLs. Pages mixing the two layers up produce <code>%26amp%3B</code>-style nightmares (URL-encoded HTML entity).</li>
</ul>
<p>The encoder above does the first two. For the fourth, use the <a href="/html-entity">HTML entity encoder</a> — different tool, different layer, never mix them.</p>
<h3>Percent encoding in JavaScript — encodeURIComponent and decodeURIComponent</h3>
<p>Percent encoding in JavaScript is handled by three native functions: <code>encodeURIComponent()</code> for individual values, <code>encodeURI()</code> for full URLs, and <code>decodeURIComponent()</code> for the inverse. The encoder above wraps these directly — paste a value, get the percent-encoded string instantly. <code>encodeURIComponent('hello world&test')</code> returns <code>'hello%20world%26test'</code>; only the unreserved set (<code>A-Z a-z 0-9 - _ . ~</code>) passes through untouched. To percent-encode a URL the way most APIs expect — full RFC 3986 with UTF-8 byte sequences — always reach for <code>encodeURIComponent</code>, never the deprecated <code>escape()</code>.</p>
<h3>HTML percent codes vs URL percent codes — they're not the same thing</h3>
<p>"HTML percent codes" usually means HTML numeric character references (<code>&#37;</code> → <code>%</code>, <code>&#38;</code> → <code>&</code>). "URL percent codes" are RFC 3986 percent-encoding (<code>%25</code> → <code>%</code>, <code>%26</code> → <code>&</code>). The numbers look similar but the syntax and the layer they apply to are different — HTML entities apply inside HTML markup, URL percent codes apply inside URLs. Mixing them produces values like <code>%26amp%3B</code> (URL-encoded HTML entity for ampersand) — a sign you've encoded the same character twice through two different schemes. The encoder above handles only the URL layer; for the HTML side use the <a href="/html-entity">HTML entity encoder</a>.</p>
<h3>urlencode in PHP, Python, and JavaScript — the differences that bite</h3>
<p><code>urlencode</code> is one name for three different operations across languages. In <strong>PHP</strong>, <code>urlencode($str)</code> form-encodes (spaces → <code>+</code>); <code>rawurlencode($str)</code> does RFC 3986 (spaces → <code>%20</code>). In <strong>Python</strong>, <code>urllib.parse.quote(str)</code> is RFC 3986; <code>urllib.parse.quote_plus(str)</code> is form-encoded. In <strong>JavaScript</strong>, <code>encodeURIComponent</code> is RFC 3986; there's no built-in form-encoder — use <code>URLSearchParams</code> for form-style. The encoder above uses RFC 3986 by default with a toggle for form-style — paste a string and switch modes to see the diff.</p>
<h3>Encode URL online with Unicode — the test that catches broken encoders</h3>
<p>Many older "encode URL online" tools still emit Latin-1 or non-standard <code>%uXXXX</code> sequences. Test any encoder with the string <code>café</code> — the correct RFC 3986 output is <code>caf%C3%A9</code> (UTF-8 bytes). If the tool returns <code>caf%E9</code> (Latin-1, the 1990s default) or <code>caf%u00E9</code> (deprecated <code>escape()</code> output), it will silently corrupt every emoji, every CJK character, every Cyrillic name in your data. The encoder above is verified UTF-8 — paste any Unicode and check the round-trip.</p>
<h3>URL encoder alternative to urlencoder.org and meyerweb.com</h3>
<p>The two long-running web URL encoders are urlencoder.org (server-side) and meyerweb.com/eric/tools/dencoder/ (a 2002 Eric Meyer page using a JavaScript prompt-and-replace). Both still work; reasons to prefer this tool in 2026:</p>
<ol>
<li><strong>Modern UTF-8 by default.</strong> Eric Meyer's tool predates broad UTF-8 adoption and uses <code>escape()</code> in places — it produces <code>%uXXXX</code> for non-ASCII, which no current API decodes.</li>
<li><strong>Both directions in one page.</strong> urlencoder.org splits encode and decode into separate pages with separate ads. This page auto-detects which direction your input needs.</li>
<li><strong>No ads, no tracking pixels.</strong> Both alternatives load multiple ad-network and analytics scripts. This page loads only Google Analytics 4 (you can block it) and the Web Crypto API.</li>
<li><strong>Side-by-side breakdown when decoding.</strong> Decoding a URL with mixed query parameters reveals each component as a row, not a single decoded blob — easier to find which parameter has the bug.</li>
</ol>
<p>For workflows that need encoding + structural URL inspection, also try the <a href="/http-request-builder">HTTP request builder</a> (which encodes query params automatically and shows the resulting wire format) and the <a href="/slug-generator">slug generator</a> (when the input is a page title and the output should be a clean URL with no encoding at all).</p>
</section>
<section class="article-section">
<h2>URL encoding and SEO — best practices for 2026</h2>
<p>Google can index URLs with percent-encoded characters, but heavily encoded URLs hurt click-through rate and shareability. The cleanest URLs are the ones that don't need encoding at all.</p>
<ul>
<li><strong>Use hyphens, not spaces, in slugs.</strong> <code>/my-blog-post</code> is far better than <code>/my%20blog%20post</code> — easier to read, no truncation in social previews, no fragility around encoding/decoding.</li>
<li><strong>Lowercase everything.</strong> URLs are technically case-sensitive in the path. <code>/About</code> and <code>/about</code> can be different pages — Google treats them as duplicates, but you fragment your link equity. Pick lowercase site-wide.</li>
<li><strong>Avoid non-ASCII in URL paths.</strong> <code>/résumé</code> works but appears as <code>/r%C3%A9sum%C3%A9</code> in browser address bars and shared links. For international content, use ASCII transliteration (<code>/resume</code>) or punycode for domains.</li>
<li><strong>Keep encoding to query parameters.</strong> Path segments should be predictable, indexable, and short. Save the messy encoding for query strings, where users don't read the URL.</li>
<li><strong>Use our <a href="slug-generator">URL Slug Generator</a></strong> to convert page titles into clean, encoding-free slugs automatically.</li>
</ul>
</section>
</article>
<!-- How to use + mistakes -->
<section class="use-cases">
<h2>How to use the URL encoder</h2>
<p>URL encoding (a.k.a. percent-encoding) escapes characters that have special meaning in URLs — <code>?</code>, <code>&</code>, <code>=</code>, <code>#</code>, spaces, non-ASCII — so they survive transit through routers, caches, and proxies. The tool runs locally and supports both <code>encodeURIComponent</code> (for query values) and <code>encodeURI</code> (for full URLs).</p>
<ul class="use-case-list">
<li><strong>1.</strong> Pick "Encode" or "Decode" mode. Auto-detect picks the right one based on whether the input contains <code>%XX</code> sequences.</li>
<li><strong>2.</strong> Paste text into the input. Multi-line is fine; the encoder handles each line independently.</li>
<li><strong>3.</strong> Choose <code>encodeURIComponent</code> (default — for query string values, single segments) or <code>encodeURI</code> (for whole URLs that already contain <code>?</code>, <code>&</code>, <code>/</code>).</li>
<li><strong>4.</strong> Output appears live with a character-count diff so you can see how much your payload grew (UTF-8 chars become 3 bytes each: <code>%XX%YY%ZZ</code>).</li>
<li><strong>5.</strong> Copy with one click. URL-safe output works in Slack, GitHub, terminals, and HTTP headers.</li>
</ul>
<h3>Common mistakes to avoid</h3>
<ul class="mistakes-list">
<li><strong>Encoding the whole URL with <code>encodeURIComponent</code>.</strong> It encodes <code>/</code>, <code>?</code>, <code>&</code> too, breaking the URL structure. Use <code>encodeURI</code> for full URLs; <code>encodeURIComponent</code> only for individual values.</li>
<li><strong>Double-encoding.</strong> If the upstream system already encoded, applying again turns <code>%20</code> into <code>%2520</code>. Decode once, then re-encode if needed.</li>
<li><strong>Forgetting to encode the <code>+</code> sign in query strings.</strong> Some servers treat raw <code>+</code> as a space. Always encode literal <code>+</code> as <code>%2B</code> in query values.</li>
<li><strong>Confusing URL encoding with HTML entities.</strong> <code>&amp;</code> is HTML; <code>%26</code> is URL. They're not interchangeable; tools that mix them up break inside <code>href</code>.</li>
<li><strong>Trusting <code>decodeURIComponent</code> on user-pasted URLs.</strong> Malformed sequences throw — wrap in try/catch, fall back to displaying raw input.</li>
<li><strong>Encoding paths that contain <code>%</code> already.</strong> If your filename literally has a <code>%</code>, encode it as <code>%25</code> first — otherwise downstream decoders mangle it.</li>
</ul>
</section>
<section class="faq-section">
<h2>Frequently Asked Questions</h2>
<div class="faq-item open">
<div class="faq-q" onclick="toggleFaq(this)">
What is the difference between encodeURI and encodeURIComponent?
<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>
</div>
<div class="faq-a">
<code>encodeURI</code> encodes a full URI but preserves characters that have special meaning in URLs — like <code>: / / ? # [ ] @ ! $ & ' ( ) * + , ; =</code>. <code>encodeURIComponent</code> encodes <em>everything</em> except unreserved characters (letters, digits, <code>- _ . ~</code>), making it the right choice for encoding individual query parameter values. Use <code>encodeURIComponent</code> for values inserted into a URL, and <code>encodeURI</code> for encoding a complete URL string.
</div>
</div>
<div class="faq-item">
<div class="faq-q" onclick="toggleFaq(this)">
Why do URLs need to be encoded?
<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>
</div>
<div class="faq-a">
URLs can only safely contain a limited set of ASCII characters as defined in <a href="https://datatracker.ietf.org/doc/html/rfc3986" style="color:var(--accent)">RFC 3986</a>. Special characters like spaces, <code>&</code>, <code>=</code>, <code>?</code>, <code>#</code>, and non-ASCII characters (Unicode / UTF-8) must be percent-encoded to be safely transmitted. Without encoding, these characters would be misinterpreted as URL delimiters or cause parsing errors in browsers and servers.
</div>
</div>
<div class="faq-item">
<div class="faq-q" onclick="toggleFaq(this)">
How do I encode spaces in a URL — plus sign or %20?
<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>
</div>
<div class="faq-a">
Both are valid but in different contexts. <code>%20</code> is the standard percent-encoding for spaces per RFC 3986 and works everywhere in a URL — path, query, fragment. The plus sign (<code>+</code>) represents a space only in <code>application/x-www-form-urlencoded</code> format, used in HTML form submissions and query strings. For general URL encoding, prefer <code>%20</code>. Use <code>+</code> only when building form-encoded POST bodies.
</div>
</div>
<div class="faq-item">
<div class="faq-q" onclick="toggleFaq(this)">
What is double encoding and how do I avoid it?
<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>
</div>
<div class="faq-a">
Double encoding happens when an already-encoded string is encoded again — for example, <code>%20</code> becomes <code>%2520</code> (the <code>%</code> itself gets encoded). This usually occurs when you pass a pre-encoded URL through an encoding function again. To avoid it: encode raw values <em>before</em> inserting them into the URL, never encode a complete URL that already contains percent-encoded characters, or decode first then re-encode once.
</div>
</div>
<div class="faq-item">
<div class="faq-q" onclick="toggleFaq(this)">
How do I URL encode non-ASCII and Unicode characters?
<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>
</div>
<div class="faq-a">
Non-ASCII characters (like é, ñ, 中文, العربية) are first converted to their UTF-8 byte representation, then each byte is percent-encoded. For example, the character <code>é</code> (U+00E9) becomes <code>%C3%A9</code> in UTF-8. JavaScript's <code>encodeURIComponent</code> handles this automatically. This is the standard defined by RFC 3986 and IRI (RFC 3987).
</div>
</div>
<div class="faq-item">
<div class="faq-q" onclick="toggleFaq(this)">
Does URL encoding affect SEO?
<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>
</div>
<div class="faq-a">
Google can handle URL-encoded characters, but clean, human-readable URLs are preferred for SEO. Excessive percent-encoding makes URLs harder to read, share, and click on in search results. Best practices: use hyphens instead of spaces or underscores, avoid special characters in URL paths, use lowercase, and keep encoding to query parameters where it's actually necessary.
</div>
</div>
<div class="faq-item">
<div class="faq-q" onclick="toggleFaq(this)">
What is the maximum length of a URL?
<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>
</div>