Open Data API
API-Dokumentation
Programmatischer Zugriff auf alle Umwelt-Score-Daten für Kanton Zürich. Geeignet für Python, R, JavaScript und jede HTTP-Bibliothek.
Pro- oder Schul-Abo erforderlich. Anfragen können per Session-Cookie (Browser-Login) oder per API-Key authentifiziert werden. API-Keys werden im Admin-Bereich generiert und im Header übergeben:
Unauthentifizierte Anfragen erhalten
Authorization: Bearer usk_live_…Unauthentifizierte Anfragen erhalten
401, Anfragen ohne passendes Abo 403. Jetzt upgraden →Basis-URL & Lizenz
Basis-URL
/api/export/gemeindenAuthentifizierung
Session-Cookie oder Authorization: Bearer usk_live_…Lizenz
CC BY 4.0 – Quellenangabe: BCS FS26 BFHFormat
JSON (Standard) oder CSVAktualisierung
Manuell / bei Pipeline-RunsQuery-Parameter
| Parameter | Typ | Beschreibung | Beispiel |
|---|---|---|---|
format | string | Ausgabeformat: json (Standard) oder csv | format=csv |
bezirk | string | Nur Gemeinden dieses Bezirks | bezirk=Zürich |
min_score | number | Mindest-Gesamtscore (0–100) | min_score=70 |
max_score | number | Maximal-Gesamtscore (0–100) | max_score=50 |
sort | string | Sortierfeld: total, name, bezirk, pop | sort=total |
order | string | Sortierrichtung: desc (Standard) oder asc | order=asc |
Datenfelder
| Feld | Typ | Beschreibung |
|---|---|---|
bfs | number | BFS-Gemeindenummer (eindeutig, stabil) |
name | string | Gemeindename |
bezirk | string | Bezirksname |
pop | number | Einwohnerzahl |
fläche | number | Gemeindefläche in km² |
total | number | Gesamtscore (0–100) |
scores.luft | number|null | Kategorie-Score Luftqualität (0–100) |
scores.lärm | number|null | Kategorie-Score Lärmbelastung (0–100) |
scores.energie | number|null | Kategorie-Score Energiemix (0–100) |
scores.grün | number|null | Kategorie-Score Grünflächen (0–100) |
scores.boden | number|null | Kategorie-Score Boden & Klima (0–100) |
data_quality.* | string | Datenqualität pro Kategorie: complete, partial, estimated, missing |
raw.nox_t_a | number|null | NOx-Emissionen (t/a/km²) |
raw.pm10_t_a | number|null | PM10-Emissionen (t/a/km²) |
raw.pm25_t_a | number|null | PM2.5-Emissionen (t/a/km²) |
raw.solar_usage_pct | number|null | PV-Nutzungsgrad Gebäude (%) |
raw.renewable_heating_pct | number|null | Erneuerbare Wärme (%) |
raw.electric_car_share_pct | number|null | E-Auto-Anteil (‰) |
raw.strassenlaerm_pct | number|null | Strassenlärm: % Bev. über Grenzwert |
raw.bahnlaerm_pct | number|null | Bahnlärm: % Bev. über Grenzwert |
raw.fluglaerm_pct | number|null | Fluglärm: % Bev. über Grenzwert |
raw.wald_pct | number|null | Waldanteil (%) |
raw.schutzgebiet_pct | number|null | Schutzgebietsanteil (%) |
raw.versiegelung_pct | number|null | Versiegelungsgrad (%) |
raw.belastete_per_km2 | number|null | Belastete Standorte pro km² |
raw.hitzetage | number|null | Ø Hitzetage pro Jahr (MeteoSchweiz Klimanorm) |
raw.strompreis_rp_kwh | number|null | Strompreis Haushalt H4 in Rp./kWh (ElCom) |
Beispiel-Requests
curlAlle Gemeinden als JSON (API-Key)
curl "https://umwelt-score.com/api/export/gemeinden" \ -H "Authorization: Bearer usk_live_YOUR_KEY" \ -o gemeinden-zh.json
curlNur Top-Gemeinden als CSV
curl "https://umwelt-score.com/api/export/gemeinden?format=csv&min_score=70&sort=total" \ -H "Authorization: Bearer usk_live_YOUR_KEY" \ -o top-gemeinden.csv
PythonDaten in pandas laden
import requests
import pandas as pd
API_KEY = "usk_live_YOUR_KEY"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
r = requests.get("https://umwelt-score.com/api/export/gemeinden", headers=HEADERS)
if r.status_code != 200:
raise SystemExit(f"Fehler {r.status_code}: {r.json().get('message', r.text)}")
data = r.json()
df = pd.DataFrame(data["gemeinden"])
# Scores und Rohdaten als eigene Spalten
scores = pd.json_normalize(df["scores"]).add_prefix("score_")
raw = pd.json_normalize(df["raw"]).add_prefix("raw_")
df = pd.concat([df[["bfs","name","bezirk","pop","fläche","total"]], scores, raw], axis=1)
print(df.sort_values("total", ascending=False).head(10))
# Hitzetage & Strompreis
print(df[["name","raw_hitzetage","raw_strompreis_rp_kwh","total"]].sort_values("raw_hitzetage", ascending=False).head(10))RDaten in R laden
library(httr)
library(jsonlite)
API_KEY <- "usk_live_YOUR_KEY"
res <- GET("https://umwelt-score.com/api/export/gemeinden",
add_headers(Authorization = paste("Bearer", API_KEY)))
data <- fromJSON(content(res, "text", encoding = "UTF-8"))
df <- data$gemeinden
# Scores und Rohdaten extrahieren
scores <- as.data.frame(df$scores)
names(scores) <- paste0("score_", names(scores))
raw <- as.data.frame(df$raw)
df <- cbind(df[c("bfs","name","bezirk","pop","total")], scores, raw)
# Korrelation Hitzetage vs. Boden-Score
cor(df$hitzetage, df$score_boden, use = "complete.obs")
# Günstigste Gemeinden nach Strompreis
head(df[order(df$strompreis_rp_kwh), c("name","strompreis_rp_kwh","score_energie")], 10)JavaScriptFetch im Browser
const API_KEY = 'usk_live_YOUR_KEY'
const res = await fetch('https://umwelt-score.com/api/export/gemeinden?min_score=60', {
headers: { Authorization: `Bearer ${API_KEY}` }
})
if (!res.ok) throw new Error(`Fehler ${res.status}: ${(await res.json()).message}`)
const { gemeinden, metadata } = await res.json()
console.log(`${gemeinden.length} Gemeinden geladen (Stand: ${metadata.pipeline_meta?.generated_at})`)
// Bezirks-Durchschnitt Score + Ø Hitzetage
const byBezirk = {}
for (const g of gemeinden) {
if (!byBezirk[g.bezirk]) byBezirk[g.bezirk] = { scores: [], hitzetage: [] }
byBezirk[g.bezirk].scores.push(g.total)
if (g.raw?.hitzetage != null) byBezirk[g.bezirk].hitzetage.push(g.raw.hitzetage)
}
const avg = Object.fromEntries(
Object.entries(byBezirk).map(([b, d]) => [b, {
score: (d.scores.reduce((a,v) => a+v) / d.scores.length).toFixed(1),
hitzetage: d.hitzetage.length ? (d.hitzetage.reduce((a,v) => a+v) / d.hitzetage.length).toFixed(1) : '–',
}])
)
console.table(avg)Antwort-Struktur (JSON)
{
"metadata": {
"exported_at": "2026-05-08T10:00:00.000Z",
"count": 160,
"kanton": "ZH",
"lizenz": "CC BY 4.0",
"pipeline_meta": { "generated_at": "2026-05-08T08:12:33", ... }
},
"gemeinden": [
{
"bfs": 261,
"name": "Zürich",
"bezirk": "Zürich",
"pop": 436551,
"fläche": 87.9,
"total": 37.5,
"scores": { "luft": 38, "lärm": 22, "energie": 61, "grün": 52, "boden": 44 },
"data_quality": { "luft": "complete", "lärm": "estimated", ... },
"raw": {
"nox_t_a": 12.4, "solar_usage_pct": 18.2,
"hitzetage": 8.3, "strompreis_rp_kwh": 24.1, ...
},
"meta": { "netzbetreiber": "EWZ", "elcom_year": "2026" }
},
...
]
}