Point in polygon checker
The point (1, 1) lies inside the rectangle with corners (0, 0), (4, 0), (4, 3) and (0, 3): a ray cast to the right crosses its outline once, and an odd count means inside. Clockwise or counter-clockwise order both work. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Runs in your browser. Free, unlimited — your data never leaves this page.
A point-in-polygon test answers a basic computational geometry question: given one query location and a closed shape defined by an ordered ring of vertices, does that location fall in the interior of the shape? Surveying, mapping products, game collision masks, logistics geofences, and classroom geometry labs all need the same deterministic answer rather than a hand-drawn sketch. This checker implements the classical even-odd ray casting algorithm on planar coordinates: a horizontal half-line is cast from the test point toward positive infinity, each polygon edge is tested for a proper crossing, and the parity of the crossing count decides inside versus outside. Points that land exactly on an edge or vertex are treated as inside and flagged with an on-boundary marker so closed-set consumers do not need a second pass. The polygon is closed implicitly—you do not have to repeat the first vertex at the end—and vertices may be supplied as objects with x and y fields or as two-element arrays.
How the even-odd ray casting test works
Start with a finite query point with coordinates x and y and an ordered list of at least three planar vertices that form a simple closed polygon when consecutive vertices are connected and the last vertex joins back to the first. The algorithm does not require you to choose clockwise or counter-clockwise order; both orientations are valid under the even-odd rule. From the query point, imagine a horizontal ray that travels only to the right, never to the left.
Walk every edge of the polygon and decide whether that edge crosses the ray. Horizontal edges are ignored so they do not create ambiguous double counts. If the query x lies strictly left of that intersection, the edge contributes one crossing; if the intersection coincides with the query within a tiny numerical tolerance, the point is classified as lying on the boundary.
After all edges are processed, an odd crossing count means the point is inside and an even count means outside, which is the classic Jordan-curve parity argument specialized to a horizontal ray. Coordinates must be finite; NaN and Infinity are rejected. Degenerate rings with fewer than three vertices are rejected with invalid input rather than silently treating a line segment as a polygon.
Where point-in-polygon checks show up in real work
Logistics and delivery products ask whether a courier GPS fix falls inside a neighborhood polygon before offering a zone-specific rate, and they need a deterministic answer that does not drift between the browser map preview and the server. Games and interactive media use axis-aligned or free-form collision masks defined as vertex rings and test player or projectile positions every frame without pulling a heavy GIS stack.
Classroom computational geometry modules teach ray casting, the Jordan curve theorem intuition, and floating-point edge cases; a single trusted oracle that returns both the inside flag and the raw crossing count helps students verify homework step by step. Urban planning and cadastral tools classify sample points against building footprints or zoning polygons during early design reviews when full topology databases are not yet connected.
If you later need polygon perimeter, polygon area, great-circle geodesy, multipolygon holes with the nonzero winding rule, or spherical containment on the WGS84 ellipsoid, treat those as separate search intents and landings rather than overloading this planar point-in-polygon checker page.
What you can do with it
Geofence membership for logistics
Classify GPS or map-click points against delivery zones and neighborhood polygons with a deterministic inside flag shared by browser previews and backend pricing.
Game and UI hit testing
Test whether a cursor, player, or projectile lies inside a free-form polygonal mask without importing a full GIS library into the client.
FAQ
What algorithm does this point-in-polygon checker use?
Even-odd ray casting: a horizontal half-line from the query point counts crossings with polygon edges; odd means inside, even means outside.
What happens if the polygon has fewer than three vertices?
A polygon needs at least three vertices; a segment or single point is not a valid ring for containment.
Does vertex order matter (clockwise vs counter-clockwise)?
Either orientation works under the even-odd rule. Order must still be sequential around the boundary; scrambling vertices produces a different (usually self-intersecting) shape.
What does it cost?
The browser tool is free and runs locally.
What if the point sits exactly on the edge?
A point exactly on an edge or a vertex counts as inside, and the result also marks it as lying on the boundary, so a marker placed on the fence line is treated as contained.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/geo/point-in-polygon \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"x":1,"y":1,"polygon":[{"x":0,"y":0},{"x":4,"y":0},{"x":4,"y":3},{"x":0,"y":3}]}'const res = await fetch("https://api.kit.forhosting.com/geo/point-in-polygon", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"x": 1,
"y": 1,
"polygon": [
{
"x": 0,
"y": 0
},
{
"x": 4,
"y": 0
},
{
"x": 4,
"y": 3
},
{
"x": 0,
"y": 3
}
]
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/geo/point-in-polygon",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"x": 1,
"y": 1,
"polygon": [
{
"x": 0,
"y": 0
},
{
"x": 4,
"y": 0
},
{
"x": 4,
"y": 3
},
{
"x": 0,
"y": 3
}
]
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/geo/point-in-polygon", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"x":1,"y":1,"polygon":[{"x":0,"y":0},{"x":4,"y":0},{"x":4,"y":3},{"x":0,"y":3}]}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"x":1,"y":1,"polygon":[{"x":0,"y":0},{"x":4,"y":0},{"x":4,"y":3},{"x":0,"y":3}]}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/geo/point-in-polygon", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"x": 1,
"y": 1,
"polygon": [
{
"x": 0,
"y": 0
},
{
"x": 4,
"y": 0
},
{
"x": 4,
"y": 3
},
{
"x": 0,
"y": 3
}
]
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "geo.point_in_polygon",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
When fewer than three vertices are provided the request fails with a clear validation error, because a polygon needs at least a triangle.
How the even-odd ray casting test works
When an edge straddles the ray height—one endpoint strictly above the query y and the other not—the exact x of the intersection is computed with a linear parameter along the edge. Boundary hits short-circuit to inside with on_boundary true so markers drawn on the fence line count as contained. The entire pipeline is deterministic floating-point arithmetic: no random seeds, no wall-clock timestamps, no network calls, and no model drift, so identical inputs always produce identical JSON.
What you send and what you get back
Send the test point as required numeric fields x and y, and the polygon as a required array under the field polygon with at least three vertices. Optional nested point objects are supported for clients that already package the query as a single structure. Each vertex may be an object with x and y or an array of two numbers; aliases vertices and points are also accepted for the ring. Missing fields, non-numeric strings, NaN, and Infinity fail with invalid_input and are not charged. When the polygon array has length zero, one, or two, the request fails with a message that a point-in-polygon test needs at least three vertices, so callers can fix the geometry instead of guessing. On success the response includes inside as a boolean, on_boundary as a boolean, a cleaned point object, the cleaned polygon array, n as the vertex count, crossings as the integer ray-edge count used by the parity test, method set to ray_casting, and rule set to even_odd. Typical smoke checks include a unit square with a query at one comma one which is inside, a query far outside the square which is outside, and a triangle with a point on a side which is inside with on_boundary true. Pricing for successful API calls is the published base of $0.002 per item; validation failures do not consume prepaid balance.
Where point-in-polygon checks show up in real work
Because this capability is a pure parse engine, API pricing is the published base of $0.002 per successful item and failed validation does not consume balance.
Integration use cases
Classroom computational geometry
Demonstrate ray casting, parity, and boundary edge cases with stable JSON that includes crossing counts for step-by-step verification.
Technical questions
Are points on the edge counted as inside?
Yes. If the query lies on an edge or vertex within a tiny numerical tolerance, inside is true and on_boundary is true.