Even Hub plugins make HTTP requests the same way any web app does — fetch(), XMLHttpRequest, WebSockets — from inside the WebView that the Even Realities App hosts on the phone. There are two independent gates a request must clear before it reaches the network, and most "works locally, fails on device" bugs come from confusing one for the other.
The two gates
Every outgoing request must pass both of the following checks:
- Even-side permission check — the destination domain must be listed in your
app.jsonnetworkpermissionwhitelist. The Even Realities App enforces this before the request leaves the WebView. Domains not in the whitelist are blocked with no network traffic generated at all. - Browser CORS check — the browser engine in the WebView (Chromium on Android, WKWebView on iOS) enforces standard CORS. The remote server must return the right
Access-Control-Allow-Origin(and related) headers, otherwise the response is dropped before yourfetch()resolves.
:::caution[The whitelist is not a CORS bypass] Adding a domain to app.json does not override CORS. It only tells the Even Realities App that your plugin is allowed to talk to that domain at all. If the remote server doesn't return the right CORS headers, the browser still blocks the response — exactly as it would in any other web page. :::
Declaring the whitelist
In your app.json, request the network permission and list every domain your plugin will hit:
json
"permissions": [
{
"name": "network",
"desc": "Fetches weather data and stores user preferences in the cloud.",
"whitelist": [
"https://api.weather.com",
"https://prefs.example.com"
]
}
]Notes:
- One whitelist entry per origin. Use the full origin (
https://api.example.com) — bare hostnames or wildcards are not supported. - HTTPS is required in production. Plain
http://is only useful for local dev (e.g. when sideloaded against a LAN dev server). - Every domain in the whitelist must actually be used. App review flags unused entries.
- See Packaging & Deployment → Permissions Format for the full schema.
Why APIs that work locally fail on device
A typical bug report:
"My API works in the simulator and from
localhost, but on real glasses the request hangs / errors out."
Three things are usually different on device versus localhost:
| Surface | Local dev (http://localhost:5173) | Production WebView |
|---|---|---|
| Page origin | http://localhost:5173 | An origin the Even Realities App injects when loading your .ehpk |
| CORS enforcement | Often relaxed by dev proxies (e.g. Vite proxy) | Strict — exactly what the browser engine implements |
| Whitelist gate | Bypassed during sideload (no manifest installed) | Enforced — every request is checked against app.json network first |
A request that works locally but fails on device almost always falls into one of these buckets:
- Domain missing from
whitelist. The Even Realities App blocks the request before it leaves the WebView. You'll see no traffic on your server. - Server is missing
Access-Control-Allow-Origin. The request reaches your server (you see logs), the server replies, and the browser then drops the response because the headers are wrong. - Preflight (
OPTIONS) failing. Non-simple requests (anything withContent-Type: application/json, custom headers,PUT/DELETE/etc.) trigger anOPTIONSpreflight. The server must respond200/204withAccess-Control-Allow-MethodsandAccess-Control-Allow-Headersset appropriately. Many production APIs proxyOPTIONSto a 404 by accident. - Mixed content. An HTTPS WebView origin cannot fetch from
http://. Use HTTPS end to end.
Required server-side CORS headers
For a third-party API to be reachable from the WebView, the server must return at minimum:
http
Access-Control-Allow-Origin: *
# or specifically the WebView origin if you can identify itFor requests with custom headers, JSON bodies, or non-GET/POST methods, also handle the preflight:
http
# Response to the OPTIONS preflight
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400If the API is third-party and you can't change its CORS configuration, route the call through a server you control that does set the right headers, then add your server's domain to the app.json whitelist.
Debugging checklist
When a request fails on device, walk through this list in order:
- Confirm the domain is in
app.jsonnetwork.whitelist. Re-pack and re-upload if you changed it. - Open the WebView inspector (Even Realities App → developer menu) and look at the failed request in the Network tab. If it shows
(blocked)with no status code, you've hit the whitelist gate. If it shows a status code but the response body is empty /fetch()rejects, you've hit CORS. - Check the response headers for
Access-Control-Allow-Origin. If it's missing or doesn't match your origin, fix it on the server. - Check the OPTIONS preflight if you're sending JSON or custom headers — it must return 2xx with the right
Allow-Methods/Allow-Headers. - Try the same request from
curlto isolate server problems from WebView problems. Ifcurlworks but the WebView doesn't, it's almost always CORS. - Test on the simulator with the same build. The simulator runs your code in a regular browser context — CORS still applies, but the whitelist gate is not enforced. A request that works in the simulator but fails on device with a "blocked" error means you forgot the whitelist; one that fails in both means it's CORS.