﻿---
title: Elasticsearch OTLP/HTTP endpoint
description: The Elasticsearch /_otlp APIs accept OTLP data from a gateway collector. On Elastic Cloud, send OTLP data to the Managed OTLP Endpoint. /_otlp does not enrich traces or produce APM metrics.
url: https://www.elastic.co/elastic/docs-builder/docs/4302/manage-data/ingest/otlp-endpoint
products:
  - Elastic Documentation
  - Elasticsearch
applies_to:
  - Elastic Cloud on Kubernetes: Generally available
  - Elastic Cloud Enterprise: Generally available
  - Self-managed Elastic deployments: Generally available since 9.2
---

# Elasticsearch OTLP/HTTP endpoint
The Elasticsearch OTLP/HTTP endpoint is a native ingest API, like the [bulk API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-bulk).
It accepts [OpenTelemetry Protocol (OTLP)](https://opentelemetry.io/docs/specs/otlp) requests on the same host and port as the other Elasticsearch APIs, under the `/_otlp` path, and writes the records to data streams as they are received.
The endpoint does not run the [`elasticapm` processor](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4302/reference/edot-collector/components/elasticapmprocessor) or [`elasticapm` connector](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4302/reference/edot-collector/components/elasticapmconnector): traces are not enriched, no aggregated APM metrics are produced, and APM views that depend on them, such as the service inventory and service map, stay empty.
The intended client for this endpoint is a gateway Collector, not an application. How you send OpenTelemetry data to Elasticsearch depends on your deployment type:
- On Elastic Cloud Hosted and Elastic Cloud Serverless, use the [Elastic Cloud Managed OTLP Endpoint](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4302/reference/opentelemetry/managed-inputs/managed-otlp-endpoint) rather than `/_otlp`. The Elastic Cloud Managed OTLP Endpoint is a separate ingestion host, and it enriches traces and produces aggregated APM metrics.
- On self-managed, Elastic Cloud Enterprise, and Elastic Cloud on Kubernetes deployments, send application data to an [Elastic Agent in Gateway mode](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4302/reference/edot-collector/config/default-config-standalone#gateway-mode). The gateway runs the `elasticapm` processor and connector, then writes the enriched result to Elasticsearch, either to `/_otlp` or through the [Elasticsearch exporter](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4302/reference/edot-collector/components/elasticsearchexporter).

The Elasticsearch OTLP/HTTP endpoint exposes three signal-specific paths:

| Signal  | Path                | Availability                                                          |
|---------|---------------------|-----------------------------------------------------------------------|
| Metrics | `/_otlp/v1/metrics` | <applies-to>Elastic Stack: Generally available since 9.2</applies-to> |
| Logs    | `/_otlp/v1/logs`    | <applies-to>Elastic Stack: Preview since 9.5</applies-to>             |
| Traces  | `/_otlp/v1/traces`  | <applies-to>Elastic Stack: Preview since 9.5</applies-to>             |

`/_otlp/v1/traces` stores spans as they are received: it does not run the `elasticapm` processor or connector, so traces ingested through it are not enriched and produce no aggregated APM metrics.
<important>
  Elasticsearch only supports [OTLP/HTTP](https://opentelemetry.io/docs/specs/otlp/#otlphttp), not [OTLP/gRPC](https://opentelemetry.io/docs/specs/otlp/#otlpgrpc).
</important>


## When to use the Elasticsearch OTLP endpoint

For most users, one of the following higher-level ingestion paths is recommended:

| Deployment                                                              | Recommended ingestion path                                                                                                                                                                                                                                      |
|-------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Elastic Cloud Hosted and Serverless                                     | [Elastic Cloud Managed OTLP Endpoint](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4302/reference/opentelemetry/managed-inputs/managed-otlp-endpoint)                                                                                          |
| Elastic Cloud Enterprise, Elastic Cloud on Kubernetes, and self-managed | [Elastic Agent in Gateway mode](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4302/reference/edot-collector/config/default-config-standalone#gateway-mode), which runs the `elasticapm` processor and connector before writing to Elasticsearch |

Use Elastic Cloud Managed OTLP Endpoint if it's available in your deployment, even when an application can target the Elasticsearch OTLP endpoint directly.
For an overview of the recommended OpenTelemetry-based ingestion architecture, refer to the [Elastic OpenTelemetry reference architecture](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4302/reference/opentelemetry/architecture).
Use the Elasticsearch OTLP endpoint directly only in the following cases:
- You operate a self-managed OpenTelemetry Collector gateway that runs the `elasticapm` processor and connector, and you prefer the `OTLP/HTTP` exporter over the [Elasticsearch exporter](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4302/reference/edot-collector/components/elasticsearchexporter) to send data from the gateway to Elasticsearch.
  The Elasticsearch exporter writes through the [bulk API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-bulk) and the `OTLP/HTTP` exporter writes to `/_otlp`. Run the `elasticapm` processor and connector in the gateway pipeline before whichever exporter you choose.
- You build a development-only setup in which an application SDK sends OTLP data straight to the cluster.
  Traces sent this way are stored without `elasticapm` enrichment or aggregated APM metrics, so the APM views that depend on them stay empty.

<warning>
  Don't send telemetry from applications or pods directly to `/_otlp`.
  As with the [bulk API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-bulk), each client opens its own connections to Elasticsearch and sends its own small batches.
  Many direct clients mean many connections and many small requests, which Elasticsearch handles less efficiently than a few connections carrying larger batches.Send telemetry to a gateway Collector or to the Elastic Cloud Managed OTLP Endpoint instead.
  A gateway Collector combines data from many clients into larger batches and writes them to `/_otlp` over a small number of connections.
  This limit is about the number of connections to Elasticsearch, not the number of applications you monitor.
</warning>


## Advantages of OTLP ingest over Bulk API

Compared to the [bulk API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-bulk), ingesting through OTLP offers:
- Improved ingestion performance, especially for payloads with many resource attributes.
- Simplified mapping: data streams, index templates, dimensions, and metrics are derived dynamically from OTLP metadata.
  There's no need to set them up manually.


## How to send data to the Elasticsearch OTLP endpoint


### Create an API key

Authenticate to the Elasticsearch OTLP endpoint with an API key.
On Elastic Cloud Hosted and Serverless, send OTLP data to the Elastic Cloud Managed OTLP Endpoint instead of to `/_otlp`, and authenticate with an API key as described in [Elastic Cloud Managed OTLP Endpoint authentication](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4302/reference/opentelemetry/managed-inputs/managed-otlp-endpoint#authentication).
On self-managed, Elastic Cloud Enterprise, and Elastic Cloud on Kubernetes deployments, refer to the API key documentation for your deployment type for instructions on how to create one:
- [Elasticsearch API keys](https://www.elastic.co/elastic/docs-builder/docs/4302/deploy-manage/api-keys/elasticsearch-api-keys) (self-managed, Elastic Cloud on Kubernetes)
- [Elastic Cloud Enterprise API keys](https://www.elastic.co/elastic/docs-builder/docs/4302/deploy-manage/api-keys/elastic-cloud-enterprise-api-keys)

The API key needs `create_doc` and `auto_configure` privileges on the data stream patterns it writes to.
`create_doc` allows writing documents without overwriting existing ones.
`auto_configure` allows the endpoint to create the target data streams on first write.
The minimum index patterns depend on which signals you ingest:

| Signals ingested | Required `names` patterns         |
|------------------|-----------------------------------|
| Metrics          | `metrics-*`                       |
| Logs             | `logs-*`                          |
| Traces           | `traces-*`, `logs-*`              |
| All three        | `metrics-*`, `logs-*`, `traces-*` |

Traces ingestion also writes span events to `logs-*` data streams, so it requires both patterns.
For example, an API key role descriptor that allows ingesting all three signals:
```json
{
  "indices": [
    {
      "names": ["logs-*", "metrics-*", "traces-*"],
      "privileges": ["create_doc", "auto_configure"]
    }
  ]
}
```


### Configure an OpenTelemetry Collector

To send data from an OpenTelemetry Collector to an Elasticsearch OTLP endpoint, configure the [`OTLP/HTTP` exporter](https://github.com/open-telemetry/opentelemetry-collector/tree/main/exporter/otlphttpexporter):
```yaml
exporters:
  otlphttp/elasticsearch:
    endpoint: <es_endpoint>/_otlp
    headers:
      Authorization: "ApiKey <api_key>"
    sending_queue:
      enabled: true
      sizer: bytes 
      queue_size: 50_000_000 
      block_on_overflow: true
      batch: 
        flush_timeout: 1s
        min_size: 1_000_000
        max_size: 4_000_000
service:
  pipelines:
    logs:
      exporters: [otlphttp/elasticsearch]
      receivers: ...
    traces:
      exporters: [otlphttp/elasticsearch]
      receivers: ...
    metrics:
      exporters: [otlphttp/elasticsearch]
      receivers: ...
```

The exporter appends the signal-specific path (`/v1/logs`, `/v1/traces`, `/v1/metrics`) to the configured `endpoint`.
To ingest enriched traces and aggregated APM metrics, run the `elasticapm` processor and connector in the pipeline before this exporter, as [Elastic Agent in Gateway mode](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4302/reference/edot-collector/config/default-config-standalone#gateway-mode) does.
These values are starting points for a gateway Collector.
Tune them for your workload and Collector resources.
They are local to each Collector instance and don't increase Elasticsearch ingest capacity.
If many applications need to send telemetry, scale out the gateway Collector instead of sending directly from each application.
Supported `compression` values are `gzip` (the `OTLP/HTTP` exporter default) and `none`.
In development-only setups, you can send data from a custom application by pointing the OTLP/HTTP exporter of an [OpenTelemetry language SDK](https://opentelemetry.io/docs/getting-started/dev/) at the corresponding Elasticsearch OTLP endpoint path.
Traces sent this way are stored without `elasticapm` enrichment or aggregated APM metrics, so the APM views that depend on them stay empty.
In production, point SDKs at a gateway Collector or at the Elastic Cloud Managed OTLP Endpoint.
<note>
  Only `encoding: proto` is supported, which the `OTLP/HTTP` exporter uses by default.
</note>


## Routing to data streams

By default, records are written to the following data streams:

| Signal  | Default data stream            |
|---------|--------------------------------|
| Logs    | `logs-generic.otel-default`    |
| Traces  | `traces-generic.otel-default`  |
| Metrics | `metrics-generic.otel-default` |

For more about how OTLP metrics are stored as time series data streams, refer to [Ingest metrics into a TSDS using the OTLP/HTTP endpoint](https://www.elastic.co/elastic/docs-builder/docs/4302/manage-data/data-store/data-streams/tsds-ingest-otlp).
The target data stream name follows the pattern `<type>-<dataset>.otel-<namespace>`.
You can influence `dataset` and `namespace` by setting attributes on your data:
- Set `data_stream.dataset` and/or `data_stream.namespace` as attributes.
  Precedence: data point or log record attribute, then scope attribute, then resource attribute.
- Otherwise, if the scope name contains `/receiver/<somereceiver>`, `data_stream.dataset` is set to the receiver name.
- Otherwise, `data_stream.dataset` falls back to `generic` and `data_stream.namespace` falls back to `default`.

Examples:

| Signal  | Attributes or scope name                                                   | Target data stream                 |
|---------|----------------------------------------------------------------------------|------------------------------------|
| Logs    | `data_stream.dataset: nginx.access`, `data_stream.namespace: prod`         | `logs-nginx.access.otel-prod`      |
| Traces  | `data_stream.dataset: checkout`, `data_stream.namespace: staging`          | `traces-checkout.otel-staging`     |
| Metrics | Scope name contains `/receiver/hostmetrics`, no `data_stream.*` attributes | `metrics-hostmetrics.otel-default` |
| Metrics | No matching attributes or receiver scope name                              | `metrics-generic.otel-default`     |


## Configure histogram handling for metrics

<applies-to>
  - Elastic Stack: Generally available since 9.4
  - Elastic Stack: Preview in 9.3
</applies-to>

You can configure how OTLP histogram metrics are mapped using the `xpack.otel_data.histogram_field_type` cluster setting.
Valid values are:
- `histogram` (default on <applies-to>Elastic Stack: Preview in 9.3</applies-to>): Map histograms as T-Digests using the `histogram` field type
- `exponential_histogram` (default on <applies-to>Elastic Stack: Generally available since 9.4</applies-to>): Map histograms as exponential histograms using the `exponential_histogram` field type

The setting is dynamic and can be updated at runtime:
```json

{
  "persistent" : {
    "xpack.otel_data.histogram_field_type" : "exponential_histogram"
  }
}
```

Because both `histogram` and `exponential_histogram` support [coerce](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4302/reference/elasticsearch/mapping-reference/coerce), changing this setting dynamically does not risk mapping conflicts or ingestion failures.
This setting only applies to metrics ingested through the Elasticsearch OTLP endpoint.
Documents ingested using the bulk API (for example through the Elasticsearch exporter for the OpenTelemetry Collector) are not affected.

## Metric temporality

<applies-to>
  - Elastic Stack: Generally available since 9.5
</applies-to>

The OTLP endpoint preserves the [temporality](https://www.elastic.co/elastic/docs-builder/docs/4302/manage-data/data-store/data-streams/metric-temporality) of ingested metrics and stores it in a `temporality` [dimension](/elastic/docs-builder/docs/4302/manage-data/data-store/data-streams/time-series-data-stream-tsds#time-series-dimension). This allows Elasticsearch to correctly interpret counter and histogram values during [ES|QL time series queries](/elastic/docs-builder/docs/4302/manage-data/data-store/data-streams/metric-temporality#temporality-and-queries) and [downsampling](/elastic/docs-builder/docs/4302/manage-data/data-store/data-streams/metric-temporality#temporality-and-downsampling).
The `temporality` dimension is set automatically based on the OTLP [AggregationTemporality](https://opentelemetry.io/docs/specs/otel/metrics/data-model/#temporality) of each metric data point. No additional configuration is needed.
Note that cumulative temporality for histograms is only supported if `xpack.otel_data.histogram_field_type` is set to `exponential_histogram` (which is the default).

## Limitations

- **Trace enrichment and APM metrics:** The endpoint does not run the `elasticapm` processor or connector.
  Traces are stored as received, no aggregated APM metrics are produced, and the APM views that depend on them, such as the service inventory and service map, stay empty.
  For the full APM experience, send traces to the [Elastic Cloud Managed OTLP Endpoint](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4302/reference/opentelemetry/managed-inputs/managed-otlp-endpoint) or through an [Elastic Agent in Gateway mode](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4302/reference/edot-collector/config/default-config-standalone#gateway-mode).
- **Delivery guarantees:** Elasticsearch can only acknowledge an OTLP request as a whole, not on a per-record basis.
  If part of a request fails, the client retries the entire batch, which can produce duplicate logs or trace spans.
  Metrics are not affected because metric points written to time series data streams are [deduplicated based on their dimensions and timestamp](/elastic/docs-builder/docs/4302/manage-data/data-store/data-streams/time-series-data-stream-tsds#time-series-dimension).
- **Profiles:** Profiles are not supported.
  To ingest profiles, use a distribution of the OpenTelemetry Collector that includes the [Elasticsearch exporter](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4302/reference/edot-collector/components/elasticsearchexporter), such as [Elastic Agent](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4302/reference/edot-collector).
- **Exemplars:** Exemplars are not supported yet.