Last updated: · By

Geo Clustering: Find Hotspots in a List of Coordinates

Paste or upload a list of latitude/longitude points and see which ones form clusters, using DBSCAN with distances in metres. Everything runs in your browser.

Drop a .csv, .tsv, .txt or .geojson file here, or choose a file

Decimal degrees (WGS84), up to 20,000 points · comma, semicolon or tab separated · a header row is detected automatically · nothing is uploaded: the file never leaves your browser.

New: 16 Oct 2026 — first version, a browser-only take on Bellingcat’s geoclustering command-line tool.

What does geo clustering show?

It shows where your points bunch together. Give the tool a list of coordinates, such as geolocated incidents, photo locations or sensor hits. It reports which points sit in dense groups (clusters) and which stand alone (noise). The method is DBSCAN, a density-based algorithm published by Ester, Kriegel, Sander and Xu in 1996 scikit-learn docs (read 16 Oct 2026). Two numbers drive it: a distance in metres and a minimum number of points.

The page is inspired by Bellingcat’s open-source geoclustering tool, a command-line program. It clusters the lat/lon rows of a CSV with DBSCAN or OPTICS and writes JSON, GeoJSON, text, CSV and a kepler.gl map Bellingcat on GitHub (read 16 Oct 2026). Bellingcat’s project is MIT-licensed. No code was copied: this is a separate JavaScript implementation that runs in your browser and needs no installation.

  1. Paste a CSV or drop a file. Columns named lat/latitude and lon/lng/longitude are found automatically; a label or name column and a date column are optional.
  2. Set the distance and minimum points. The defaults (200 m, 4 points) suit street-level data. See the next sections before you rely on a result.
  3. Read the table and the map. Clusters are numbered by size, largest first. Each row gives the point count, the centre, the spread from the centre and the first and last date.
  4. Export. Download the points with a cluster_id column as CSV or GeoJSON, or a one-row-per-cluster summary.

Settings at a glance

Setting or outputWhat it means herePractical note
Distance (metres)Two points are neighbours if the great-circle distance between them is at most this valueIt is the reach between neighbours, not a cap on cluster size scikit-learn docs (read 16 Oct 2026)
Minimum pointsA point is a core point if this many points, itself included, lie within the distanceSame convention as scikit-learn’s min_samples scikit-learn docs (read 16 Oct 2026)
ClusterCore points that reach each other, plus border points next to themNumbered 1, 2, 3… by size
NoisePoints that belong to no clusterExported with cluster_id -1, as scikit-learn labels noise scikit-learn docs (read 16 Oct 2026)
SpreadLargest distance from the cluster centre to one of its pointsA spread far above the distance setting means a chained cluster
Distance formulaHaversine on a sphere with a 6,371 km mean radiusSpherical errors are typically up to 0.3% Movable Type Scripts (read 16 Oct 2026)

How does DBSCAN group the points?

DBSCAN looks at every point and counts its neighbours within the distance. A point with enough neighbours (the minimum points, counting itself) is a core point. Core points that are within reach of each other join one cluster. Points within reach of a core point, but without enough neighbours of their own, join as border points. Everything else is noise scikit-learn docs (read 16 Oct 2026).

Distances are measured along the Earth’s surface with the haversine formula, which gives the “as-the-crow-flies” great-circle distance Movable Type Scripts (read 16 Oct 2026). That means a 200 m setting means 200 m in Oslo and in Quito alike, which a setting in raw degrees would not. Points on either side of the 180° meridian are treated as neighbours when they are close. A grid index keeps the search fast, so the 20,000-point limit is practical (see the tests below).

Bellingcat’s tool also offers OPTICS, which it describes as giving tighter clusters but running slower Bellingcat on GitHub (read 16 Oct 2026). This page offers DBSCAN only.

How do I choose the distance and minimum points?

  • Match the distance to your data’s precision. Phone GPS and geolocated photos are often good to tens of metres; geocoded addresses or place names can be off by hundreds. A distance below the error of your coordinates creates noise; one far above it merges separate places.
  • Raise minimum points for noisy data. With 2 points, any pair becomes a cluster. With 5 or more, a cluster needs a real concentration.
  • Test the stability. Run the same data at half and double the distance. A hotspot that persists is a finding; one that appears at a single setting is a parameter effect.
  • Watch the spread column. DBSCAN chains along lines of points, so roads and rivers can produce long clusters. scikit-learn’s documentation calls the distance “not a maximum bound on the distances of points within a cluster” scikit-learn docs (read 16 Oct 2026).
  • Remember duplicates count. Ten reports at exactly the same coordinate are ten points. Remove repeats first if they are the same event.

