KunYu
epsgcoordinate-conversionproj4crs

Convert Coordinates Between EPSG Systems

Learn how to convert coordinates between EPSG coordinate systems using proj4js, pyproj, and ogr2ogr, with practical examples for WGS 84, Web Mercator, UTM, and China CRS.

KunYu TeamMarch 25, 202612 min read

You receive a set of GPS survey points in WGS 84 and need to overlay them on a site plan projected in UTM Zone 50N. You paste the coordinates, and the points land in the middle of the ocean — thousands of kilometers off. The numbers look similar enough that you almost trust them, but the coordinate systems are fundamentally incompatible without conversion. Converting coordinates between EPSG systems is one of the most common GIS operations, and getting it wrong produces errors that range from invisible (a few meters) to catastrophic (a different continent).

EPSG coordinate conversion transforms point coordinates from one coordinate reference system to another using mathematically defined datum transformations and map projections. Below: the code to do it in JavaScript, Python, and the command line, plus the mistakes that silently corrupt your data.

What Is Coordinate Conversion and When Do You Need It?

Coordinate conversion reprojects point data from one CRS to another. You need it whenever you combine datasets collected in different coordinate systems, display GPS data on a web map, convert between geographic (degrees) and projected (meters) coordinates, or work with China's offset coordinate systems like GCJ-02 and BD-09.

Two operations are often conflated. Coordinate conversion changes the map projection while staying on the same datum, for example converting WGS 84 geographic coordinates (EPSG:4326) to WGS 84 / UTM Zone 50N (EPSG:32650). Coordinate transformation changes the datum itself. Converting NAD27 to WGS 84 involves physical model parameters because the two datums define the Earth's shape differently. Most GIS libraries handle both transparently, but the distinction matters when you're debugging precision issues.

The five scenarios where you'll reach for a coordinate converter:

  1. Merging datasets from different CRS — a contractor delivers survey data in a national grid (say OSGB 1936, EPSG:27700) and you need to combine it with your WGS 84 baseline.
  2. GPS to web map — raw GPS output is WGS 84 (degrees), but web maps render in Web Mercator (meters). Every tile-based map does this conversion under the hood.
  3. Delivering survey data in a client-required CRS — the client's CAD system expects Lambert-93 (EPSG:2154); your field equipment records in WGS 84.
  4. Working with China maps — Amap, Tencent Maps, and Baidu Maps each use proprietary offset CRS (GCJ-02 and BD-09) that are not interchangeable with WGS 84.
  5. UTM zone conversions — a project spans two UTM zones, and you need a single projected CRS for consistent distance and area calculations.

How to Convert EPSG:4326 to EPSG:3857

To convert from EPSG:4326 (WGS 84, degrees) to EPSG:3857 (Web Mercator, meters), apply the Mercator projection formula. In JavaScript, use proj4("EPSG:4326", "EPSG:3857", [lng, lat]). In Python, use Transformer.from_crs("EPSG:4326", "EPSG:3857", always_xy=True). The conversion maps longitude/latitude to easting/northing in meters.

Using Beijing as an example:

// JavaScript — proj4js
import proj4 from "proj4";

const [easting, northing] = proj4(
  "EPSG:4326",
  "EPSG:3857",
  [116.4074, 39.9042] // Beijing (lng, lat)
);
console.log(easting, northing);
// → 12958175.0, 4852834.1
# Python — pyproj
from pyproj import Transformer

transformer = Transformer.from_crs("EPSG:4326", "EPSG:3857", always_xy=True)
easting, northing = transformer.transform(116.4074, 39.9042)
print(easting, northing)
# → 12958175.0, 4852834.1

The input is two small numbers (degrees). The output is two large numbers (meters from the origin at 0°N, 0°E). This is expected — Web Mercator measures distance from the intersection of the equator and the Prime Meridian.

One thing to watch: EPSG:3857 clips at approximately ±85.06° latitude. The Mercator projection maps the poles to infinity, so coordinates above 85°N or below 85°S cannot be represented. Arctic and Antarctic data requires a polar stereographic projection like EPSG:3413 (North) or EPSG:3031 (South) instead.

You can verify any conversion instantly in KunYu's coordinate converter — paste coordinates, select source and target CRS, and get results without installing anything.

Converting Between Any Two EPSG Codes

The same pattern works for any EPSG pair. For non-built-in codes, you need the CRS definition (a proj4 string or WKT). Libraries like proj4js require you to register custom CRS definitions before using them; pyproj ships with the full EPSG database built in.

JavaScript (proj4js)

Proj4js only knows EPSG:4326 and EPSG:3857 out of the box. Everything else needs a definition string, which you can look up at epsg.io.

import proj4 from "proj4";

// Register Lambert-93 (France) — definition from epsg.io/2154
proj4.defs(
  "EPSG:2154",
  "+proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 " +
    "+x_0=700000 +y_0=6600000 +ellps=GRS80 +units=m +no_defs"
);

