BYTETOOLS

openSenseMap API

Free citizen weather station API with no key: read any senseBox's sensors and their latest measurements, from temperature and humidity to particulates. Tested example included.

No API key requiredCORS enabledHTTPSFree tier

Endpoint tested and returned HTTP 200 on 2026-08-21

What is the openSenseMap API?

openSenseMap hosts data from senseBox citizen science weather stations and serves it openly with no API key. Fetching a box returns its sensor array — each with a type, title, unit and last measurement — along with its location and metadata.

This is a citizen science network, not a professional one, and the distinction runs through everything. Thousands of senseBoxes are deployed by schools, hobbyists and community groups, which gives spatial density that official networks cannot approach — and data quality that varies from excellent to abandoned. The API makes no attempt to hide that, and the honest way to use it is to check `lastMeasurement` on every sensor before trusting a reading.

The example deliberately fetches a single box rather than the full listing, and for a good reason: `/boxes` without a filter returns tens of megabytes covering the entire global network and will truncate in most clients. Fetch a single box by id, or filter geographically with a bounding box. Note that sensor `title` and `unit` are set by whoever built the box, so they arrive in whatever language and convention that person used — the sample here has German titles like `Helligkeit` and `Luftdruck` alongside a `Pegel` unit that has no standard meaning.

Quick facts

Base URL
https://api.opensensemap.org
Authentication
No API key for reading boxes and measurements. Submitting data requires a token issued to the box owner.
Rate limit
No published limit. Measurements arrive at whatever interval each box is configured for.
Pricing
Free. The platform and the data are open.
CORS
Enabled — callable directly from browser JavaScript
Official docs
Read the docs

How to use the openSenseMap API

Every request below was executed against the live API on 2026-08-21, and the response shown is the real body it returned — not an illustration.

1. Read a single senseBox and its sensors

GET https://api.opensensemap.org/boxes/5391be52a8341554157792e6

curl
curl 'https://api.opensensemap.org/boxes/5391be52a8341554157792e6'
JavaScript (fetch)
const res = await fetch("https://api.opensensemap.org/boxes/5391be52a8341554157792e6");
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
const data = await res.json();
console.log(data);
Python (requests)
import requests

res = requests.get("https://api.opensensemap.org/boxes/5391be52a8341554157792e6", timeout=20)
res.raise_for_status()
print(res.json())
Response — HTTP 200 (truncated)
{
  "_id": "5391be52a8341554157792e6",
  "name": "LeKa Berlin",
  "sensors": [
    {
      "_id": "5391be52a8341554157792e7",
      "__v": 0,
      "boxes_id": "5391be52a8341554157792e6",
      "lastMeasurement": {
        "createdAt": "2024-10-16T02:32:18.156Z",
        "value": "25.3"
      },
      "sensorType": "GL5528",
      "title": "Helligkeit",
      "unit": "Pegel"
    },
    {
      "_id": "5391be52a8341554157792e8",
      "__v": 0,
      "boxes_id": "5391be52a8341554157792e6",
      "lastMeasurement": null,
      "sensorType": "LM386",
      "title": "Schall",
      "unit": "Pegel"
    },
    {
      "_id": "5391be52a8341554157792e9",
      "__v": 0,
      "boxes_id": "5391be52a8341554157792e6",
      "lastMeasurement": null,
      "sensorType": "BMP085",
      "title": "Luftdruck",
      "unit": "Pa"
    },
    {
      "_id": "5391be52a8341554157792ea",
      "__v": 0,
      "boxes_id": "5391be52a8341554157792e6",
      "lastMeasurement": null,
      "sensorType": "DHT11",
      "title": "Luftfeuchtigkeit",
      "unit": "%"
    },
    {
      "_id": "5391be52a8341554157792eb",
      "__v": 0,
      "boxes_id": "5391be52a8341554157792e6",
      "lastMeasurement": {
        "createdAt": "2026-08-21T03:38:58.416Z",
        "value": "-999.999"
      },
      "sensorType": "BMP085",
      "title": "Temperatur",
      "unit": "°C"
    }
  ],
  "exposure": "unknown",
  "createdAt": "2022-03-30T11:25:43.193Z",
  "model": "custom",
  "currentLocation": {
    "coordinates": [
      13.42761039733887,
      52.54760056249269
    ],
    "type": "Point",
    "timestamp": "

Parameters

ParameterTypeRequiredDescription
(box id)pathRequiredMongoDB ObjectId of the senseBox, from the map or from a filtered listing. 5391be52a8341554157792e6
bboxqueryOptionalBounding box as `minLon,minLat,maxLon,maxLat` to filter the listing geographically. Strongly recommended over an unfiltered `/boxes`. 13.3,52.4,13.5,52.6
phenomenonqueryOptionalFilter boxes to those measuring a given phenomenon. Temperatur
/boxes/{id}/data/{sensorId}pathOptionalHistorical measurements for one sensor over a date range.

Response fields

_idstring
Box identifier.
namestring
Name given by the box's owner.
sensorsarray
Every sensor fitted to the box.
sensors[]._idstring
Sensor identifier, needed for the historical data endpoint.
sensors[].titlestring
Owner-supplied label — frequently German, as in `Helligkeit` for brightness or `Luftdruck` for air pressure.
sensors[].unitstring
Owner-supplied unit. Not standardised: `Pegel` appears in the sample and means nothing outside that box's own convention.
sensors[].sensorTypestring
Hardware model, such as `BMP085` or `GL5528`. This tells you far more about accuracy than the title does.
sensors[].lastMeasurementobject
The most recent reading with `value` and `createdAt`. Null when the sensor has never reported — and check the date, because a box can be years dead.
sensors[].boxes_idstring
Back-reference to the parent box.

What you can build with the openSenseMap API

  • Build a hyperlocal weather map from community sensors
  • Compare citizen particulate readings against official monitoring
  • Run a school project on a class's own senseBox data
  • Study spatial temperature variation across a city

Common errors and how to fix them

Truncated or enormous response

`/boxes` with no filter returns the entire global network.

Fix: Always pass a `bbox` or fetch a single box by id. The unfiltered listing runs to tens of megabytes.

Stale readings

Boxes are volunteer-run and get abandoned.

Fix: Check `lastMeasurement.createdAt` on every sensor. A value from 2024 in a live dashboard is worse than no value.

null lastMeasurement

The sensor is fitted but has never successfully reported.

Fix: Skip it rather than rendering an empty tile.

Unrecognisable units

Titles and units are free text chosen by each box owner.

Fix: Use `sensorType` to identify what the hardware actually is, and do not attempt automatic unit conversion on `unit`.

openSenseMap API — frequently asked questions

Is openSenseMap free to use?

Yes, free with no key for reading. It is an open citizen science platform; submitting measurements requires a token issued to the box owner.

How reliable is the data?

It varies enormously. These are hobbyist and school-built stations, so siting and calibration are inconsistent and some boxes have been offline for years. Check `lastMeasurement` timestamps and treat `sensorType` as your guide to accuracy.

Why is the boxes endpoint so slow?

Because without a filter it returns every box in the global network. Pass a `bbox` to constrain it geographically, or fetch a single box by id.

Why are the sensor labels in German?

The project originated in Germany and labels are typed by each box owner, so they appear in whatever language and convention that person used. `sensorType` is the language-independent field.

Tools that pair with this API

openSenseMap is an independent third-party service and is not affiliated with ByteTools or ByteVancer. Details on this page were verified on 2026-08-21; always check the official documentation before relying on this API in production, as terms and limits can change.