# GIS Format Converter: Shapefile, GeoJSON, KML, GPX, WKT & CSV (`nibble/geo-format-converter`) Actor

Convert vector GIS data between Shapefile, GeoJSON, KML, KMZ, GPX, WKT and CSV, with optional EPSG reprojection. Deterministic, no GDAL, no scraping.

- **URL**: https://apify.com/nibble/geo-format-converter.md
- **Developed by:** [Simon Fletcher](https://apify.com/nibble) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 dataset converteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### What does GIS Format Converter do?

**GIS Format Converter converts vector geospatial data between the formats GIS teams actually
use** — **Shapefile (.zip)**, **GeoJSON**, **KML**, **KMZ**, **GPX**, **WKT** and
**CSV-with-geometry** — and can optionally **reproject** coordinates from one **EPSG** CRS to
another (for example WGS84 `4326` → Web Mercator `3857`, or → British National Grid `27700`).
It runs entirely on data **you supply** (URL, uploaded file, inline text, or base64) — it does
**not** scrape any website, needs **no login**, and touches **no personal data**.

Because it runs on the [Apify platform](https://apify.com/actors), you get an HTTP **API**,
**scheduling**, **integrations** (Make, Zapier, n8n), and **[MCP](https://mcp.apify.com/) access
for AI agents** — turning a fiddly command-line `ogr2ogr` step into a callable cloud endpoint.
The engine is pure Python (shapely + pyproj + pyshp), so conversions are **deterministic** and
there is **no GDAL install** to babysit.

### Why use GIS Format Converter?

- **Interoperability:** move data between tools that each demand a different format — QGIS,
  Google Earth, Garmin/Strava (GPX), PostGIS (WKT), spreadsheets (CSV), web maps (GeoJSON).
- **Reprojection on the fly:** get coordinates in the CRS your map or database expects without
  opening a desktop GIS.
- **Automation & AI agents:** call it from a pipeline or an LLM agent to normalize incoming
  geodata to one canonical format (usually GeoJSON) before further processing.
- **No-toolchain conversion:** no GDAL, no local installs, no CLI — just JSON in, structured
  JSON + a downloadable file out.

### How to use GIS Format Converter

1. Open the **Input** tab.
2. Provide your data one of four ways: paste **inline text** (GeoJSON/KML/GPX/WKT/CSV), add a
   **file URL**, **upload a file** (passed via a key-value-store key), or send **base64** for
   binary inputs (Shapefile `.zip`, KMZ).
3. Choose a **Target format** (e.g. `geojson`).
4. *(Optional)* set a **Target CRS (EPSG code)** to reproject; set the **Source CRS** if the
   input's own CRS is unknown or missing.
5. Click **Start**. Each converted file appears as one row in the **Output** dataset, and the
   converted file itself is saved to the run's **key-value store** for download.

### Input

| Field | Type | Description |
|-------|------|-------------|
| `targetFormat` | string | Output format: `geojson`, `kml`, `kmz`, `gpx`, `wkt`, `csv`, `shapefile`. |
| `fileUrls` | array | Public URLs of GIS files to download and convert. |
| `keyValueStoreKeys` | array | Keys of uploaded files in the run's key-value store. |
| `inlineData` | array | Inline text payloads (GeoJSON/KML/GPX/WKT/CSV). |
| `base64Data` | array | Base64 payloads for binary inputs (Shapefile `.zip`, KMZ). |
| `sourceFormat` | string | Force the input format (else auto-detected). |
| `sourceEpsg` | integer | EPSG code of the input coordinates (else read from the file or `4326`). |
| `targetEpsg` | integer | EPSG code to reproject the output to (blank = no reprojection). |
| `coordinatePrecision` | integer | Decimal places for output coordinates (default `6`). |
| `geometryColumn` / `latColumn` / `lonColumn` / `csvDelimiter` | string | CSV parsing hints. |

#### Input example

```json
{
  "targetFormat": "geojson",
  "inlineData": ["POINT (-0.1276 51.5074)\nPOINT (2.3522 48.8566)"],
  "targetEpsg": 3857,
  "coordinatePrecision": 2
}
```

### Output

Each input file becomes **one dataset item**. You can download the dataset as JSON, CSV, Excel
or HTML, and each converted file is also saved to the key-value store (see
`output.keyValueStoreKey`).

```json
{
  "source": "inlineData[0]",
  "status": "ok",
  "sourceFormat": "wkt",
  "targetFormat": "geojson",
  "featureCount": 2,
  "geometryTypes": ["Point"],
  "sourceCrs": "EPSG:4326",
  "targetCrs": "EPSG:3857",
  "reprojected": true,
  "bbox": [-14204.37, 6250564.35, 261845.71, 6711542.48],
  "output": {
    "format": "geojson",
    "filename": "converted.geojson",
    "encoding": "text",
    "content": "{\"type\":\"FeatureCollection\", ...}",
    "byteSize": 214,
    "keyValueStoreKey": "output-0-converted.geojson"
  },
  "features": [
    { "geometry": { "type": "Point", "coordinates": [-14204.37, 6711542.48] }, "properties": {} },
    { "geometry": { "type": "Point", "coordinates": [261845.71, 6250564.35] }, "properties": {} }
  ],
  "meta": { "engine": "shapely+pyproj+pyshp", "coordinatePrecision": 2, "detectedSourceEpsg": null }
}
```

#### Output fields

| Field | Description |
|-------|-------------|
| `source` | Which input this record came from. |
| `status` | `ok` or `error`. |
| `sourceFormat` / `targetFormat` | Formats converted from/to. |
| `featureCount` | Number of vector features converted (billed only when > 0). |
| `geometryTypes` | Distinct geometry types (Point, LineString, Polygon, …). |
| `sourceCrs` / `targetCrs` | Input/output CRS as `EPSG:<code>`. |
| `reprojected` | Whether coordinates were transformed. |
| `bbox` | `[minX, minY, maxX, maxY]` in the target CRS. |
| `output` | The converted file (content + downloadable key-value-store key). |
| `features` | Normalized GeoJSON features — an agent-friendly structured view. |

### Supported conversions

Any listed source format converts to any listed target format. GPX output supports Point and
LineString geometries; Shapefile output requires a single geometry family per file (all points,
all lines, or all polygons) per the shapefile specification.

| | Shapefile | GeoJSON | KML | KMZ | GPX | WKT | CSV |
|--|--|--|--|--|--|--|--|
| **In** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| **Out** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |

### Pricing / cost estimation

This Actor uses **pay-per-event**: you are charged **once per non-empty converted file**
(`featureCount > 0`). Empty or failed inputs are **never** billed, and the run honors any
max-charge cap you set. Compute per file is tiny (well under a second of work), so cost is driven
by the per-result event, not by CPU time. See the Console pricing tab for the current rate.

### Tips & advanced options

- **Batch** many files in one run (multiple `fileUrls` / `inlineData` entries) to amortize
  container startup.
- **CRS not in the file?** Set `sourceEpsg` explicitly — KML/GPX are always WGS84 (`4326`);
  Shapefiles carry a `.prj`; GeoJSON defaults to `4326` per RFC 7946.
- **Protect precision:** raise `coordinatePrecision` for projected/metric CRSs where you need
  sub-metre accuracy.
- **CSV geometry:** the Actor auto-detects a WKT column (`wkt`/`geometry`/`geom`) or
  latitude/longitude columns; override with `geometryColumn` / `latColumn` / `lonColumn`.

### FAQ, disclaimers & support

- **Does it scrape anything?** No. It only transforms data you provide. No login, no PII.
- **Do I need GDAL/ogr2ogr?** No. The engine is pure Python and self-contained.
- **What about 3D/Z coordinates and .gml/.gpkg?** The current version converts 2D X/Y vector
  geometry across the seven listed formats; GeoPackage/GML are not yet supported.
- **Found a bug or need another format?** Open the **Issues** tab on the Actor page — custom
  format/CRS support can be added on request.

# Actor input Schema

## `targetFormat` (type: `string`):

The format to convert every input file into.

## `fileUrls` (type: `array`):

Public URLs of GIS files to convert. Each is downloaded (with retries). Format is auto-detected from the extension/content; override with 'sourceFormat' if needed.

## `keyValueStoreKeys` (type: `array`):

Keys in this run's default key-value store that hold GIS file bytes. This is how files uploaded via the Console form are passed to the Actor.

## `inlineData` (type: `array`):

Raw text payloads passed inline — for GeoJSON, KML, GPX, WKT or CSV. Convenient for API or AI-agent callers.

## `base64Data` (type: `array`):

Base64-encoded payloads passed inline — for binary inputs (Shapefile .zip, KMZ). Convenient for API or AI-agent callers.

## `sourceFormat` (type: `string`):

Force the input format instead of auto-detecting. Leave blank to auto-detect from extension/content.

## `sourceEpsg` (type: `integer`):

EPSG code of the INPUT coordinates. Leave blank to use the file's own CRS (from a shapefile .prj or GeoJSON crs member) or default to WGS84 (4326).

## `targetEpsg` (type: `integer`):

EPSG code to reproject the OUTPUT to (e.g. 3857 for Web Mercator, 27700 for British National Grid). Leave blank for no reprojection.

## `coordinatePrecision` (type: `integer`):

Decimal places to round output coordinates to. 6 (~0.11 m at the equator) is a good default for lat/lon.

## `includeFeatures` (type: `boolean`):

The converted file is always saved to the run's key-value store (and linked from each record). By default the dataset record embeds only a small preview of the parsed GeoJSON features to keep records small (the full geometry is already in the saved file). Enable this to embed the complete 'features' array in every record instead.

## `geometryColumn` (type: `string`):

For CSV input: the name of the column holding WKT geometry. Leave blank to auto-detect (wkt/geometry/geom) or use latitude/longitude columns instead.

## `latColumn` (type: `string`):

For CSV input with point coordinates: the latitude column name. Leave blank to auto-detect (lat/latitude/y).

## `lonColumn` (type: `string`):

For CSV input with point coordinates: the longitude column name. Leave blank to auto-detect (lon/lng/longitude/x).

## `csvDelimiter` (type: `string`):

For CSV input: the column delimiter. Leave blank to auto-detect comma, semicolon, tab or pipe.

## Actor input object example

```json
{
  "targetFormat": "geojson",
  "fileUrls": [
    {
      "url": "https://raw.githubusercontent.com/johan/world.geo.json/master/countries/USA.geo.json"
    }
  ],
  "inlineData": [
    "POINT (-0.1276 51.5074)\nPOINT (2.3522 48.8566)"
  ],
  "sourceFormat": "",
  "coordinatePrecision": 6,
  "includeFeatures": false
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "fileUrls": [
        {
            "url": "https://raw.githubusercontent.com/johan/world.geo.json/master/countries/USA.geo.json"
        }
    ],
    "inlineData": [
        "POINT (-0.1276 51.5074)\nPOINT (2.3522 48.8566)"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("nibble/geo-format-converter").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "fileUrls": [{ "url": "https://raw.githubusercontent.com/johan/world.geo.json/master/countries/USA.geo.json" }],
    "inlineData": ["""POINT (-0.1276 51.5074)
POINT (2.3522 48.8566)"""],
}

# Run the Actor and wait for it to finish
run = client.actor("nibble/geo-format-converter").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "fileUrls": [
    {
      "url": "https://raw.githubusercontent.com/johan/world.geo.json/master/countries/USA.geo.json"
    }
  ],
  "inlineData": [
    "POINT (-0.1276 51.5074)\\nPOINT (2.3522 48.8566)"
  ]
}' |
apify call nibble/geo-format-converter --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nibble/geo-format-converter"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/pk0BghJIV0l6WdEAd/builds/sAs0hb2ftbgS493pN/openapi.json
