Proxylang Guide

Everything you need to know about using Proxylang to translate your website.

How Server-Side Proxy Works

1. User Visits

User visits /es/about or /es-mx/about

2. Proxy Pre-Translates

Proxylang fetches your page & translates it

3. Proxy Serves Translations

User receives fully translated HTML

Supported URL formats:

  • /es-mx/about -- Full locale code (e.g., es-mx, ko-kr, zh-cn)
  • /es/about -- Language code (e.g., es, ko, zh)
  • /mx/about -- Country code (e.g., mx, kr, jp)

Getting Started

Quick Setup

Four steps to go from zero to a translated site:

1

Add your domain

Go to the Domains page and register your website's domain.

2

Configure DNS

Point your translated subdomain(s) to Proxylang's servers.

3

Verify ownership

Complete the DNS verification process.

4

Select languages

Choose which languages you want to support.

How It Works

Proxylang operates as a reverse proxy that sits between your visitors and your origin server:

1

Visitor requests a translated URLyourdomain.com/es/page

2

Proxylang fetches the original page from your server

3

AI translates all visible text content

HTML structure is preserved exactly.

4

Translated page is cached and served to the visitor

5

SEO elements are automatically injected

Hreflang tags, canonical URLs, and more.

Hybrid Mode

What is Hybrid Mode?

Hybrid mode combines the two integration strategies Proxylang supports so you get the benefits of both at once:

Search engine crawlers

Googlebot, Bingbot, Apple, Perplexity, ChatGPT, Claude and others.

Receive fully server-translated pages via the DNS proxy. Indexable, cacheable translations that look like native localized pages to every crawler.

Real human visitors

See your origin site, translated client-side via the Proxylang script tag.

Your CDN, analytics, personalization, and A/B testing continue to work exactly as they do today — Proxylang is invisible except for the language switcher.

How to enable it

Hybrid mode activates automatically when both integrations are on for the same domain. You don't pick “Hybrid” from a dropdown — you enable Script Tag and DNS Proxy, and Proxylang detects the combination.

1

Open your domain setup

Domains[your domain]Setup

2

Turn on DNS Proxy

Complete DNS verification (your translated subdomain CNAMEs to Proxylang).

3

Turn on Script Tag

Add the snippet we generate to your origin site.

4

Your domain badge flips to Hybrid (SEO)

Once both integrations are active.

No downtime when switching

Disabling either toggle drops the domain back to the single remaining mode. You can switch in and out of Hybrid at any time without downtime.

Bot policy & cost controls

Hybrid mode translates pages for crawlers server-side, which costs AI tokens. Proxylang protects your budget on three fronts:

Beneficial-bot allowlist

Only crawlers that drive customer-visible traffic (real search engines, AI search bots, social link previewers) get translated. Useless bots (SEO scrapers, archive crawlers, uptime monitors) get the original page, zero AI cost.

Allowed: Googlebot family, Bingbot, Applebot, Yandex, Baidu, Naver, GPTBot, ClaudeBot, PerplexityBot, Bytespider, Meta-AI, Amazonbot, Twitterbot, LinkedInBot, Facebook unfurl, Slack/Discord/Telegram link previews, and more.

Per-page token budget

Hard cap on tokens any single bot crawl can spend per page. Title, meta description, Open Graph tags, and the first h1 are always translated and don't count toward this budget.

UI presets: 100 / 500 (default) / 1,000 tokens

Daily bot word cap

Hard ceiling on TOTAL words AI-translated for all bot requests across a UTC day. Once exhausted, bots get the source-language page until midnight UTC. Counter shared across script-tag and hybrid modes.

Default: 5,000 words/day · 0 = block all bot translation

Verified vs unverified bots

Verified search engines (Googlebot, Bingbot, Applebot, DuckDuckBot, Yandexbot — confirmed via reverse-DNS) are uncapped on the per-domain request count. Unverified bots (any other allowlisted bot) share a daily request cap (default 10/day) AND the daily word cap above.

Where to configure

Domains [your domain] SEO & Indexing

When to use Hybrid mode

Choose Hybrid when any of these are true:

You care about SEO in translated languages

