Using the data programmatically
The API is a tree of static JSON files served over HTTPS with
Access-Control-Allow-Origin: *. You can call it from a browser, a notebook
or another website with no key, no sign-up and no rate limit.
It is read-only and addressed entirely by path. There are no query parameters, because there is no server — filtering happens on your side, after you fetch. In exchange you get something that cannot go down under load, cannot rotate a key on you, and is cached on a CDN.
Base URL:
https://nikunjfriends25-droid.github.io/western-ghats-esa/
Endpoints
| Path | Returns |
|---|---|
api/v1/summary.json |
Per-state village counts, mapped area, notified area and ratio |
api/v1/states/{CODE}.json |
Every village in one state, attributes only, no geometry. Codes: GA GJ KA KL MH TN |
api/v1/geometry/{CODE}.json |
Every village in one state with geometry, as a GeoJSON
FeatureCollection. Simplified to ~33 m for overlay use |
api/v1/outline/{CODE}.json |
One state's ESA dissolved to a single outer boundary |
api/v1/outline.json |
The whole ESA dissolved, one feature per state — the lightest way to draw it |
api/v1/villages/{censuscode}.json |
One village as a GeoJSON Feature, full resolution |
api/v1/boundary-points.json |
The 401 Annexure B boundary points with state and gazette page |
api/v1/unmatched.json |
Gazette rows with no polygon, each with a reason |
api/v1/analysis-summary.json |
Derived totals, per-state rows, priority bands, and the limitations list |
api/v1/analysis/{CODE}.json |
Every village in a state with its derived indicators |
api/v1/kerala-comparison.json |
The same metrics computed on whole villages and on Kerala's official boundary — a measurement of how much the whole-village approximation shifts each figure |
Bulk geometry
Whole-state GeoJSON, Shapefile, KML and CSV are plain files under downloads/ —
fetch them the same way. The merged full-resolution GeoPackage is attached to the
latest release
rather than served here.
Overlaying the ESA on your own map
Three levels of detail, so you can pick the lightest thing that answers your question.
| Use | Endpoint | Size |
|---|---|---|
| Just show where the ESA is | api/v1/outline.json | smallest |
| Show one state's villages | api/v1/geometry/{CODE}.json | moderate |
| Exact boundary of one village | api/v1/villages/{censuscode}.json | tiny, full resolution |
Every one of these returns valid GeoJSON, so it drops straight into MapLibre, Leaflet, OpenLayers, Mapbox, QGIS or GeoPandas with no conversion.
MapLibre or Mapbox:
const base = 'https://nikunjfriends25-droid.github.io/western-ghats-esa/';
map.addSource('esa', { type: 'geojson', data: base + 'api/v1/outline.json' });
map.addLayer({ id: 'esa-fill', type: 'fill', source: 'esa',
paint: { 'fill-color': '#2f6d3a', 'fill-opacity': 0.35 } });
map.addLayer({ id: 'esa-line', type: 'line', source: 'esa',
paint: { 'line-color': '#1d4a25', 'line-width': 1.2 } });
Leaflet:
fetch(base + 'api/v1/geometry/KL.json')
.then(r => r.json())
.then(gj => L.geoJSON(gj, {
style: { color: '#2f6d3a', weight: 1, fillOpacity: 0.3 },
onEachFeature: (f, l) => l.bindPopup(f.properties.gz_village)
}).addTo(map));
QGIS — add these as a vector layer straight from the URL (Layer ▸ Add Layer ▸ Add Vector Layer ▸ Protocol: HTTP), or in the Python console:
iface.addVectorLayer(
"https://nikunjfriends25-droid.github.io/western-ghats-esa/api/v1/outline.json",
"Western Ghats ESA", "ogr")
Intersect the ESA with your own points, in GeoPandas:
import geopandas as gpd
base = "https://nikunjfriends25-droid.github.io/western-ghats-esa/"
esa = gpd.read_file(base + "api/v1/outline.json")
sites = gpd.read_file("my_sites.geojson").to_crs(esa.crs)
inside = gpd.sjoin(sites, esa, predicate="within")
print(len(inside), "of", len(sites), "sites fall inside the draft ESA")
Geometry from outline and geometry is simplified to
about 33 m for overlay use, so it is not suitable for measuring or for any
parcel-level question. Use api/v1/villages/{censuscode}.json, or the release
GeoPackage, when you need the full-resolution edge — and read
the caveats first.
Examples
One village, by 2011 Census code:
curl https://nikunjfriends25-droid.github.io/western-ghats-esa/api/v1/villages/626770.json
Every Kerala village that the gazette marks as bifurcated:
const base = 'https://nikunjfriends25-droid.github.io/western-ghats-esa/';
const kl = await fetch(base + 'api/v1/states/KL.json').then(r => r.json());
const partial = kl.rows.filter(r => r.bifurcated);
console.log(partial.map(r => r.gz_village));
Load a whole state into GeoPandas:
import geopandas as gpd
base = "https://nikunjfriends25-droid.github.io/western-ghats-esa/"
ka = gpd.read_file(base + "downloads/WG_ESA_2024_KA.geojson")
print(ka.area_km2.sum(), "km2 across", len(ka), "villages")
Total mapped area against what was notified:
curl -s https://nikunjfriends25-droid.github.io/western-ghats-esa/api/v1/summary.json \
| jq '.states[] | {state, area_km2, notified_km2, ratio}'
There are no Zone 1/2/3 fields. The 2024 notification defines a single,
undivided ESA. esa_category records how a village was mapped, not a level of
legal protection — see why there are no zones.
Field reference
| Field | Meaning |
|---|---|
gz_state, gz_district, gz_taluka, gz_village |
As printed in Annexure C of the notification |
gz_village_raw | Verbatim, including the * bifurcation marker |
gz_sno | Gazette serial number within its state |
cen_village, cen_subdistrict, cen_district |
The matched census record |
censuscode | 2011 Census village code — the join key to census tables |
lgd_villagecode | Local Government Directory village code |
esa_category |
whole_village, bifurcated_village, notified_forest,
kerala_village, kerala_bifurcated_village |
bifurcated | true when only part of the village is in the ESA |
score | Name similarity, 0–100 |
scope | How wide the search had to go: dist+tal, dist, state |
area_km2 | Polygon area, computed in EPSG:7755 |
analysis |
Present on each village endpoint: population and census composition, land cover, protection and tenure overlaps, forest and hydrological setting, and the two composite scores. See the analysis layer — these are derived figures with real limitations, not transcribed ones. |
Read the caveats before drawing conclusions. Villages with
bifurcated: true are returned as whole polygons and over-state the ESA, and all
Kerala rows are whole villages where the state's own definition is portion-wise. A low
score or a scope of state means the pairing is less
certain. See Method & caveats.
Stability & licence
Paths under api/v1/ are intended to stay put; a breaking change would appear
as api/v2/. Data is released under
CC BY 4.0, and derived from
the MoEFCC draft notification S.O. 3060(E) (PDF, 4.9 MB) — attribute
Western Ghats ESA Atlas, Nikunj Jambu and link back. The underlying government data
remains under its own terms.