Arabic URLs in production: a safe routing and SEO guide
How to handle Arabic path segments without splitting routes, duplicating content, or letting edge normalization disagree with your application.

Arabic belongs in URLs when it helps Arabic readers understand and trust a link. A path such as /ar/مركز-المساعدة is easier to recognise than a transliterated or opaque alternative. The visible form is only one representation, though. Browsers, crawlers, CDNs, WAFs and application frameworks may handle the same path as Unicode characters, UTF-8 bytes, or percent-encoded triplets.
That is where production bugs start. Two strings can look alike while differing at the code-point level. A slash inside a title can become a route separator. One edge layer can decode a value that the origin expects to remain encoded. Search metadata can then advertise a different URL from the one the server treats as canonical.
This guide stays with path segments. Arabic domains have a separate IDNA path, covered in SultanByte's Arabic domains and internationalized email guide. Locale routing, hreflang and cache partitioning are covered in the bilingual Next.js routing guide.
Cover: original SultanByte editorial artwork.
Start with the standards boundary
The standards do not give applications a universal slug policy. They define syntax and conversion rules. Your product still has to decide which incoming spellings identify the same resource.
Standards requirements
RFC 3986 defines a URI using a limited ASCII repertoire. Percent encoding represents an octet as % plus two hexadecimal digits. Reserved characters such as /, ? and # have structural meaning, so decoding or encoding one can change interpretation. A path itself is a sequence of segments separated by /.
RFC 3987 adds IRIs, which can contain Unicode. Its IRI-to-URI mapping converts eligible non-ASCII characters to UTF-8 bytes, then writes each byte as %HH. The RFC applies NFC when converting from a non-Unicode representation, but explicitly says not to renormalize input that already arrives in UTF-8 or UTF-16. It also requires bidirectional IRIs to be stored and transmitted in logical order, regardless of their visual rendering.
The WHATWG URL Standard defines the parser and serializer used by contemporary browser APIs. Treat that implementation model as the browser boundary, while retaining RFC 3986's component rules when you construct and compare application routes.

