πΊοΈ Format Conversion Β· 8 min read
CSV to KML: Plot a CSV of Coordinates on Google Earth
If you are going to Google My Maps, you may not need KML at all: My Maps imports a CSV with a latitude and longitude column directly, up to 2,000 rows. You need a KML file when the destination only reads KML, which includes Google Earth, most GIS tools, and a deliverable you send to somebody else as one layer. Either way the hard part is the same: your spreadsheet almost certainly lists latitude first, and KML wants longitude first.
That single ordering rule accounts for most of the "my pins are in the ocean" reports. The rest are degrees-minutes-seconds left unconverted, a sign dropped from a western longitude, or a file over the row limit that imported without complaint and lost half its points.
First, Check Whether You Need KML at All
Google's My Maps help page lists the file types it accepts: CSV, TSV, KML, KMZ, GPX, XLSX and Google Sheets. For a CSV it needs one column it can position a point from, and it accepts any of these:
- a latitude column and a longitude column
- a full address, which it geocodes
- a place name
- a WKT geometry column literally named
WKT
The same page gives the limits in plain numbers: do not import files with more than 2,000 rows, unzipped KML and KMZ files can be up to 5 MB, and other file types up to 40 MB. If your CSV is 40,000 delivery stops, My Maps is the wrong tool regardless of format; you want a real GIS layer, or several maps split by region.
So the decision tree is short. Sharing a quick view with a colleague: upload the CSV to My Maps. Handing a file to a client, opening it in Google Earth, feeding a CAD or GIS workflow, or archiving one self-contained layer: build KML.
The Coordinate Order Trap
Google's KML reference defines a <coordinates> tuple as "floating point values for longitude, latitude, and altitude (in that order)", with longitude between -180 and 180 and latitude between -90 and 90, no spaces between the values. Longitude first. Always.
Now look at a typical CSV exported from a phone app, a fleet tracker or a CRM with a geocoding step. The columns are usually Latitude, Longitude, in that order, because that is how people say it. Concatenate them in column order and every point is mirrored across the diagonal. The map still renders. It just shows your London depot somewhere in the Indian Ocean, and the first reaction is to blame the data.
Two cheap checks catch it before anyone sees the map. Confirm that the first number in every tuple is between -180 and 180 and the second between -90 and 90: if the "longitude" column tops out at 90 or the "latitude" column goes past 90, the columns are swapped. Then plot one known point, a head office with an address you can check, and see if it lands on the right street.
The Smallest KML File That Works
KML is XML with a namespace, a Document, and one Placemark per point. This is the whole structure:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>Depots</name>
<Placemark>
<name>Bristol</name>
<description>Orders: 142</description>
<Point>
<coordinates>-2.5879,51.4545,0</coordinates>
</Point>
</Placemark>
</Document>
</kml>Read that coordinate again: -2.5879 is longitude, 51.4545 is latitude, and 0 is altitude in metres. Bristol's longitude is negative because it is west of Greenwich; the same file with 2.5879 puts the pin in France.
Keep the namespace exactly as written. A KML file without xmlns="http://www.opengis.net/kml/2.2" is XML that Google Earth may refuse to open, and the error message says nothing useful about namespaces.
A Script That Reads the CSV and Writes the KML
Fifteen lines, standard library only, no API key:
import csv
from xml.sax.saxutils import escape
marks = []
with open("sites.csv", newline="", encoding="utf-8-sig") as f:
for row in csv.DictReader(f):
lat = float(row["Latitude"])
lon = float(row["Longitude"])
name = escape(row.get("Name", "").strip())
marks.append(
"<Placemark><name>" + name + "</name>"
"<Point><coordinates>" + f"{lon},{lat},0" + "</coordinates></Point>"
"</Placemark>"
)
kml = ('<?xml version="1.0" encoding="UTF-8"?>'
'<kml xmlns="http://www.opengis.net/kml/2.2"><Document>'
+ "".join(marks) + "</Document></kml>")
open("sites.kml", "w", encoding="utf-8").write(kml)Note the deliberate reversal: the CSV columns are read as lat and lon by name, then written lon,lat into the tuple. Naming the variables after what they hold is what stops the swap from creeping back in when the file changes.
escape() handles the ampersands and angle brackets that appear the moment a place name is "Smith & Sons" or a note contains a comparison. Without it the XML is malformed and the failure is a parser error with no line number.
Carrying the Attributes Across
A pin with no data is a dot. If the CSV has order counts, phone numbers or status columns, put them in the Placemark so they travel with the file and show in Google Earth's properties panel:
<Placemark>
<name>Bristol</name>
<ExtendedData>
<Data name="orders"><value>142</value></Data>
<Data name="status"><value>active</value></Data>
</ExtendedData>
<Point><coordinates>-2.5879,51.4545,0</coordinates></Point>
</Placemark>Google Earth renders ExtendedData as a table, which is usually enough for a client review. If a person only needs to read one line about the point, a plain <description> is simpler and shows in the balloon.
Cleaning the Coordinates Before You Convert
Coordinate columns fail in a small number of predictable ways, and all of them produce a map that looks plausible but is wrong.
- Degrees, minutes, seconds.
51Β°30'26"Ncannot go into a coordinates tuple. Convert to 51.5072 first. A converter that accepts the string and returns NaN will usually drop the point silently rather than fail. - Letters in the values.
51.4545 Nand2.5879 Wcarry the hemisphere as a letter instead of a sign, and a naive float conversion throws. Strip the letter and negate when it is S or W. - Missing altitude. The third value is optional.
lon,latis valid;lon,lat,with a trailing comma is not. - Blank rows and duplicate points. A CSV exported from a form has empty rows, and 300 duplicate pins at one address turn the map into a blob. The dirty data clean-up guide covers both, and removing duplicates is a two-minute pass before conversion.
Look at the raw column values before anything else. The CSV analyzer reports each column's inferred type, so a "latitude" column that it reads as text is a signal that letters, degree symbols or stray spaces are in there. A sample file with quoted commas and mixed types is in the CSV example set if you want something to test the script against.
KML or KMZ
KMZ is a zip containing one KML file plus whatever it references, commonly custom icons. A text-only layer is often smaller as plain KML and is readable in any editor, which matters when something looks wrong and you need to inspect the coordinates yourself. Choose KMZ when the layer carries icons or runs into the thousands of placemarks, and when you want a single compact attachment instead of a folder. Rename a .kmz to .zip and unzip it to see exactly what is inside.
Frequently Asked Questions
Do I need KML to put a CSV on a map?
Not for Google My Maps, which imports CSV, TSV, KML, KMZ, GPX, XLSX and Google Sheets as long as one column holds latitude and longitude, an address, a place name, or WKT. You need KML when the destination is Google Earth, a GIS or CAD tool, or a single-layer deliverable you hand to someone else.
Why are my points in the wrong place after converting CSV to KML?
Almost always a latitude and longitude swap. A KML tuple is longitude first, then latitude, then optional altitude. Most CSVs list latitude first, so a straight copy puts the latitude where the longitude belongs.
How many rows can I import into Google My Maps?
Google's help says not to import files with more than 2,000 rows. Unzipped KML and KMZ can be up to 5 MB and other file types up to 40 MB. Beyond that, split the file by region or date.
What coordinate format does KML expect?
Decimal degrees: longitude -180 to 180, latitude -90 to 90, so west and south are negative. No degrees-minutes-seconds. Altitude is optional, in metres. Values in a tuple are comma separated with no spaces.
How do I add name and phone to each point?
Use an ExtendedData block with Data elements inside the Placemark. They travel with the file and appear in Google Earth's properties panel. A short description element is enough if a person only needs to read one line.
CSV, KML or KMZ?
CSV is the working file, KML is the map file, KMZ is KML zipped with its icons and images. Plain KML for text-only layers you may need to inspect; KMZ when icons are involved or the layer is large and you want one attachment.
Check the Coordinate Columns First
The analyzer shows whether your latitude and longitude columns are really numbers, or text hiding degree symbols and hemisphere letters.
Related reading
Format Conversion β other guides that pair well with this one.
- Convert CSV to PDF
- Convert CSV to Excel Without Excel
- Convert Excel to CSV Free Online
- Convert TSV to CSV
Browse all guides in the NoCodeCSV blog.