Proxy and CORS configuration
EDOT Browser exports telemetry from the user's browser to an OTLP endpoint. You must put a reverse proxy in front of your OTLP endpoint and configure it for authentication and Cross-Origin Resource Sharing (CORS).
Do not send telemetry directly from the browser to Elastic Observability with an API key in client-side code. Any credentials in browser code are visible to end users and can be misused. EDOT Browser requires a reverse proxy in front of the OTLP endpoint for these reasons:
- Authentication: The EDOT Collector or Elastic Cloud Managed OTLP endpoint expects an
Authorizationheader with an API key. The reverse proxy injects the header so the key stays on the server and is not exposed to the browser. - Cross-origin requests: Your web application and the OTLP endpoint often have different origins. Browsers enforce CORS, so without the right headers, export requests are blocked. A reverse proxy on the same origin as your app (or configured to allow it) can add the required CORS headers and handle preflight
OPTIONSrequests. - Traffic control: You can apply rate limiting or other controls at the proxy before traffic reaches the Collector or Elastic Observability.
For complete examples and security considerations, refer to OpenTelemetry for Real User Monitoring (RUM).
If your site uses a Content Security Policy (CSP), add the domain of your reverse proxy or OTLP endpoint to the connect-src directive so the browser allows export requests. For example: connect-src 'self' https://telemetry.example.com.
When your web application and the export endpoint have different origins, the browser might block requests unless CORS is configured. Your reverse proxy must:
- Return
Access-Control-Allow-Originmatching your application origin - Respond to
OPTIONSpreflight requests with 204 - Include
AuthorizationinAccess-Control-Allow-Headerswhen using API key authentication
The following example forwards telemetry from webapp.example.com to an EDOT Collector at collector.example.com, injects the required Authorization header, and handles CORS preflight:
server {
# Configuration for HTTP/HTTPS goes here
location / {
# Take care of preflight requests
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Access-Control-Allow-Origin' 'webapp.example.com' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Accept-Language,Authorization,Content-Language,Content-Type' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
add_header 'Access-Control-Allow-Origin' 'webapp.example.com' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Accept-Language,Authorization,Content-Language,Content-Type' always;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Set the auth header for the Collector here. Follow security best practices
# for adding secrets (for example Docker secrets, Kubernetes Secrets).
proxy_set_header Authorization 'ApiKey ...your Elastic API key...';
proxy_pass https://collector.example.com:4318;
}
}
- Install the agent and initialize EDOT Browser in your application.
- Refer to Configure EDOT Browser for initialization options.