Client-side translation adds latency and a JS dependency bots can't afford.

Your origin has heavy personalization, A/B testing, or auth flows

Those would break under a full reverse proxy for real users.

You want AI search engines to cite your translated content

Perplexity, ChatGPT web search, and Google AI Overviews only cite server-rendered translations.

Alternatives

DNS Proxy only

Choose this if you want zero client JavaScript. Bots still get translated (with the same allowlist + caps as Hybrid).

Script Tag only

Lightest integration — widget translates client-side for real users only. Bots are server-side hard-blocked from triggering translation (zero AI cost, zero bot SEO benefit via this mode). Use Hybrid if you need bot SEO indexing.

Translation Control

Skipping Content

Sometimes you need to prevent certain content from being translated. Proxylang provides several methods to exclude content from translation.

HTML Comments

Wrap content in special HTML comments to prevent translation:

HTML

For JavaScript/TypeScript files, use JS-style comments:

JavaScript

Class-Based Exclusion

Add the proxylang-no-translate class to any element to exclude it and all its children from translation:

HTML

Use Cases for Exclusion

  • Brand names and trademarks
  • Code snippets and technical identifiers
  • User-generated content that shouldn't be altered
  • Content already in the target language

Automatic Protection

Proxylang automatically protects code blocks and technical content from translation. You don't need to add any special classes or attributes--it just works.

Automatically Protected

Supported Code Highlighting Libraries

  • Shiki - Used by VitePress, Astro, and this site
  • highlight.js - Popular universal highlighter
  • Prism.js - Lightweight extensible highlighter
  • CodeMirror - Full-featured code editor
  • Monaco Editor - VS Code's editor engine

All semantic HTML code elements ( <code> , <pre> , <kbd> , <var> , <samp> ) and elements with data-language or data-highlighted attributes are automatically excluded from translation.

Bot-Only Do Not Translate

Sometimes you want crawlers and AI bots to index the source-language copy while human visitors still see the translated version. The bot-only family of markers blocks translation for the bot path only. Standard proxylang-no-translate markers (above) block both audiences; bot-only markers block only crawlers.

Works across every Proxylang serving mode — Proxy, Hybrid, and Shopify proxy. Bot traffic is detected by user-agent and routed to a separate translation cache, so bot-only-marked content stays in the source language for crawlers without affecting what humans see on the same page.

When to use bot-only over standard DNT

  • SEO snippets you want indexed in your canonical language
  • Brand copy, taglines, or product names that should appear in source language to crawlers and AI search engines (Google, Perplexity, ChatGPT, Claude) but be localized for real visitors
  • A/B-tested copy where the canonical-language variant is the version search engines should index
  • Pages where you want machine readability in one language while still serving humans a translated experience

Wrap content in a bot-only HTML comment fence:

HTML

For JavaScript/TypeScript files, use the bot-only JS-style fence:

JavaScript

Or add the proxylang-bot-only-no-translate class to any element:

HTML

Or use the data-proxylang-bot-only-no-translate attribute:

HTML

Counts toward your word quota

Because human visitors still translate this content, the wrapped text is included in your billable word count. If you want content excluded from BOTH audiences (and your quota), use the standard proxylang-no-translate markers from the previous section.

SEO Optimization

On-Page SEO Tags

Proxylang automatically injects the following SEO signals on every translated page -- no configuration required:

Hreflang Tags

Alternate links for all enabled languages + x-default

Canonical URLs

Per-language canonical to prevent duplicate content

Content-Language

HTTP header + meta tag for Bing & Baidu

og:locale Tags

Open Graph locale for Facebook & LinkedIn

HTML lang Attribute

Set on the <html> element for accessibility & SEO

HTTP Link Header

Redundant hreflang signal via response headers

Hreflang Output
Canonical & Language Signals

Meta & Social Translation

All SEO-critical meta tags are translated so search engines and social platforms see localized content:

description

Page descriptions shown in search results

og:title & og:description

Facebook & LinkedIn sharing previews

twitter:title & twitter:description

X/Twitter card previews

keywords

Keyword meta tag translated for all languages

Open Graph Locale