Why is there no street map?

Choice: no map tiles. The map is a plain SVG scatter plot drawn in your browser, with a coordinate grid and a scale bar. Map tiles would tell a tile server which area you are investigating, and heavy use of free tile servers is restricted. The OpenStreetMap Foundation’s policy allows normal interactive viewing of its standard tiles. It forbids bulk downloading, prefetching and offline use, offers “no SLA or guarantee” and can block heavy use without notice OSMF tile policy (read 16 Oct 2026).

For context, each cluster row has two links. OpenStreetMap opens the cluster centre on openstreetmap.org; Geo tools hands it to our geolocation tools. Both send only that one coordinate, and only when you click. For a full basemap, export the GeoJSON and open it in a desktop GIS such as QGIS, or in a mapping tool you already trust.

What can clustering not tell you?

  • Why points are close. A cluster can reflect where people report, post or travel, such as a busy square or a road. It does not show that events are related.
  • A single right answer. Different settings give different clusters. Report the distance and minimum points you used with every finding.
  • Precision you do not have. Clusters inherit the errors of the coordinates. Rounded or geocoded locations produce artificial clusters on rounding grid points or town centres.
  • Anything about time, unless you split the data yourself. The date column is summarised per cluster, but the clustering itself uses location only.

Use it responsibly. Clustering one person’s location history can reveal their home, workplace and routine. Use the tool on incident, photo or sensor data you are entitled to analyse, not to track a specific individual. Check the law on location data where you work.

How was the tool tested?

We tested the engine (geo-clustering-engine.js) in Node.js and the page in headless Chromium at 375 and 1280 pixels (16 Oct 2026):

  • Haversine distance for 1° of longitude on the equator equals 6,371 km × π / 180 (111,194.9 m).
  • The grid-indexed DBSCAN matched a brute-force DBSCAN on 15 random datasets. They covered a city, the high Arctic (78° N), the 180° meridian near Fiji, the North Pole and a global spread.
  • A chain of points 100 m apart is one cluster at 110 m and all noise at 90 m. Minimum points 1 makes every point a cluster.
  • Parsing covered header synonyms (latitude, lng), semicolon files with decimal commas, tab and space separators and GeoJSON. It also covered swapped, out-of-range and empty coordinates and CSV formula injection.
  • 20,000 points at a 1 km distance clustered in about 0.1 seconds in Node.js.
  • In the browser we tested the sample data, pasted text, file upload, column overrides, the tooltip, zoom and all three downloads. Hostile labels such as <img onerror> stayed text, and clustering made no network requests.

Sources

Frequently asked questions

What distance should I use for clustering?

Start with the distance at which two of your points would plausibly be about the same place: around 50 to 200 metres for street-level events, a few kilometres for towns, tens of kilometres for regions. Then try values half and double that size. Clusters that survive all three settings are the ones worth reporting. Very large distances chain whole areas together; very small ones leave almost everything as noise.

What does noise mean in the results?

Noise points are points that are not within the chosen distance of a dense enough group. With a minimum of 4 points, a point needs at least 3 neighbours within the distance, or must sit next to a point that has them, to join a cluster. Noise is still data: an isolated event can matter more than a hotspot. Exports can include noise points with cluster_id -1.

Why did points far apart end up in the same cluster?

DBSCAN chains. The distance is the reach between neighbouring points, not the maximum size of a cluster, so a line of points 150 metres apart forms one long cluster at a 200 metre setting even if its ends are kilometres apart. The cluster table shows each cluster’s spread from its centre so you can spot this. Lower the distance or raise the minimum points to split chains.

Is my data uploaded anywhere?

No. The CSV is read and clustered by JavaScript in your browser, and the map is drawn locally without map tiles, so not even the area you are looking at is sent to a tile server. Only the links you choose to click, such as Open in OpenStreetMap for a cluster centre, send one coordinate to that site.

Can I use addresses or degrees-minutes-seconds?

Not directly. The tool needs decimal degrees in WGS84, the format phones, EXIF and most exports use. Convert DMS, UTM or MGRS values with the Coordinate Converter first. Addresses must be geocoded into coordinates by another tool, and geocoding errors then become clustering errors, so check a sample by hand.

How is this different from Bellingcat’s geoclustering tool?

Bellingcat’s geoclustering is a Python command-line tool that runs DBSCAN or OPTICS and writes JSON, GeoJSON, text, CSV and a kepler.gl map, with the distance given in kilometres. This page is an independent browser version inspired by it. It offers DBSCAN only, takes the distance in metres, measures great-circle distance with the haversine formula, and needs no installation.