# json_exporter turns any JSON endpoint into Prometheus metrics

> The Prometheus community json_exporter fetches a remote JSON document, picks values out of it with JSONPath, and publishes them as metrics, which fills the gap left when a service exposes only a JSON API and no instrumentation of its own.

**prometheus-community/json_exporter** — A prometheus exporter which scrapes remote JSON by JSONPath

- Repository: https://github.com/prometheus-community/json_exporter
- Stars: 743 · Forks: 217
- Language: Go
- License: Apache-2.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/prometheus-community-json-exporter

## The probe endpoint takes a module and a target

The exporter is a Prometheus exporter which scrapes remote JSON by JSONPath, and the whole interface is one HTTP endpoint. The example in the readme shows the setup and the first probe.

```console
$ make build
$ ./json_exporter --config.file examples/config.yml &
$ python3 -m http.server 8000 &
Serving HTTP on :: port 8000 (http://[::]:8000/) ...
```

The probe request names a module and a target, so the exporter knows which configuration to apply and which URL to fetch.

```console
$ curl "http://localhost:7979/probe?module=default&target=http://localhost:8000/examples/data.json"
```

The response is plain Prometheus exposition text, with HELP and TYPE lines and a metric per configured path, and the labels come from the JSON itself, so a value in the document becomes an attribute of the metric. A second module can point at a different document entirely, which is how the readme demonstrates a different JSON file with a different set of metrics on the same exporter.

```console
$ curl "http://localhost:7979/probe?module=animals&target=http://localhost:8000/examples/animal-data.json"
```

The JSONPath syntax supported is the one documented by Kubernetes for kubectl, which is a useful reference because it is a well specified dialect rather than a loose implementation.

## Lists in the JSON document become one series per element

The example output shows how the interesting cases are handled. A top level scalar becomes a single metric with the environment and location labels, and the value itself is a number, in the example 1234. A timestamped value becomes a count, a sub-level value scrape becomes one series per list element with the id label distinguishing them, and a boolean becomes a one or zero. The list case is the one to think about, because a JSON array of objects turns into one series per array element, with every field of the object becoming either a label or a value. That is a cardinality decision disguised as a parsing detail. A document with a hundred array entries produces a hundred series, and the metric names stay the same, so what changes between scrapes is the label set. The animal module in the readme makes the point with a population list, where each entry contributes a series labelled with the name and whether the animal is a predator.

## Timestamps from the JSON document disable staleness handling

There is one feature with a real consequence, and the readme flags it twice. The exporter allows you to use a field of the metric as the unix or epoch timestamp for the data as an int64, but this may lead to unexpected behaviour, because Prometheus implements a staleness mechanism, and including timestamps in metrics disables the staleness handling and can make data visible for longer than expected. That is a subtle failure in both directions. Without timestamps, a value that stops being reported goes stale on the Prometheus side as expected. With a timestamp taken from the document, the sample carries the age of the value in the source system, so a value that stopped changing but is still present in the JSON document can keep looking fresh long after it stopped updating. For a status document with a timestamp field this is usually what you want, and for a document without one it is a trap.

## POST bodies can be templated with Sprig functions

Some targets only respond to a POST, and the exporter supports that with the modules.<module_name>.body parameter, which is sent as the body content in the scrape request, and the HTTP method is set to POST in that case.

```yaml
body:
  content: |
    My static information: {"time_diff": "1m25s", "anotherVar": "some value"}
```

The body content can also be a Go Template, and all the functions from the Sprig library are available in the template, with all the query parameters Prometheus sent in the scrape query available as values while rendering. The readme shows both shapes.

```yaml
body:
  content: |
    {"time_diff": "{{ duration `95` }}","anotherVar": "{{ randInt 12 30 }}"}
  templatize: true
```

```yaml
body:
  content: |
    {"time_diff": "{{ duration `95` }}","anotherVar": "{{ .myVal | first }}"}
  templatize: true
```

