---
title: "Custom metrics"
description: "Configure Middleware integration for Custom Metrics to monitor application performance, track key metrics, and detect anomalies in real-time."
section: "API"
breadcrumb: "API > Custom Metrics"
canonical: "https://docs.middleware.io/get-started/ingestion-api/custom-metrics"
---
# Custom metrics

Collect any business or platform signal as custom metrics and visualise it alongside your Host/Kubernetes/Service telemetry in Middleware.

You can send metrics in two ways:

1. HTTP (OTLP/JSON): Simple `curl`/scripted pushes to `/v1/metrics`
2. OpenTelemetry SDKs: Instrument your app and export to Middleware over OTLP

## Option A: Send custom data with cURL (OTLP/JSON)

POST your payload to OTLP Metrics HTTP endpoint:

```bash
curl -X POST "your-initial-uid/v1/metrics" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -H "Authorization: your-initial-token" \
  -d @- << 'EOF'
{
  "resource_metrics": [
    {
      "resource": {
        "attributes": [
          { "key": "mw.resource_type", "value": { "string_value": "custom" } },
          { "key": "service.name", "value": { "string_value": "custom-metrics-pusher" } }
        ]
      },
      "scope_metrics": [
        {
          "metrics": [
            {
              "name": "swap-usage",
              "description": "SWAP usage",
              "unit": "By",
              "gauge": {
                "data_points": [
                  {
                    "attributes": [
                      { "key": "device", "value": { "string_value": "nvme0n1p4" } }
                    ],
                    "time_unix_nano": 1759743015000000000,
                    "asInt": 4000500678
                  }
                ]
              }
            }
          ]
        }
      ]
    }
  ]
}
EOF
```

**Notes:**

- Use `asInt` for integer values or `asDouble` for floating-point values.
- `time_unix_nano` is the event timestamp; if omitted, the backend may use its receive time.
- You can send multiple metrics in the same batch; add them to the `metrics` array.
- To attach the metric to an existing resource (host/pod/service/etc.), add the required resource attribute(s) (see tables below).

## Option B: Send custom metrics via OpenTelemetry

If you want to send custom metrics via your codebase, you need to install the OpenTelemetry Python SDK:

```bash
pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp
```

You can use the template codebase given below to send custom metrics:

```bash
import time
from opentelemetry import metrics
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter

# Configure OTLP exporter for Middleware
exporter = OTLPMetricExporter(
    endpoint="https://ruplp.middleware.io",  # no /v1/metrics for gRPC
    headers={"authorization": "<MW_API_KEY>"},
)

# Attach resource attributes (choose one of the options shown in the tables below)
resource = Resource.create({
    "mw.resource_type": "custom",
    "service.name": "custom-metrics-pusher"
})

metric_reader = PeriodicExportingMetricReader(exporter)
provider = MeterProvider(resource=resource, metric_readers=[metric_reader])
metrics.set_meter_provider(provider)

meter = metrics.get_meter(__name__)

counter = meter.create_counter(
    name="custom_counter",
    description="Counts something custom",
    unit="1",
)

histogram = meter.create_histogram(
    name="custom_histogram",
    description="Records histogram data",
    unit="ms",
)

while True:
    counter.add(1, attributes={"environment": "production", "region": "us-east-1"})
    histogram.record(100, attributes={"operation": "database_query"})
    time.sleep(5)
```

For other languages (Node.js/Go/Java, etc.), configure the OTLP/gRPC or OTLP/HTTP exporter and set the same endpoint and authorization header.

## Ingest into existing Middleware resource types

Attach the required resource attribute so the metric lands in the correct dataset:

| Type | Required resource attributes | Data set stored in |
| --- | --- | --- |
| `host` | `host.id` | Host Metrics |
| `k8s.node` | `k8s.node.uid` | K8s Node Metrics |
| `k8s.pod` | `k8s.pod.uid` | K8s Pod Metrics |
| `k8s.deployment` | `k8s.deployment.uid` | K8s Deployment Metrics |
| `k8s.daemonset` | `k8s.daemonset.uid` | K8s DaemonSet Metrics |
| `k8s.replicaset` | `k8s.replicaset.uid` | K8s ReplicaSet Metrics |
| `k8s.statefulset` | `k8s.statefulset.uid` | K8s StatefulSet Metrics |
| `k8s.namespace` | `k8s.namespace.uid` | K8s Namespace Metrics |
| `service` | `service.name` | Service Metrics |
| `os` | `os.type` | OS Metrics |

**Example (host):**

Add to the `resource.attributes`:

```json
{ "key": "host.id", "value": { "string_value": "ip-10-0-0-12" } }
```

## Ingest pure custom data (no existing type)

If your metric doesn’t belong to an existing resource, set:

```json
{ "key": "mw.resource_type", "value": { "string_value": "custom" } }
```

These metrics appear under the Custom Metrics dataset in the UI and can be charted, alerted, and filtered using any attributes you attach.

## Verify Delivery

- Send a test data point.
- In the dashboard, open dashboard builder → Create a new or open an existing dashboard and add a metrics widget.
- Under the Look for menu, select Custom, and the data should start showing in the selected dashboard.

![Middleware Custom Metrics API integration ](/images/v2/apm/custom-metrics-api.webp)

## Troubleshooting (quick)

- 401/403: Check the `Authorization` header (no `Bearer`), that the key is active, and you’re hitting the correct region.
- 400/422: Validate OTLP structure — ensure `resource_metrics[*].scope_metrics[*].metrics[*]` contains one of `gauge` / `sum` / `histogram` with a `data_points` array.
- No data visible: Confirm `mw.resource_type` or the correct resource attribute (e.g., `host.id`) is set. Ensure timestamps are realistic nanoseconds.
- High cardinality: Reduce dynamic attribute values; prefer enums/buckets.
- gRPC exporters: Use endpoint without `/v1/metrics` and keep TLS enabled (port 443).

Need assistance or want to learn more about Middleware? Get in touch with us via our Contact Us page or join our Slack channel.
