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:
Add your domain
Go to the Domains page and register your website's domain.
Configure DNS
Point your translated subdomain(s) to Proxylang's servers.
Verify ownership
Complete the DNS verification process.
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:
Visitor requests a translated URLyourdomain.com/es/page
Proxylang fetches the original page from your server
AI translates all visible text content
HTML structure is preserved exactly.
Translated page is cached and served to the visitor
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.
Open your domain setup
Domains → [your domain] → Setup
Turn on DNS Proxy
Complete DNS verification (your translated subdomain CNAMEs to Proxylang).
Turn on Script Tag
Add the snippet we generate to your origin site.
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:
For JavaScript/TypeScript files, use JS-style comments:
Class-Based Exclusion
Add the proxylang-no-translate class to any element to exclude it and all its children from translation:
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.
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:
For JavaScript/TypeScript files, use the bot-only JS-style fence:
Or add the proxylang-bot-only-no-translate class to any element:
Or use the data-proxylang-bot-only-no-translate attribute:
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.
Legal Documents
Recommended Setup
Mark your legal pages early
Any legal content that gets translated before you add the exclusion marker will count against your word translation quota. We recommend marking legal pages as soon as you set up Proxylang.
Mark the container element of your legal pages (Privacy Policy, Terms of Service, etc.) to reliably prevent them from being translated. You can use any of these methods:
- Add the
proxylang-no-translateclass to the container element - Add the
data-proxylang-no-translateattribute to the container element - Wrap content in
<!-- @proxylang-do-not-translate-start -->and<!-- @proxylang-do-not-translate-end -->HTML comments
Proxylang also includes automatic legal document detection as a safety net. However, due to the wide variety of site structures, frameworks, and rendering methods across the web, automatic detection cannot guarantee perfect results in every case. Adding the class manually ensures your legal content is always protected.
The automatic detection system looks for:
- Page titles containing "Privacy Policy", "Terms of Service", etc.
- Numbered sections ("1.", "Article 3", "Section 2")
- Legal language ("hereby", "pursuant", "liability", "indemnify")
- Document structure (multiple headings, ordered lists, dense text)
Why Legal Docs Are Skipped
Legal Liability Warning
Translating legal documents can create liability issues. Machine translations of contracts, privacy policies, and terms of service may not be legally valid in all jurisdictions.
If you need to translate legal documents, consult with a legal professional and consider using certified human translators.
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
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
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 ChineseSitemap 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.
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-leveldirection: rtlrules 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:
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.
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.
Only tag images that actually contain text. Translating photos, icons, or logos wastes your image translation quota and produces no benefit.
How It Works
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.
Background Processing
The image is sent to a translation API, and the translated version is stored in cloud storage.
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
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.
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"namematchesq,query,search,keyword,term, ors(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
- Visitor types a query in their language.
- 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. - 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. - 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.
- Visitor types a query in their language.
- We debounce input events (~700ms) + skip IME composition events for Korean/Japanese/Chinese.
- After the pause, we reverse-translate and do replace
el.valuewith the translation . We dispatch syntheticinput+changeevents 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"orname="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
fetchwhich 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/subscriptionor 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:
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:
Using a meta tag instead?
If you set your CSP via a <meta> tag in your HTML head, use this format:
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.
| Method | Returns | Description |
|---|---|---|
getCurrentLanguage() | string | Active language code (e.g. "ko-KR" ) |
getBaseLanguage() | string | Source 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 |
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 .
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.
Unsubscribe Pattern
onLanguageChange() returns an unsubscribe function -- call it to stop receiving updates. Useful in component teardown (e.g. React useEffect cleanup, Vue onUnmounted ).