GeoJSON to CSV Converter
A GeoJSON to CSV converter turns a FeatureCollection into a spreadsheet. This one gives Point features real latitude and longitude columns, keeps every line and polygon's full shape in a WKT column rather than reducing it to a single vertex, flattens nested properties with dot notation, and keeps the feature id. Nothing is uploaded and nothing is silently dropped.
Want to filter, join or chart the result? Open the app
The problem is that a table has no shape
GeoJSON is a tree. A CSV is a rectangle. Most of the work in going between them is deciding what to do with the parts of the tree that do not fit, and there are only two honest answers: write them down in a form a cell can hold, or say that you dropped them. Every converter that quietly does neither is the reason people end up writing their own.
Two things in a FeatureCollection do not fit a rectangle. The first is the geometry of anything that is not a Point. A Polygon is a list of rings, each ring a list of positions, and there is no sensible pair of numbers that represents it. The second is the property bag, which is arbitrary JSON and can nest as deep as whoever built the API felt like nesting it.
The common shortcut for geometry is to take the first coordinate of whatever shape is there and call it the location. It produces a tidy table and it throws the shape away. Open the result in QGIS and your municipal boundaries have become a handful of dots in the corners of the districts they used to outline. Nothing warns you, because from the converter's point of view it did produce a latitude and a longitude.
The other shortcut is to write every geometry as a WKT string, including points. That loses nothing, and it makes the 90% case worse: a file of 4,000 stores comes back with a column of POINT (-0.1276 51.5072) text that Excel cannot plot, pandas cannot do arithmetic on, and a database load has to unpick.
What this one does instead
Points get real numeric columns. Everything else keeps its full geometry as WKT. A geometry column names the type of each row, so a file that mixes the two is still readable as a table and you can filter on it.
Take a small collection of parks, one of them a trail and one of them a square:
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "id": "GGP",
"properties": {
"name": "Golden Gate Park",
"hectares": 412,
"contact": { "office": "McLaren Lodge", "phone": "415-831-2700" }
},
"geometry": { "type": "Point", "coordinates": [-122.4862, 37.7694, 61.5] } },
{ "type": "Feature",
"properties": { "name": "Presidio Coastal Trail" },
"geometry": { "type": "LineString",
"coordinates": [[-122.475, 37.805], [-122.4805, 37.8021]] } }
]
}
comes back as:
geometry,longitude,latitude,elevation,wkt,id,name,hectares,contact.office,contact.phone
Point,-122.4862,37.7694,61.5,,GGP,Golden Gate Park,412,McLaren Lodge,415-831-2700
LineString,,,,"LINESTRING (-122.475 37.805, -122.4805 37.8021)",,Presidio Coastal Trail,,,
The park has usable coordinates and an elevation from the third ordinate. The trail's two vertices are both in the wkt cell, ready for ST_GeomFromText or GeoPandas' from_wkt. The nested contact object became two dotted columns. The feature id, which lives outside properties in the spec and is the thing most likely to be the join key, has its own column.
Columns are only created when something needs them. A file of nothing but points has no wkt column at all, and a file with no third ordinate has no elevation column. Six empty columns on every export is clutter, and clutter is what makes people distrust the tool.
Nested properties, and where the line is
Properties are flattened with dot notation, four levels deep. That is the same flattener the JSON converters on this site use, so a nested object behaves identically wherever you meet it. properties.address.city becomes a column called address.city, and the properties prefix is dropped because every column would carry it and it says nothing.
Two shapes stop the flattening. A list of objects, such as a features array of opening hours, cannot become columns without inventing rows, so the cell keeps the JSON text. Nesting past four levels does the same. Both are counted in the warnings, so you know a cell holds JSON before you try to sum it.
A property whose name collides with one of the geometry columns is renamed rather than allowed to overwrite. A dataset with a property literally called latitude, which happens more often than you would think in files that have already been round-tripped once, gets latitude_property alongside the real one. Two different numbers under one heading is the worst outcome available.
Files that are not quite GeoJSON
Three things arrive claiming to be GeoJSON and are not exactly. All three are handled, and all three say so.
A collection wrapped in an envelope. Plenty of APIs return {"status": "ok", "data": {"type": "FeatureCollection", ...}}, and a strict reader refuses it. The common wrapper keys are checked, and the warning tells you where the collection was found so you know the endpoint is not returning what its documentation says.
A bare geometry with no Feature around it. Legal, and it means there are no properties, which the warning states plainly rather than leaving you to wonder why the table has three columns.
A feature with "geometry": null. This is legal GeoJSON and it usually means a record that failed geocoding. Those rows stay in the table with their properties and empty coordinates, because a list of the addresses that could not be located is often the whole reason someone is exporting to CSV. The count is reported.
What is not handled quietly is a file that is not JSON at all. That fails immediately with the parser's own message about where the syntax broke, which is more useful than a generic complaint. If you have a GeoJSON Text Sequence, the newline-delimited variant, split it and convert one record at a time, or bring it to the JSON Lines converter first.
Questions
What happens to a polygon when there is only one row for it?
Its full outline is written into a wkt column as a POLYGON literal, so nothing is lost. The alternative that most converters pick, taking the first vertex and calling it the location, throws the shape away silently. The latitude and longitude columns are left empty for non-point features, and a geometry column says what each row actually is, so a mixed file is still readable as a table.
How are nested properties handled?
Flattened with dot notation. A property object holding contact with a phone inside it becomes a column named contact.phone. Nesting is followed four levels deep, which covers everything that arrives from a real API, and anything deeper or any list of objects is kept as JSON text in its cell rather than being dropped. The warnings say when that happened.
Does the feature id survive?
Yes. RFC 7946 allows an id beside the properties object rather than inside it, and it is usually the key that joins the geometry back to whatever system produced it. It comes through as an id column. If a property is also called id, the two are kept apart rather than one overwriting the other.
Which way round are the coordinates?
GeoJSON stores them longitude first, and the CSV writes separate latitude and longitude columns, correctly labelled. That is the point of the conversion: the ordering trap disappears the moment the values have names. If the source had a third ordinate, it comes through as an elevation column, and if it did not, there is no elevation column at all.
What if the FeatureCollection is nested inside another object?
It is found. Some APIs wrap the collection under a data, result or geojson key rather than returning it at the top level. Those wrappers are checked, and a warning says where the collection was found so you know the file was not quite what it claimed. A bare geometry with no Feature around it is also accepted, with a note that there are no properties to put in columns.
What happens to a feature whose geometry is null?
It stays in the table. A null geometry is legal GeoJSON and usually means a record that failed geocoding, which is exactly the row you want to see. Its properties come through as normal and the coordinate columns are empty. The count of such features is reported so you know how many of your rows have no location.
Is the file uploaded?
No. Parsing and conversion happen in your browser tab. Nothing is sent to a server, nothing is kept between visits, and there is no row cap. Location data is often sensitive, which is a good reason to prefer a tool that cannot see it.
Related
Convert your GeoJSON to CSV
No sign-up, no upload, no row cap. Coordinate columns for points, WKT for everything else, nothing dropped without a word.
Back to the converter