﻿---
title: Proxy and CORS configuration
description: Configure a reverse proxy and CORS for EDOT Browser telemetry export.
url: https://www.elastic.co/elastic/docs-builder/docs/2970/reference/opentelemetry/edot-sdks/browser/proxy-cors
products:
  - Elastic Cloud Serverless
  - Elastic Distribution of OpenTelemetry Browser (RUM)
  - Elastic Distribution of OpenTelemetry SDK
  - Elastic Observability
applies_to:
  - Serverless Observability projects: Generally available
  - Elastic Stack: Generally available
  - Elastic Distribution of OpenTelemetry Browser (RUM): Preview
---

# Proxy and CORS configuration
EDOT Browser exports telemetry from the user's browser to an OTLP endpoint. You can send data directly to an OTLP endpoint if you set the appropriate headers (for example `Authorization`). For security, Elastic recommends placing a reverse proxy in front of your OTLP endpoint and configuring it for authentication and [Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS) so that credentials are not exposed in the browser.
<warning>
  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.
</warning>


## Why a reverse proxy is recommended

A reverse proxy in front of the OTLP endpoint is recommended for these reasons:
- Authentication: The EDOT Collector or Elastic Cloud Managed OTLP endpoint expects an `Authorization` header 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 `OPTIONS` requests.
- 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)](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/2970/solutions/observability/applications/otel-rum).

## Content Security Policy (CSP)

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`.

## CORS requirements

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-Origin` matching your application origin
- Respond to `OPTIONS` preflight requests with 204
- Include `Authorization` in `Access-Control-Allow-Headers` when using API key authentication


## Example: NGINX reverse proxy

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:
```nginx
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' 'https://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 'Access-Control-Allow-Methods' 'POST, OPTIONS' 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;
    }
}
```


## Next steps

- [Install the agent](https://www.elastic.co/elastic/docs-builder/docs/2970/reference/opentelemetry/edot-sdks/browser/install-agent) and initialize EDOT Browser in your application.
- Refer to [Configure EDOT Browser](https://www.elastic.co/elastic/docs-builder/docs/2970/reference/opentelemetry/edot-sdks/browser/configuration) for initialization options.