Arabic URL path pipeline. Sources: WHATWG URL, RFC 3986, RFC 3987, Unicode UAX #15 revision 57, Google Search, Next.js and Cloudflare URL normalization examples. Credit: SultanByte editorial artwork.
Production recommendations
Choose NFC as your application's canonical form for newly created path segments. Unicode UAX #15 explains that normalization gives canonically equivalent strings a stable binary representation. This is an application identity decision, not permission to rewrite every historical URL in place.
Keep the submitted title, the canonical slug and the resource ID separate. Do not apply NFKC, diacritic stripping, letter substitution or search folding unless your slug contract calls for it. Those broader text choices belong in a field-specific policy; SultanByte's Arabic text normalization guide covers that boundary in detail.
Encode a segment, not a whole path
A slug is data inside one path segment. Encode it before joining it to the route. Do not interpolate an untrusted title into a pathname, and do not run a component encoder over the completed path because that would also encode the separators you intended to keep.
function encodePathSegment(value: string): string {
const nfc = value.normalize("NFC");
return encodeURIComponent(nfc).replace(
/[!'()*]/g,
(char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`,
);
}
export function articlePath(slug: string): string {
return `/ar/articles/${encodePathSegment(slug)}`;
}
JavaScript's encodeURIComponent() encodes UTF-8 and escapes /, ?, #, & and other syntax characters. The small replacement closes the remaining RFC 3986 reserved-character gap. Invalid lone UTF-16 surrogates cause an error, which is preferable to silently creating a replacement slug. Validate slug input before publishing.
Never decode repeatedly. %252F becomes %2F after one pass and / after a second. That second decode can turn data into a segment boundary. Parse once at the framework boundary, validate the resulting segment, and carry a structured value through the application.
Make route identity explicit
A title is editable copy. A slug is a public locator. Neither should be the database primary key.
A durable content model has an immutable article ID, one NFC canonical slug, and an alias table for old slugs. Put a unique constraint on the canonical comparison value. When an editor changes a slug, create the new canonical row and retain the old value as an alias. Requests for an alias should return a permanent redirect to the current canonical URL.
Do the collision check before publishing, in the same transaction that claims the slug. If two submitted strings normalize to the same NFC value, they cannot become two live routes under this policy. Preserve both submitted titles, but require a different slug for one of them.
Also define forbidden values and limits. Reject empty segments, dot segments, control characters, unexpected bidi controls and values that exceed your byte budget after UTF-8 encoding. OWASP's input-validation guidance recommends early syntactic and semantic validation, with allowlists where practical. Validation does not replace contextual output encoding or authorization.
Keep the edge and origin on one interpretation
A request may be evaluated by a CDN cache, WAF, edge function, load balancer and origin router. Record what each layer sees: raw request target, normalized path, decoded segment and cache key.
Cloudflare, for example, can normalize percent-encoded unreserved characters, uppercase percent triplets and remove dot segments. Its optional extended mode also merges repeated slashes and converts backslashes. The normalization settings separately control what edge products inspect and what reaches the origin, while the examples show that those values can differ.
Pick one canonicalization contract and test the deployed chain. WAF rules should inspect the same logical path the application authorizes. Cache keys should not preserve aliases that the origin collapses, unless that separation is intentional. Reject malformed percent escapes and invalid UTF-8 rather than letting components recover differently. Log raw and canonical forms in separate, safely encoded fields so incident responders can see where a change occurred.
A Next.js App Router pattern
Next.js dynamic segments expose the captured segment through params. Normalize for lookup, resolve aliases by resource ID, and generate every outgoing URL with the same builder.
// app/ar/articles/[slug]/page.tsx
import { notFound, permanentRedirect } from "next/navigation";
import { articlePath } from "@/lib/urls";
import { findArticleBySlug } from "@/lib/articles";
export default async function ArticlePage({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
const requested = slug.normalize("NFC");
const article = await findArticleBySlug(requested);
if (!article) notFound();
const canonicalPath = articlePath(article.canonicalSlug);
if (slug !== article.canonicalSlug) {
permanentRedirect(canonicalPath);
}
return <article>{article.body}</article>;
}
Use articlePath() in links, generateMetadata, sitemap generation, Open Graph data and redirect targets. The repository function should look up both canonical slugs and aliases, but return the article's canonical slug. Do not decode params.slug again.
Make SEO signals agree byte for byte
Google's URL structure guidance requires reserved characters to be percent encoded and recommends descriptive words in the audience's language. Arabic words are therefore a valid design choice, provided the route is crawlable and stable.
Choose one serialized public URL, preferably HTTPS with lowercase host, the NFC slug and uppercase percent triplets. Return it in the redirect Location, self-referencing canonical link, internal links, structured data and sitemap. A browser may display the Arabic characters, but your generated machine-facing value should remain consistent.
Google treats redirects and rel="canonical" as strong canonical signals, while sitemap inclusion is weaker, according to its canonicalization guidance. Do not make them argue. Include only the canonical URL in the sitemap. Google's sitemap documentation also requires UTF-8 and fully qualified URLs.
When a slug changes, redirect every known old spelling directly to the new URL. Avoid chains through several historical slugs. Keep the redirect long enough for bookmarks, external links and crawlers to converge.
Display Arabic URLs without changing their identity
Bidirectional rendering changes where characters appear, not their stored order. A mixed URL can place slashes, digits or punctuation where an operator does not expect them. That is a display problem, not a reason to reverse substrings or store visual order.
In HTML, isolate the complete URL from surrounding prose:
<bdi dir="ltr">https://example.com/ar/مركز-المساعدة</bdi>
The W3C's inline bidi guidance identifies URLs and file paths as common mixed-direction cases and recommends tightly wrapped directional markup. For security screens and logs, offer a copyable canonical value and a code-point or percent-encoded view. Keep invisible direction controls out of slugs unless the product has a documented need for them.
Practical QA matrix
Test literal Arabic and its UTF-8 percent-encoded form first. Both should resolve to the same resource and advertise the same canonical URL. Then expand the suite with the failure classes that tend to split infrastructure:
- Send NFC and decomposed variants. The result should follow the documented redirect or rejection policy, never create two records.
- Put
/and%2Finside the candidate slug. The value must remain one encoded segment or be rejected without changing the route boundary. - Send
%252Fand%25D8.... The request must go through exactly one decode, with no bypass or redirect loop. - Try
%,%G0and truncated UTF-8. Require a deterministic 4xx response at a documented layer. - Exercise lowercase percent triplets, dot segments, repeated slashes and backslashes. CDN, WAF, cache and origin must follow the chosen contract.
- Place the URL beside Arabic text, Latin text and numbers. Check isolation, copy and paste, and the logical stored order.
- Request the current slug and every historical alias. Each alias should make one permanent hop to the canonical URL.
- Compare HTML metadata, response headers, structured data and the sitemap. They should carry the same absolute serialized canonical URL.
Run the matrix against the public edge, not only a local server. Repeat GET and HEAD, cold and warm cache requests, and inspect the origin log beside the client-visible result. Arabic URLs are ready when every layer agrees on where segments end, which Unicode string owns the route, and which single URL represents the page.