The templatize flag is what distinguishes the second from the first, since without it the content is sent literally. The example curl then shows the effect, with a request carrying myVal=something producing a body with a computed time_diff and the value from the query string. The dependency on Sprig v3 in the go.mod is what supplies those functions.

## Running it in a container and under Prometheus

The Docker image is published on Quay under the prometheuscommunity organisation, and the run command is short.

```console
$ docker run -v $PWD/examples/config.yml:/config.yml quay.io/prometheuscommunity/json-exporter --config.file=/config.yml
```

The Dockerfile in the repository is a single stage over the Prometheus busybox image, with the binary copied in and the user set to nobody, and it exposes port 7979, which is the exporter's default listen port and the one the probe examples use. To see it end to end, the readme shows running Prometheus itself in a container with the example configuration mounted.

```console
$ docker run --rm -it -p 9090:9090 -v $PWD/examples/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus
```

You then look at the graph or the targets page to check the scraped metrics. HTTPS is supported through the exporter toolkit, whose web configuration documentation is the reference for the TLS settings. The example directory holds the pieces this all depends on, with config.yml and prometheus.yml alongside the two JSON documents, animal-data.json and data.json, that the probes fetch.

## Where a JSON scraper is the wrong tool

Three limits are worth stating. The first is that this is a scrape, not instrumentation. The exporter fetches a document on the Prometheus schedule and reports what it finds, so the metric reflects the state of the JSON at scrape time and nothing more, and any event inside the target that is not represented in the document is invisible. If you own the service, instrumenting it is strictly better. The second is cardinality, which the list handling makes concrete, since a JSON array becomes one series per element and every field of the element becomes a label, and a document with unbounded or high variety arrays will produce a metric that Prometheus finds expensive to store and awkward to query. The third is that the JSONPath dialect is the kubectl one, which is well specified but not the same as what a JSON API is usually documented in, so mapping an unfamiliar document is a small research task in itself. A related operational note is that the exporter must be able to reach the target from wherever it runs, and in a Kubernetes cluster that means network policy and egress rules, which is a deployment concern that the exporter itself does not address.

## Conclusion

json_exporter suits an operator who has to monitor a service that only offers a JSON status endpoint, and it suits anyone who wants metrics from a third party API without writing an exporter. It is the wrong tool for a service you own and can instrument properly, since a scraped snapshot of a JSON document is not the same as a metric emitted at the moment something happened, and it is the wrong tool for high cardinality JSON, since every distinct value in a list becomes a label. Before adopting it, check the staleness trade-off, because using a field as the metric timestamp disables Prometheus's staleness handling, and read the example configurations to see how the modules are structured. The last push was on 2026-10-19 and the current release is v0.8.0 from 2026-08-12.

## FAQ

### How do I use the json_exporter?

Build it with make build, run it with a configuration file such as ./json_exporter --config.file examples/config.yml, and then request a probe with a module name and a target URL, for example curl "http://localhost:7979/probe?module=default&target=http://localhost:8000/examples/data.json". The response is Prometheus exposition text.

### Does json_exporter support HTTPS and POST requests?

TLS configuration is supported through the Prometheus exporter toolkit, whose web configuration documentation is the reference. For POST, setting modules.<module_name>.body in the configuration sends that content as the scrape request body and sets the method to POST, and the body can be a Go Template with the Sprig library functions available.

### What happens if I use a JSON field as the metric timestamp in json_exporter?

You can use a field of the metric as the unix or epoch timestamp for the data as an int64, but the README warns that including timestamps in metrics disables Prometheus staleness handling and can make data visible for longer than expected.

## Sources

- [Issues](https://github.com/prometheus-community/json_exporter/issues)
- [License: Apache-2.0](https://github.com/prometheus-community/json_exporter/blob/master/LICENSE)
- [prometheus-community/json_exporter on GitHub](https://github.com/prometheus-community/json_exporter)
- [README](https://github.com/prometheus-community/json_exporter/blob/master/README.md)
- [Releases](https://github.com/prometheus-community/json_exporter/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/prometheus-community-json-exporter
