geojsonkit.org
GeoJSON utilities, in the browser
Say hi →

Point in polygon

updated 26 August 2026

Drop a .geojson file, or
Drop the polygon file, or

What this tool does

It answers the commonest spatial question there is: which area is this point in? Paste points in the first pane and polygons in the second, and every point comes back carrying the properties of the polygon that contains it — district, postcode area, sales territory, catchment, ward.

That is a spatial join, and it is normally a reason to install PostGIS or open QGIS. For a few thousand points against a few hundred polygons it is a page of arithmetic, so it runs here instead, and nothing leaves your browser.

How this tool works

1. Even-odd ray casting

For each point, draw a ray to infinity and count how many times it crosses the polygon's boundary. Odd means inside, even means outside. It needs no trigonometry, no winding order, and no assumption that the polygon is convex — which matters, because real administrative boundaries are neither convex nor tidy.

2. Holes are subtracted

In GeoJSON a polygon's first ring is its outer boundary and every later ring is a hole. A point inside the outer ring and inside a hole is outside the polygon. Tools that ignore this quietly put every point in the lake inside the county, and you find out later. Here each ring set is tested outer-first and any hole hit disqualifies the match. MultiPolygon is treated as what it is: several ring sets, any one of which counts.

3. Bounding boxes first

Five thousand points against four hundred polygons is two million containment tests. Each polygon's bounding box is computed once, and a point outside the box cannot be inside the polygon — so nearly every pair is rejected by four numeric comparisons instead of a full ring walk. The status line reports how many real ray casts survived that filter, which is usually a small fraction of the total.

4. Overlaps are reported, not hidden

A point can be inside two polygons — overlapping catchments, a boundary file with duplicated features, nested administrative levels in one collection. Keeping the first match silently is how a spatial join produces a confident wrong answer, so the count of multiply-matched points is always shown and how to resolve them is a choice: keep the first, emit one output feature per match, or join the values with a semicolon.

Things worth knowing

  • A point exactly on a boundary is not promised either way. Under floating-point arithmetic no convention for that case is stable, so rather than claim a rule the honest answer is that a point on the edge may land on either side. If it matters, nudge the geometry or buffer the polygon.
  • Coordinates are compared in whatever units the files use. GeoJSON is longitude, latitude in WGS 84 — and both files must agree. If your points come back matching nothing, check for the classic swap: a "longitude" of 50.45 is a latitude. Reproject handles a genuine projection mismatch.
  • Planar, not geodesic. Containment is computed on the flat lon/lat plane. For everything except polygons that cross the antimeridian or reach the poles, this gives the same answer as a geodesic test; for those two cases it does not, and no browser-side tool should pretend otherwise.
  • MultiPoint features match if any of their points is inside — the alternative would make a scattered cluster match nothing.
  • Lines and polygons in the points pane are skipped and counted in the status line, rather than being silently dropped.

Counting instead of tagging

Set the output to count per polygon and you get CSV instead: one row per polygon with the number of points that fell inside it, highest first. That is the answer to "how many incidents per ward" without a spreadsheet step, and it is worth running before a tag join — a polygon with a count of zero is often a sign that the two files are in different coordinate systems rather than that the area is genuinely empty.

FAQ

Which properties get copied? All of the polygon's by default. Name a comma-separated list to copy only those, and set a prefix to avoid colliding with property names the points already have. A match_count property is always added, so a point that matched nothing is distinguishable from one that was never tested.

How large a file can it handle? Tens of thousands of points against hundreds of polygons is comfortable because of the bounding-box filter. Hundreds of thousands is not — that is the point at which a real spatial index earns its keep, and the tool will simply be slow rather than wrong.

Is anything uploaded? No. Both files are parsed and joined in your browser.