GuidesWIX
Wix CORS errors and external APIs
On Wix, fetch() in page code runs in the visitor's browser with your site's origin, and code in an Embed HTML element ran in an iframe on a separate filesusr.com origin in our October 2026 tests, so both fail against APIs that send no CORS headers. The native fix is a backend web module: wix-fetch runs on Wix's servers, where CORS does not apply and secrets stay out of the page. For code you paste into an embed or Custom Code, prefix public GET requests with https://proxy.cors.dev/ (free, about 600 requests a minute per IP); POST and Authorization need cors.dev Pro at $5 a month for 500,000 requests.
Where your code runs on Wix
Wix runs custom code in four places: page code (Velo frontend code), backend code (web modules), the Embed HTML element, and Custom Code added in the site's Settings. Wix's wix-fetch docs: "In frontend code, the browser's native Fetch API is used. In backend code, the node-fetch module is used." Calling an API from backend code "avoids CORS issues that can occur when sending some requests from the frontend".
Page code runs in the visitor's browser. On two live Wix sites checked on 28 October 2026 with a headless browser, page code ran in a web worker loaded from the site's own domain, so its requests carried the site's origin, such as https://www.wix.com or https://gaweb1.wixsite.com. Custom Code needs a published site with a connected domain and runs in the page itself, with the same origin.
| Place | Runs in | Origin an API sees | CORS applies |
|---|---|---|---|
| Page code | Visitor's browser, in a web worker | Your site, such as https://www.yourdomain.com | Yes |
| Backend web module | Wix servers | None, it is a server request | No |
| Embed HTML element | Sandboxed iframe | A filesusr.com host, such as https://www-wix-com.filesusr.com | Yes |
| Custom Code in Settings | Visitor's browser, in the page | Your connected domain | Yes |
The native fix: a backend web module
If you write Velo page code, move the API call into a backend web module. Wix documents web modules as the way to avoid CORS restrictions and says a request blocked by CORS in frontend code should move to backend code. Backend code is also where a secret key stays private, and it can send POST requests to any API without a proxy.
- Create the module
Add a file ending in
.web.jsto the backend. Wrap each exported function inwebMethod()with a permission such asPermissions.Anyone, both imported fromwix-web-module(in the Wix SDK,@wix/web-methods). - Call the API
getJSON()fromwix-fetchfetches a URL and parses the JSON in one call, on Wix's servers. - Import it in page code
import { getPlayerCount } from 'backend/steam.web'gives page code a function that Wix runs on the server.
// backend/steam.web.js
import { Permissions, webMethod } from 'wix-web-module';
import { getJSON } from 'wix-fetch';
const PLAYERS_URL = 'https://api.steampowered.com/ISteamUserStats/GetNumberOfCurrentPlayers/v1/';
export const getPlayerCount = webMethod(Permissions.Anyone, async (appId) => {
const data = await getJSON(`${PLAYERS_URL}?appid=${encodeURIComponent(appId)}`);
return data.response.player_count;
});Page code then awaits the web method like any async function and writes the result into an element.
// Page code on the page that shows #playerCount
import { getPlayerCount } from 'backend/steam.web';
$w.onReady(async () => {
const players = await getPlayerCount(730);
$w('#playerCount').text = `${players.toLocaleString()} playing now`;
});Keep API keys in the Wix Secrets Manager and read them in backend code with secrets.getSecretValue() from wix-secrets-backend.v2, wrapped in elevate() from wix-auth; it replaces the deprecated getSecret(). Backend code never ships to the browser, so a secret read there stays private. cors.dev cannot do that: anything in page code or an embed is visible to visitors.
Embed HTML runs on a filesusr.com origin
Wix's docs say the HTML element "creates a sandboxed environment (an iframe) that doesn't have direct access to the other elements on your page". Page code and the iframe exchange data through postMessage and the element's onMessage handler.
On 28 October 2026 the Embed HTML iframe on https://www.wix.com/velo-examples/hello-html-comp loaded from https://www-wix-com.filesusr.com, with a sandbox attribute that includes allow-same-origin and allow-scripts. On https://gaweb1.wixsite.com the iframe origin was https://gaweb1-wixsite-com.filesusr.com. On both sites the host was the site's host name with dots replaced by hyphens, followed by .filesusr.com. Requests from code inside the element carry that origin, which an API almost never allows.
The Steam player count API (https://api.steampowered.com/ISteamUserStats/GetNumberOfCurrentPlayers/v1/?appid=730) sends no CORS header. Through https://proxy.cors.dev/ it answered 200 with Access-Control-Allow-Origin echoing https://www-wix-com.filesusr.com, so code pasted into an Embed HTML element can read it.
<p id="players">Loading player count...</p>
<script>
(async () => {
const output = document.getElementById('players');
const target =
'https://api.steampowered.com/ISteamUserStats/GetNumberOfCurrentPlayers/v1/?appid=730';
try {
const response = await fetch('https://proxy.cors.dev/' + target);
if (!response.ok) {
throw new Error(response.headers.get('X-Cors-Error') || 'HTTP ' + response.status);
}
const { response: stats } = await response.json();
output.textContent = stats.player_count.toLocaleString() + ' playing now';
} catch (error) {
output.textContent = 'Player count unavailable: ' + error.message;
}
})();
</script>When the keyless proxy is enough
The free tier needs no signup and no key: put https://proxy.cors.dev/ in front of the full target URL. It fits code in an Embed HTML element or Custom Code that reads public data.
- Methods:
GETandHEADonly;POSTanswers405method_not_allowed. - Rate: About 600 requests per minute per IP and no daily or monthly quota; past that,
429with aRetry-Afterheader that JavaScript can read. - Headers:
Accept,Accept-Language,If-None-Match,If-Modified-SinceandRangepass.Authorization, and names containingtoken,apikey,api-key,api_key,secretorpasswordor ending in-key, answer400header_not_allowed. Other custom headers, including names containingcsrforxsrfsuch asX-CSRF-Token, are dropped and listed inX-Cors-Dropped-Headers. - Size: Responses up to 6 MiB within a 30 second upstream deadline. Cookies are never forwarded.
When the proxy refuses a request, the X-Cors-Error response header names the reason; X-Cors-Source: upstream marks status codes that came from the API.
Origins to register for cors.dev Pro
cors.dev Pro costs $5 a month for 500,000 requests, with a 7-day trial of 1,000 requests and no card. It adds POST, PUT, PATCH and DELETE with bodies up to 1 MiB, plus the Authorization, Content-Type and custom headers, and it can cache a GET for up to 300 seconds when the upstream response allows it; cache hits still count as requests. Throughput is 3,000 requests a minute per account and 100 in flight.
You sign up with Google, create a Connection with up to 10 exact page origins and up to 20 target hosts, and send its publishable key in an X-Cors-Key header. Register the exact origin your code runs on:
- Page code and Custom Code: Your connected domain, for example
https://www.yourdomain.com. - A free Wix address:
https://username.wixsite.com. - Embed HTML: The exact
filesusr.comorigin; loglocation.origininside the embed to read it.
A request from an origin that is not on the Connection answers 403 origin_not_allowed, and Origin: null never matches. For page code, a backend web module remains the better fix.
Good questions.
Why does wix-fetch work in backend code but fail in page code?
wix-fetch uses node-fetch on Wix's servers in backend code and the browser's native Fetch API in page code. Page code runs in a web worker in the visitor's browser, so its requests carry your site's origin and CORS applies. A backend web module makes a server request with no browser origin, so CORS never comes up.
What is filesusr.com and why is it in my CORS error?
In our October 2026 tests, Wix loaded the Embed HTML element in a sandboxed iframe from a filesusr.com host rather than your domain, such as https://gaweb1-wixsite-com.filesusr.com for gaweb1.wixsite.com. Requests from code inside that iframe carry the filesusr.com origin. External APIs almost never allow it, so the browser blocks the response.
Can code in an Embed HTML element read elements on my Wix page?
No. Wix's docs say the HTML element is a sandboxed iframe without direct access to the other elements on your page. Pass data between page code and the iframe with postMessage and the element's onMessage handler.
Where do I keep an API key on Wix?
In the Wix Secrets Manager, read inside a backend web module with secrets.getSecretValue() from wix-secrets-backend.v2. Backend code never ships to the browser, so the key stays private. Never put a secret key in page code, Custom Code or an Embed HTML element, with or without cors.dev, because visitors can read all of it.
Do I need a connected domain for Custom Code?
Yes. Custom Code in your site's Settings needs a published site with a connected domain. The code runs in the visitor's browser on that domain, so its requests carry your connected domain's origin.