Upload a GeoJSON or a Shapefile and check it for the five recurring topology errors — overlap, gap, sliver, duplicates, dangle. Free, runs entirely in your browser: the file never leaves your computer.
Published
September 3, 2026
Upload a file — .geojson, or a shapefile as a single .zip or as .shp/.dbf/.shx selected together — and find out whether any feature overlaps, leaves a gap, is a sliver, duplicates another, or (for lines) dangles unconnected.
Runs entirely in your browser (Python via WebAssembly): the file is never uploaded to a server. This is diagnosis only, not repair — fixing a topology error almost always requires a human decision (see the full article for why), so there’s no “Fix” step here, just the report and a map to inspect it on.
// The input and the writing logic into the virtual filesystem live in// shared/upload.js (WebGeoDS.Upload) — same helper used across the// blog's articles, not rewritten here.viewof uploadedFiles = WebGeoDS.Upload.createInput()
Click Check to run the five checks on the current data — your file uploaded above, or (if nothing’s uploaded) a built-in two-polygon overlap example.
The code itself isn’t shown here — it’s a fixed, non-editable check using GeoPandas/Shapely underneath; see the full article for the actual code, editable and explained one check at a time.
First run loads the Python engine — expect 30-40 seconds. Instant after that, and again each time you come back to this page.
sharedMapEl = sharedMap.element
// The color is decided by JS, not Python — see topology-errors.qmd for// the full explanation. The geometry type isn't fixed (polygons for// overlap/gap/sliver/duplicates, lines for dangle), so the paint// itself depends on the data: setGeoJSON() (shared/map.js) detects on// its own when the layer's TYPE needs to change and recreates it.errorPaint = (data) => {const geometryType = data?.features?.find((f) => f?.geometry?.type)?.geometry?.type??"";const colorExpr = ["case", ["==", ["get","has_error"],true],"#e05252","#3d5a73"];if (geometryType ==="LineString"|| geometryType ==="MultiLineString") {return { "line-color": colorExpr,"line-width":4 }; }if (geometryType ==="Point"|| geometryType ==="MultiPoint") {return { "circle-color": colorExpr,"circle-radius":6 }; }return { "fill-color": colorExpr,"fill-opacity":0.55 };}
// Not promoted to shared/ (still only one other tool using it, the// Validator, with a slightly different call site): a Blob + a// temporary <a download> is enough, no library needed.downloadGeoJSON = (sourceId, filename) => {const data = sharedMap.getGeoJSON(sourceId);if (!data) return;window.WebGeoDS.track?.("download_clicked", { tool:"topology-checker", sourceId });const blob =newBlob([JSON.stringify(data,null,2)], { type:"application/geo+json" });const url = URL.createObjectURL(blob);const a =document.createElement("a"); a.href= url; a.download= filename; a.click(); URL.revokeObjectURL(url);}
Want to understand each of the five errors, see the actual code, or compare against R’s independent implementation? The full article covers all of it, with a worked example for each one.