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

CSV to GeoJSON

Paste a CSV (or drop a .csv file) and get a GeoJSON FeatureCollection. I auto-detect lat/lng (and aliases like longitude, x, y) or pull geometry from a WKT column when you have polygons or lines. Everything runs locally — your data never leaves the browser.

CSV to GeoJSON

updated 8 June 2026

Drop a .csv / .tsv file, or

What this tool does

It turns a CSV into a GeoJSON FeatureCollection — one feature per data row. Each row needs a location: either a longitude/latitude pair or a single WKT geometry column. I find the spatial columns by header name, build the geometry, and carry every remaining column through as feature properties.

The intent it closes: "I have a spreadsheet of places and I need it as GeoJSON I can drop on a map or load into a GIS tool." Everything runs in your browser — I never see your file, and the page works offline once loaded. There's no hard size limit, since the CSV is parsed in a single pass, but tens of millions of rows will eventually exhaust the tab's memory.

How this tool works

One click on Convert runs a four-step pass, entirely in your browser.

1. Read the CSV

I strip a leading Byte Order Mark if there is one, then sniff the delimiter from the first line: I try comma, tab, semicolon, and pipe (|), and pick whichever splits the header into the most columns. Rows are parsed quote-aware, so a cell wrapped in double quotes can hold the delimiter, doubled quotes ("") for an escaped quote, or an embedded newline.

2. Find the spatial columns

I match header names case-insensitively. For longitude I look for lng, lon, long, longitude, x (and the _dd variants); for latitude, lat, latitude, y, lat_dd; for a WKT geometry column, wkt, geometry, geom, the_geom, shape, wkt_geom. If none of those turn up, you can name the column yourself in Options. With no spatial column at all, the status bar shows No spatial columns found. and lists your header so you can see what I saw.

3. Build a geometry per row

For each row I try the WKT column first. WKT supports POINT, LINESTRING, POLYGON, and the MULTI variants, with coordinates written as space-separated lng lat (a Z or M dimension is accepted but dropped). If there's no usable WKT value, I fall back to the lng/lat pair — both must be finite numbers — and emit a Point. Coordinates always come out as [longitude, latitude], the GeoJSON order. Cells that are blank or read as null, n/a, na, or none (any case) count as empty. A row with no valid geometry is skipped rather than turned into a broken feature.

4. Assemble properties and report

Every column that isn't the chosen lng, lat, or WKT column becomes a property on the feature, value left exactly as it appears in the CSV. The features are wrapped in a FeatureCollection and written to the output pane. The status bar sums it up — Converted. Features: N · K row(s) skipped · WKT col: … / Coords: lng/lat · Delimiter: … — and the result is stashed in your session, so you can hop straight to the Viewer.

Options

Leave all three boxes on auto and I detect the columns by name. Fill one in when your header isn't on the list above.

lng col / lat col

Type the exact header for your longitude and latitude columns when they use names I don't recognize — POINT_X/POINT_Y, centroid_lon, or a localized label. The match is case-insensitive, and leading or trailing spaces in the header are tolerated because I trim both sides.

WKT col

Set this when your geometry column has a non-standard name. WKT takes precedence over lng/lat on a per-row basis: if a row has a valid WKT value I use that; if it's blank or unparseable, I fall back to the lng/lat pair for that row.

Example

Input (CSV with mixed Point + Polygon data via WKT):

name,population,wkt
Lake,0,"POLYGON((-122.5 37.7,-122.4 37.7,-122.4 37.8,-122.5 37.8,-122.5 37.7))"
Coffee Shop,1,"POINT(-122.4 37.7)"

Output (GeoJSON):

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": { "name": "Lake", "population": "0" },
      "geometry": {
        "type": "Polygon",
        "coordinates": [[[-122.5,37.7],[-122.4,37.7],[-122.4,37.8],[-122.5,37.8],[-122.5,37.7]]]
      }
    },
    {
      "type": "Feature",
      "properties": { "name": "Coffee Shop", "population": "1" },
      "geometry": { "type": "Point", "coordinates": [-122.4, 37.7] }
    }
  ]
}

Notice that the spatial column (wkt) is consumed by the geometry and removed from properties, while everything else carries through verbatim.

Tips & common pitfalls

  • Coordinate order is the #1 footgun. CSV exports vary wildly — some use lat, lng, some use lng, lat. I match by column name, not position, so as long as your header is honest, the output is correct. If your points show up off Madagascar instead of in Texas, you probably mislabeled a column.
  • Numbers in quotes are fine. A cell like "-122.4" parses cleanly. Locale-formatted numbers like -122,4 (European decimals) do not — convert those to dot-decimals first.
  • Null-ish values are tolerated. Cells equal to null, n/a, na, or none (any case) are treated as missing. Rows with no usable geometry are skipped — and counted in the status bar — instead of producing broken features.
  • WKT with Z/M ordinates. If you have POINT Z(1 2 3) or POINT M, the Z/M flag is recognized but only X and Y are kept. Add an elevation property column if you need to preserve altitude.
  • Property values stay as strings. CSV has no real type system, so I leave numbers and booleans as strings. If your downstream tool needs typed properties, transform them after the conversion.

Troubleshooting

"No spatial columns found."

Your header row doesn't include any of the auto-detected names. Either rename the columns to lat/lng (or wkt), or type the actual header text into the override boxes above the panes. The error message echoes your header so you can confirm what the parser read.

The status bar says "N row(s) skipped."

Those rows had blank, non-numeric, or unparseable geometry. Open the original CSV at the reported row count to see what went wrong — common causes are stray summary rows at the bottom or empty cells where coordinates should be.

Output is one giant feature per cell.

Your CSV is probably tab- or semicolon-separated and the delimiter sniff picked wrong on the first line. Try saving it as proper comma-CSV from your spreadsheet, or set the explicit override columns so the picker doesn't matter.

Polygons look like a tangled mess on the map.

WKT polygons must close (last vertex = first vertex). A few exporters drop the closing point. Fix that in the source, or post-process the GeoJSON with the Simplify tool, which often heals minor issues.

FAQ

What delimiters are supported?

Comma, tab, semicolon, and pipe (|). The parser picks whichever splits your header row into the most columns. If the auto-detect picks wrong, save the file with explicit commas.

Does it handle quoted cells with commas or newlines?

Yes. Cells wrapped in double quotes can contain the delimiter, doubled quotes ("") for an escaped quote, and embedded newlines. The output stays intact.

What if my CSV has many millions of rows?

The conversion happens in browser memory, so the practical ceiling is a few hundred MB on a typical laptop. For very large datasets I'd convert in chunks or use a CLI like ogr2ogr on your machine.

Why are my numeric properties strings in the output?

CSV is type-less; I don't guess. If you need numbers as numbers, run a small post-processing pass with jq or any JSON tool, or use the Formatter to inspect first.

Is my file uploaded anywhere?

No. The whole conversion is JavaScript in your tab. Disconnect your network and it still works.