Social Sharing

When users share your translated pages on social media, the previews automatically show translated titles and descriptions in the correct language.

Structured Data Translation

Proxylang translates JSON-LD schema.org structured data so your rich results appear in the correct language in search engines.

Content

Article, BlogPosting, NewsArticle, WebPage, WebSite

Commerce

Product, LocalBusiness, Review, SoftwareApplication

Navigation

BreadcrumbList, Organization, FAQPage

Events & Media

Event, Course, JobPosting, VideoObject, Recipe

Smart Translation

Language attributes ( inLanguage , @language ) are automatically updated to the target language. Non-translatable fields like URLs, prices, dates, and identifiers are preserved.

Multilingual Sitemaps

Proxylang generates multilingual XML sitemaps with full hreflang cross-referencing to help search engines discover all language versions of your pages.

Main Sitemap /sitemap.xml

All pages with hreflang annotations for every enabled language

Per-Language Sitemaps /{lang}/sitemap.xml

Language-specific sitemaps with cross-language references

Automatic Discovery

Pages are discovered from your origin sitemap or crawled pages database

URL Structure

example.com/page→ English (default)
example.com/es/page → Spanish
example.com/zh-cn/page → Simplified Chinese
Multilingual Sitemap

Sitemap URL Filtering

Control which pages appear in your multilingual sitemap. This is useful for phased rollouts where you want to start translating a few key pages before expanding to the full site.

Include Mode

Only the paths you list will appear in the multilingual sitemap. Best for phased rollouts — start with a few pages, then expand.

Exclude Mode

