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.
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 'https://api.opensensemap.org/boxes/5391be52a8341554157792e6'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);import requests
res = requests.get("https://api.opensensemap.org/boxes/5391be52a8341554157792e6", timeout=20)
res.raise_for_status()
print(res.json()){
"_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
| Parameter | Type | Required | Description |
|---|---|---|---|
(box id) | path | Required | MongoDB ObjectId of the senseBox, from the map or from a filtered listing. 5391be52a8341554157792e6 |
bbox | query | Optional | Bounding 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 |
phenomenon | query | Optional | Filter boxes to those measuring a given phenomenon. Temperatur |
/boxes/{id}/data/{sensorId} | path | Optional | Historical 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
Unit Converter
Convert between units of length, weight, temperature, area, volume, speed, time and data storage instantly, with a swap button and common conversion tables.
Coordinate Converter
Convert GPS coordinates between decimal degrees, degrees-minutes-seconds and decimal minutes instantly. Paste any format like 40°26'46"N and copy the result.
CSV Column Statistics Calculator
Profile a CSV column by column: type, blanks, distinct values, min, max, mean, median, standard deviation and percentiles, plus top values — all in-browser.
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.