// WGS 84 → Lambert-93
const [x, y] = proj4("EPSG:4326", "EPSG:2154", [2.3522, 48.8566]);
console.log(x, y);
// → 652469.5, 6862035.9 (Paris in Lambert-93 meters)

One thing that trips people up: the proj4 definition string must match exactly. I once spent an hour debugging a 3-meter offset in a CGCS2000 projected dataset — turned out the .prj file shipped with the Shapefile used a slightly different ellipsoid parameterization than what epsg.io listed. The fix was to copy the proj4 string directly from the .prj content using gdalsrsinfo input.shp rather than looking up the EPSG code and assuming the definition would match. When precision matters, always derive the definition from the source data itself.

Python (pyproj)

Pyproj ships the full PROJ database, so you never need to register definitions manually. The critical parameter is always_xy=True — without it, pyproj follows the EPSG standard axis order (latitude first for geographic CRS), which swaps your coordinates silently.

from pyproj import Transformer

# pyproj knows all EPSG codes — no manual registration
transformer = Transformer.from_crs("EPSG:4326", "EPSG:2154", always_xy=True)
x, y = transformer.transform(2.3522, 48.8566)
print(x, y)
# → 652469.5, 6862035.9

Command Line (ogr2ogr)

For file-based reprojection of Shapefiles, GeoJSON, or GeoPackage, ogr2ogr from GDAL is the standard tool. It handles batch conversion of entire datasets in a single command.

# Reproject a GeoJSON from WGS 84 to UTM Zone 50N
ogr2ogr -t_srs EPSG:32650 output.geojson input.geojson

# Reproject a Shapefile from OSGB 1936 to WGS 84
ogr2ogr -s_srs EPSG:27700 -t_srs EPSG:4326 output.shp input.shp

Use -s_srs to specify the source CRS explicitly when the input file lacks CRS metadata (no .prj file or embedded projection info). If the source CRS is already defined in the file, -t_srs alone is sufficient.

Converting China Coordinates (WGS 84, GCJ-02, BD-09)

China mandates coordinate offsets on all public map services. GCJ-02 ("Mars Coordinates") shifts WGS 84 points by 100–700 meters using a non-linear algorithm based on the Krasovsky 1940 ellipsoid. BD-09 adds a further offset on top of GCJ-02. These are not EPSG-registered systems, and standard tools like proj4 and pyproj cannot convert them — you need custom offset algorithms.

The offsets exist because China's surveying regulations require all publicly available digital maps to use an encrypted coordinate system. The forward transform (WGS 84 → GCJ-02) is a deterministic formula. The reverse (GCJ-02 → WGS 84) has no closed-form solution and requires iterative approximation — typically 10 iterations to achieve sub-meter accuracy (~0.1m).

Which services use which system:

Map Service Coordinate System Offset from WGS 84
Google Maps (China) GCJ-02 100–700 m
Amap (Gaode) GCJ-02 100–700 m
Tencent Maps GCJ-02 100–700 m
Apple Maps (China) GCJ-02 100–700 m
Baidu Maps BD-09 100–700 m + additional offset
OpenStreetMap WGS 84 None

The conversion chain is: WGS 84 ↔ GCJ-02 ↔ BD-09. Converting directly between WGS 84 and BD-09 without the GCJ-02 intermediate step produces incorrect results. KunYu's coordinate converter implements the full chain with iterative reverse algorithms, something most international GIS tools don't support.

In my experience, the offset is worst in western China — near Urumqi I've seen shifts exceeding 600 meters, which is enough to place a point of interest across a river or on the wrong side of a highway. In eastern coastal cities like Shanghai the offset is smaller (around 200–300 meters) but still far too large to ignore. The subtle trap is that the offset varies smoothly across the country, so you won't catch it by spot-checking a single location — a conversion that "looks right" in Beijing can be noticeably wrong in Chengdu.

Coordinate Converter

Convert coordinates between EPSG systems with batch support and smart detection.

Try it now

Five Common Coordinate Conversion Mistakes

The most frequent coordinate conversion errors are: selecting the wrong source CRS, confusing axis order, using Web Mercator for measurements, ignoring datum transformations, and assuming all degree-based coordinates are WGS 84. Each one produces subtly wrong results that can go unnoticed until they cause real problems downstream.

Wrong Source CRS Selection

If your source data is NAD83 (EPSG:4269) but you tell the converter it's WGS 84 (EPSG:4326), the difference is only ~1–2 meters in most of North America — easy to miss in testing, significant for survey-grade work. Confusing NAD27 with WGS 84 is worse: offsets of 10–200 meters depending on location, enough to place a building on the wrong side of a property line.

Axis Order Confusion (lat/lon vs lon/lat)