All pages are included except those matching your patterns. Useful for hiding large sections like /property/* or /listing/*.

Wildcard Patterns

Use * to match any characters. For example, /blog/* matches /blog/my-post and /blog/2024/recap.

Example: Phased Rollout

Phase 1 — Include mode

/about

/contact

/pricing

Only these 3 pages (+ homepage) appear in the multilingual sitemap.

Phase 2 — Add more paths

/about

/contact

/pricing

/blog/*

/products/*

Blog and product pages are now included. Expand as you're ready.

Phase 3 — All pages

Switch to "Include all pages" to remove the filter entirely.

How to configure

Go to Settings → Sitemap in your dashboard. Choose a filter mode, enter your path patterns (one per line), and save. Changes take effect immediately — the cached sitemap is automatically refreshed.

Good to know

The homepage (/) is always included regardless of filter settings. Filtering applies to the sitemap only — it does not block translation of pages accessed directly.

Search Engine Indexing

When pages are translated, Proxylang notifies search engines for faster indexing:

IndexNow

Instant notification to Bing, Yandex, Naver, Seznam, and Yep. DuckDuckGo, Ecosia, and Qwant also participate through Bing.

Google Sitemap Ping

Google is automatically notified when sitemaps are generated or updated

Auto-Generated robots.txt

Includes multilingual sitemap directives so crawlers discover all language versions

Optional Integrations

Connect Google Search Console for direct sitemap submission, or add a Bing Webmaster API key for direct URL submission. Configure these in your SEO settings.

AI & Bot Optimization

Proxylang supports Generative Engine Optimization (GEO) to ensure AI search engines can access and cite your multilingual content.

AI Crawler Access

robots.txt automatically allows GPTBot, ChatGPT-User, ClaudeBot, PerplexityBot, Google-Extended, and other AI crawlers

llms.txt /llms.txt

AI-friendly site description listing all available languages and sitemaps for LLM crawlers

Bot translation policy by integration mode

  • DNS Proxy / Hybrid: Beneficial bots (search engines + AI search + social previewers) get full server-side translation. Useless bots (SEO scrapers, archive crawls, uptime monitors) get the source page untranslated — zero AI cost.
  • Script Tag only: Bots never see translated content — they always get the original page. This is intentional: search engines work best when each page has a single, consistent version. If you want search engines to index your translated pages, switch to Hybrid mode.
robots.txt (auto-generated)
llms.txt (auto-generated)

Force URL Language Prefix

By default, Proxylang uses clean URLs for human visitors on single-page apps (SPAs) and stores the selected language in a cookie. With Force URL Language Prefix enabled, every visitor always sees the language code in the URL path (e.g., /en-us/about), regardless of how they arrived at the page.

Consistent URLs for SEO

Search engines always index the prefixed version of each page, ensuring consistent crawling and ranking signals

Paid Advertising

Ad landing pages keep the language prefix, so analytics and attribution track the correct language version

Language Switcher

When a visitor changes language via the widget, they navigate to the prefixed URL (e.g., /zh-cn/about) instead of a clean URL with a cookie

How to enable

Go to Settings → Advanced in your dashboard. Each domain has its own toggle — enable it for any domain that needs guaranteed prefix URLs.

Default behavior (prefix off)

example.com/about→ English (cookie-based)
example.com/es/about→ Spanish (bots only)

With prefix forced on

example.com/en-us/about→ English (all visitors)
example.com/es/about→ Spanish (all visitors)

Direction (RTL / LTR) Support

Automatic Direction Handling

Proxylang automatically handles direction changes in both directions:

  • LTR → RTL : LTR site (English, Spanish, etc.) translating to Arabic, Hebrew, Persian, or Urdu — Proxylang sets dir="rtl" and injects CSS fixes for sliders, progress bars, tickers, and carousels.
  • RTL → LTR : RTL-source site (Arabic, Hebrew, Persian, Urdu) translating to English or another LTR language — Proxylang sets dir="ltr" and injects a CSS reset that overrides author-level direction: rtl rules on <body> so the layout actually flips back.

Same-direction translations (LTR → LTR, RTL → RTL) leave the dir attribute untouched.

Sets dir="rtl" or dir="ltr"

Bidirectional — based on source vs target language

Fixes Animations

Progress bars, tickers, and carousels work correctly

Preserves Layout

Sliders and scroll containers maintain correct direction

CSS Variables

--pl-transform-origin-start/end for custom use

Script-tag mode: brief flash on cold loads

In script-tag mode (and the real-user path of hybrid mode), the page paints in its original direction first and snaps to the target direction once our script loads — applies to both LTR → RTL and RTL → LTR flips. Expect a brief flash and possible layout shift, especially on slow connections. Proxy and Shopify proxy modes flip server-side and have no flash. You can disable auto-flip per-domain (covers both directions) in /customize → Advanced.

Flipping Elements

Some elements like arrows, directional icons, or asymmetric graphics should be mirrored when displayed in RTL languages. Use the proxylang-flip-on-rtl class:

HTML

Common Use Cases

  • Directional arrows pointing left/right
  • Navigation icons (back, forward, etc.)
  • Asymmetric decorative elements
  • Progress indicators with direction

Animation Fixes (LTR → RTL)

When flipping an LTR site to an RTL target, Proxylang automatically applies CSS fixes for common animation and layout issues. The following elements are handled:

Progress Bars

Transform origin reversed so bars fill from right to left

Tickers & Marquees

Scroll containers maintain LTR direction while content stays RTL

Carousels & Sliders

Navigation direction preserved for smooth scrolling

NProgress Loading Bars

Top loading indicators animate correctly from left to right

Direction Reset (RTL → LTR)

When flipping an RTL-source site to an LTR target, setting dir="ltr" alone is not enough — author CSS that pins direction at the <body> level (e.g. body { direction: rtl } ) would otherwise keep the layout RTL. Proxylang injects a small CSS reset that forces direction: ltr under html[dir="ltr"] on <html> , <body> , and direct body children, so the layout reflows left-to-right as expected. No animation fixes are needed in this direction — components authored for an RTL site already have an LTR fallback in the browser's default behavior.

Opt-Out per Element

If Proxylang's automatic direction CSS interferes with your custom animations or layout, add the data-pl-no-rtl-fix attribute to any element to exclude it from both the LTR → RTL animation fixes and the RTL → LTR direction reset.

Image Translation

Proxylang can translate text embedded in images — banners, infographics, diagrams, and more. This is an opt-in feature that works alongside regular text translation and is sold as prepaid translation packs separate from subscription tiers.

Pricing

Prepaid packs. Per-image cost scales down with pack size.

10 images
$5 / ₩7,000
$0.50 / ₩700 per image
50 images
$20 / ₩28,000
$0.40 / ₩560 per image
100 images
$35 / ₩49,000
$0.35 / ₩490 per image

Packages valid for 12 months from purchase.

See full pricing →

Image Translations are consumed per image, per target language.

Translating one image to Korean uses 1 image translation . Translating the same image to Japanese uses another image translation . This is because each language requires a distinct translated copy of the image.

Each language version caches permanently after its first translation, so repeat visits by viewers in that language are free. Visitors in your site's source language never consume image translations.

Works in all integration modes — script-tag, hybrid, and proxy. In script-tag mode the widget scans tagged images client-side; in proxy and hybrid modes the worker also pre-rewrites them server-side, and hybrid delivers translated images to bots and humans alike once cached.

See before/after examples

Four real images translated through the full pipeline.

View examples →

Setup

1. Enable per domain

Go to Settings and toggle Translate Images on for each domain where you want image translation.

2. Tag your images

Add the data-pl-translate-image attribute to any <img> tag that contains text you want translated.

HTML

Only tag images that actually contain text. Translating photos, icons, or logos wastes your image translation quota and produces no benefit.

How It Works

1

First Visit

Tagged images are detected and queued for translation. The original image is served while translation happens in the background, then swapped in automatically once ready — no page refresh required.

2

Background Processing

The image is sent to a translation API, and the translated version is stored in cloud storage.

3

Subsequent Visits

The translated image is served automatically. The src is rewritten to point to the cached translation.

Translation takes roughly 45 seconds to 1 minute per language and runs in a background queue. The original image is served while processing, then the translated version replaces it in-place automatically as soon as it's ready — visitors don't need to refresh the page. Subsequent visits in that language receive the cached translation instantly. Each language is processed independently and consumes one quota.

Best Practices

HTML

Good candidates

  • Marketing banners with text overlays
  • Infographics and charts with labels
  • Product comparison images
  • Screenshots with UI text
  • Diagrams with annotations

Skip these

  • Photos without embedded text
  • Icons and logos
  • SVG graphics (use text translation instead)
  • Animated GIFs
  • Decorative images

Supported formats: PNG, JPG/JPEG, and WebP. Maximum file size is 5 MB. SVG and GIF files are automatically skipped.

Supported target languages: Image translation is available for the 33 languages below. Tagged images on a page in any other language fall back to the original untranslated image — text translation still works for all Proxylang-supported languages.

ArabicBengaliChinese (Simplified)CzechDanishDutchEnglishFilipinoFinnishFrenchGermanGreekHebrewHindiHungarianIndonesianItalianJapaneseKoreanMalayNorwegianPersianPolishPortugueseRomanianRussianSpanishSwedishThaiTurkishUkrainianUrduVietnamese

Search Translation

When visitors view your site in another language and type a search query in their own language, Proxylang reverse-translates the query to your site's source language before it reaches your search backend — so 엑스복스 still finds xbox . Results come back in your source language and the normal forward translation renders them in the visitor's display language, so the round-trip is invisible.

Pricing

10,000 searches
$9.99 / ₩13,900
50,000 searches
$39.99 / ₩55,900
200,000 searches
$139.99 / ₩194,000

Packages valid for 12 months from purchase.

Buy Package →

Each search request consumes 1 quota — cache hits included.

Every unique translated query is cached for 30 days per domain. Repeat searches return instantly (no AI call) but still consume 1 quota. You pay for the feature, not for cold AI calls — cached responses are our infrastructure cost, not yours to track.

Searches where the visitor is already viewing your source language consume 0 quota — we detect identity and short-circuit.

Works in all integration modes — script-tag, hybrid, and proxy. Installs from your existing Proxylang client script; no extra snippet to add.

Setup

1. Purchase Pack

Visit Billing to buy a pack. Quota stacks; each pack is valid for 12 months from purchase.

2. Enable per domain

Open the domain you want to cover. Under Advanced settings, flip Translate Search Queries on. The toggle is disabled until you have search quota available.

3. That's it — for most sites

Standard search forms and API calls are intercepted automatically. See How It Works for what qualifies as "standard", and Client-Side Filters for the one case that needs a one-line HTML change.

How It Works

Proxylang's client script watches four entry points to your search backend:

1 Native form submits

Any <form> containing a search-like input. GET forms : we translate, then navigate directly to the action URL with translated values — visible input never modified. POST forms : we swap input values + resubmit.

2 fetch() / XHR

Outbound requests with ?q= , ?query= , ?search= params, or JSON bodies with the same keys. GraphQL payloads are skipped.

3 URL navigation

Direct links and SPA router pushes to /search?q=… URLs. Query param is rewritten before the router re-fetches.

4 Opt-in client filters

Inputs tagged with data-proxylang-reverse-search . For sites whose search never makes a network call. See below.

Automatic input detection

An input is treated as a search input when it is a <input> (text/search type) or <textarea> and matches one of:

  • type="search"
  • role="search"
  • name matches q , query , search , keyword , term , or s (case-insensitive)

Hidden, password, email, checkbox, and other non-text input types are always skipped — CSRF tokens and other payloads won't be accidentally translated.

<!-- Network-based search: already works automatically
     when the input uses a recognized name/type. -->
<form action="/search" method="GET">
  <input type="search" name="q" />
  <button type="submit">Search</button>
</form>

<!-- Or via JS fetch / XHR — we auto-intercept outbound requests
     with query params like ?q= / ?query= / ?keyword=. -->

Translation blocks the submit/request briefly. Cold AI call: ~300–800ms (Gemini 2.5 Flash Lite). Cache hit: ~30ms . Hard 2-second timeout — if the AI takes too long we pass the original value through, so visitors never see indefinite loading.

Client-Side Filters (edge case)

Some sites implement search entirely in the browser — typing filters an already-loaded list, no network request is ever made. Our automatic interception has nothing to hook into, so these inputs need a single attribute to opt in:

<!-- Client-side filter (no search API): add the attribute -->
<!-- Default: translates only when the user presses Enter.
     Mirrors Weglot's approach. 1 translation per search, minimal cost. -->
<input
  type="text"
  placeholder="Search guide..."
  data-proxylang-reverse-search
/>

<!-- Optional "live" mode: translate debounced as the user types.
     More quota consumed (one per pause > 700ms). Use when your filter
     needs continuous feedback without requiring Enter. -->
<input
  type="text"
  placeholder="Search..."
  data-proxylang-reverse-search="live"
/>

Default mode (Enter-only) — recommended for fetch / form search

  1. Visitor types a query in their language.
  2. Visitor presses Enter . We reverse-translate once and pre-warm the per-page cache. Visible input is NOT modified — your typed text stays in the box.
  3. Your existing fetch / form submit fires next (browser default on Enter, or your own onClick / onSubmit handler). Our fetch/form interceptor catches the outbound request, reads the cached translation, and rewrites the ?q= param or form values before the request leaves the browser.
  4. Customer search API receives the source-lang query → returns real results → existing forward translation renders them in the visitor's display language.

Matches Weglot's "translate at submit" UX — cheap (1 quota per search), no input flip, visitor's typed text stays visible until navigation.

Live mode — opt in with ="live"

Use this mode when your search filters an in-memory list locally (no network call) and your filter code reads the input element's value directly — e.g. Vue v-model , React controlled inputs, or vanilla onChange filtering an array.

  1. Visitor types a query in their language.
  2. We debounce input events (~700ms) + skip IME composition events for Korean/Japanese/Chinese.
  3. After the pause, we reverse-translate and do replace el.value with the translation . We dispatch synthetic input + change events so your filter code re-runs with the translated value. Matches appear.

Trade-off: visible input flips from typed language to source after the pause. Required for client-side filters since your code reads the input value directly. If your search hits a network endpoint instead, use default mode — no flip, same result.

Domain context hint — data-proxylang-search-context

Named entities (Pokémon, anime, K-pop, films, place names) have official translations that aren't phonetic. Korean 리자몽 isn't "Lijamong", it's "Charizard". Set a per-input hint so the AI picks the canonical target-lang name.

<input
  type="search"
  name="q"
  data-proxylang-reverse-search
  data-proxylang-search-context="Pokémon characters and species"
/>

The hint is passed to the AI as additional system context for that input's translations. Keep it short (under ~240 chars) and specific to the expected query domain. Falls back to your domain's Site Description (Brand & Context tab) when not set.

Best Practices

  • Use type="search" or name="q" when possible. These are detected automatically without any opt-in attribute.
  • Keep search inputs in a proper <form> . Form submit is the most reliable interception point. SPA frameworks can still dispatch fetch/XHR from inside a form.
  • Monitor your quota balance. The feature auto-disables when quota hits zero — visitors' queries pass through untranslated, which silently breaks non-English search. Set a low-balance alert.
  • Don't add the opt-in attribute to network-based inputs. Doubles the work — we'd rewrite the value on keystroke AND on submit/fetch. Attribute is only for pure client-side filters.
  • Autocomplete-on-keystroke search will burn quota fast. Every unique typed prefix is a separate translation. If your site fires a search request on every character, consider debouncing server-side before the query hits Proxylang, or scope the feature to only the submit action.

Known Limits

  • Programmatic form.submit() calls from JavaScript do not fire a submit event per the HTML spec — these bypass our interceptor. User-initiated submits (Enter key, button click) work normally.
  • XHR searches with query parameters in the URL are not rewritten (only the body is). Most modern SPAs use fetch which is covered.
  • JSON request bodies are scanned at the top level only. Nested shapes like {"filter": {"q": "..."}} are not detected.
  • GraphQL payloads (values starting with query / mutation / subscription or containing braces) are deliberately skipped to avoid mangling the operation string.
  • Quota balance propagation takes up to 60 seconds between the dashboard and the edge worker.

Content Security Policy

Overview

If your site uses a Content Security Policy (CSP) header, it may block Proxylang's translation scripts from running. When this happens, translations silently fail to load — your visitors see the original language with no error message.

How to tell if CSP is blocking Proxylang

Open your browser's Developer Tools (F12) and check the Console tab. If you see errors like "Refused to execute inline script because it violates the following Content Security Policy..." then your CSP needs updating.

Proxy Mode

In proxy mode, translations are injected server-side before reaching the browser. Most CSP configurations work without changes.

If you have a very strict CSP that blocks all inline scripts, you'll need to allow inline execution for the pre-hydration and post-hydration scripts that preserve translations during page load:

HTTP Header

Script Tag Mode

In script tag mode, Proxylang loads a client-side script from cdn.proxylang.dev. You need to allow this domain in your CSP:

HTTP Header

Using a meta tag instead?

If you set your CSP via a <meta> tag in your HTML head, use this format:

HTML Meta Tag

Widget Events

The window.Proxylang API lets you programmatically detect the active language, react to changes, and build custom integrations. It works in both proxy mode and script-tag mode.

JavaScript API

All methods are available on window.Proxylang as soon as the widget loads.

MethodReturnsDescription
getCurrentLanguage()string Active language code (e.g. "ko-KR" )
getBaseLanguage()stringSource language of the site
getLanguages()Array All enabled languages with code , english , native , isBase
setLanguage(code)void Switch to a different language (triggers page navigation)
isReady()boolean Whether the widget has finished initializing
onReady(fn)void Callback when widget is ready (fires immediately if already ready)
onLanguageChange(fn)() => void Callback on language switch; returns an unsubscribe function
JavaScript

Ready Event

Use onReady() or listen for the proxylang:ready DOM event to run code after the widget initializes. The event's detail contains language and baseLanguage .

JavaScript

The DOM event works with any framework -- React, Vue, Angular, Svelte, or plain JavaScript. No need to wait for window.Proxylang to exist before adding the listener.

Language Change Event

Use onLanguageChange() or listen for proxylang:languagechange to react when the user switches language. Useful for analytics tracking, conditional UI, or syncing with other systems.

JavaScript

Unsubscribe Pattern

onLanguageChange() returns an unsubscribe function -- call it to stop receiving updates. Useful in component teardown (e.g. React useEffect cleanup, Vue onUnmounted ).

React