EPSG:4326's formal definition is latitude first (lat, lng). But GeoJSON, proj4js, Leaflet's L.latlng() constructor (despite the name), and most web mapping libraries expect longitude first (lng, lat). If your converted points scatter randomly across the map but at roughly the correct scale, you've probably swapped lat and lon. Pyproj's always_xy=True parameter exists specifically to avoid this trap.

Using Web Mercator for Measurements

EPSG:3857 is for display, not computation. Computing area in Web Mercator inflates results at higher latitudes — Greenland appears 14× larger than it actually is. For distance and area calculations, convert to a local projected CRS (a UTM zone or national grid) first, then measure.

Missing Datum Transformations

Converting between CRS that use different datums — for example, ED50 to ETRS89 in Europe — requires a datum transformation with specific parameters. Using a generic or default transformation can introduce errors of several meters. GDAL and pyproj handle this automatically when grid shift files are available, but you should verify the transformation method used.

Assuming All Degree Coordinates Are WGS 84

Many geographic CRS use degrees: EPSG:4326 (WGS 84), EPSG:4269 (NAD83), EPSG:4490 (CGCS2000), EPSG:4612 (JGD2000). A point at 139.6917, 35.6895 could be any of these — they look identical in format but use different datums. Always check the source metadata before converting.

Choosing the Right Tool for Coordinate Conversion

For single or small-batch conversions, browser-based tools are fastest — no installation, no code. For file reprojection, use ogr2ogr or QGIS. For programmatic pipelines, proj4js (JavaScript) or pyproj (Python) integrate directly into your code. For China CRS, most international tools fall short.

Scenario Best Tool Why
Quick single-point check KunYu Coordinate Converter Browser-based, 6000+ EPSG, China CRS included
File reprojection (SHP/GeoJSON) ogr2ogr (GDAL) Any format, batch processing, scriptable
QGIS project Reproject Layer tool GUI workflow, preserves attributes and styling
JavaScript web app proj4js Client-side, ~100KB, no server needed
Python data pipeline pyproj Full PROJ database, NumPy-compatible
China CRS (GCJ-02/BD-09) KunYu Coordinate Converter Built-in offset algorithms most tools lack

For what it's worth, I default to ogr2ogr for anything repeatable. Once I had to reproject 200+ GeoJSON files from a municipal dataset (all in a local Lambert projection) to WGS 84 for a web app. In QGIS, that's 200 manual "Export → Save As → Set CRS" clicks. With ogr2ogr, it was a one-liner shell loop: for f in *.geojson; do ogr2ogr -t_srs EPSG:4326 out/"$f" "$f"; done — done in under a minute. QGIS is better when you need to visually verify the reprojection or when the source CRS isn't embedded in the file and you need to try a few options interactively.

EPSG Search

Search and browse the EPSG coordinate reference system database.

Try it now

FAQ

How Do I Convert EPSG:4326 to UTM?

First, determine which UTM zone your coordinates fall in: zone = floor((longitude + 180) / 6) + 1. Then convert using the corresponding EPSG code — EPSG:326xx for the Northern Hemisphere, EPSG:327xx for the Southern Hemisphere, where xx is the zone number. For example, Beijing at 116.4°E falls in UTM Zone 50N, which is EPSG:32650.

What Is the Difference Between Coordinate Conversion and Coordinate Transformation?

Coordinate conversion changes the map projection while staying on the same datum (e.g., WGS 84 geographic to WGS 84 / UTM). Coordinate transformation changes the datum itself (e.g., NAD27 to WGS 84), which involves physical model parameters. GIS tools like pyproj and GDAL handle both transparently — the distinction matters primarily when debugging precision issues.

Why Are My Converted Coordinates Offset by Hundreds of Meters?

The most common cause is a wrong source CRS. In China, mixing WGS 84 with GCJ-02 produces offsets of 100–700 meters — this is by design, not a bug. Outside China, confusing NAD27 with WGS 84 or using incorrect datum transformation parameters produces similar errors. Always verify your source CRS before converting.

Can I Convert Coordinates in Bulk Without Coding?

Yes. KunYu's coordinate converter accepts multiple coordinates (one per line) for batch conversion directly in the browser — no signup required and your data never leaves your device. For file-based bulk conversion of Shapefiles or GeoJSON, use the format converter tool or ogr2ogr on the command line.

Is proj4js the Same as PROJ?

No. PROJ is a C/C++ coordinate transformation library maintained by the OSGeo community, with a database of 10,000+ CRS definitions and support for grid-based datum transformations. Proj4js is a JavaScript port that implements the same core algorithms but only includes EPSG:4326 and EPSG:3857 by default — all other CRS definitions must be registered manually.

What to Remember

The pattern is always the same: identify your source CRS, identify your target CRS, apply the conversion. For quick checks, use an online converter. For file-level reprojection, reach for ogr2ogr. For application code, embed proj4js or pyproj. And if you're not sure which EPSG code you need, start with EPSG Codes Explained or search directly with the EPSG Search tool.