# EUDR Plot File Fixer: GeoJSON validator and auto-repair (`translucent_wire/eudr-plot-file-fixer`) Actor

EUDR geolocation file rejected? Upload GeoJSON, KML, CSV or Shapefile plots and get back a file that follows the EU Information System rules, with a report of every fix: broken polygons, holes, swapped coordinates, metres, country codes, area. KML to GeoJSON too. About $10 per 1,000 plots.

- **URL**: https://apify.com/translucent_wire/eudr-plot-file-fixer.md
- **Developed by:** [Ghulam Nabi](https://apify.com/translucent_wire) (community)
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 plot processeds

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## EUDR Plot File Fixer: GeoJSON validator and auto-repair

**Did the EU system reject your EUDR geolocation file? Upload it here.** In seconds you get back a GeoJSON file that follows the **EU Deforestation Regulation (EUDR) Information System rules**, plus a plain-language list of every change.

- ✅ **Fixes the mistakes that get plot files rejected:** broken or self-intersecting polygons, holes, swapped latitude and longitude, coordinates in metres, wrong property names, country names instead of ISO codes, area written as text
- 📂 **Reads the files suppliers actually send:** GeoJSON, KML/KMZ (Google Earth), CSV and zipped Shapefiles
- 🔒 **Never guesses:** a plot it can't fix safely is set aside with the reason, so you can ask the supplier
- 💵 **Pay per plot, no subscription:** about **$10 for a 1,000-plot cooperative file**, $0.50 for a 50-plot test

**Why now:** EUDR obligations apply from **30 December 2026** for large and medium companies, and from 30 June 2027 for most micro and small companies. Every due diligence statement needs the geolocation of every plot, and files from farms and cooperatives are often full of errors.

Built for **EU importers, exporters, cooperatives, traders and compliance teams** handling **cocoa, coffee, palm oil, rubber, soy, cattle and wood**.

### What does EUDR Plot File Fixer do?

It reads your plot file, **repairs every mistake that can be repaired safely**, and tells you exactly what it changed. Plots that need a human are never silently altered: they're listed separately with the reason.

| Common problem in supplier files | What the fixer does |
|---|---|
| Self-intersecting ("bow-tie") polygons | Rebuilds a valid shape and reports any change in area |
| Polygon not closed, clockwise ring, repeated points | Closes the ring, turns it counter-clockwise, removes repeats |
| Holes inside polygons (not accepted by the EU system) | Opens each hole to the edge with a 30 cm channel; the hole stays excluded |
| Longitude and latitude in the wrong order | Swaps them when the order is certain, warns when it isn't |
| Coordinates in metres (UTM etc.) | Converts to WGS 84 using the Shapefile `.prj`, the GeoJSON `crs`, or the system you enter |
| Decimal commas, numbers as text, degrees-minutes-seconds, 3D heights | Converts to clean decimal degrees |
| Points that collapse at 6 decimals, duplicate plots | Merges or removes them |
| Wrong property names (`farmer`, `country`, `hectares`, `area_m2`, `acres`...) | Renames to `ProducerName`, `ProducerCountry`, `ProductionPlace`, `Area` |
| Country names or 3-letter codes | Converts to ISO 2-letter codes (Ghana → GH, IDN → ID) |
| Area written as text ("2,5", "3 ha", "1.234,5") or in m²/acres | Converts to a number in hectares |
| More than 1,000 plots | Splits into files of up to 1,000 plots, under 25 MB |

### What it will not guess

These plots go to `needs_attention.geojson` with a clear reason, so you can fix them at the source:

- A point with an Area over 4 ha (plots over 4 ha must be mapped as polygons; cattle excepted)
- Coordinates in metres with no known coordinate system
- Open GPS tracks, shapes with no area, unreadable geometry

It also **warns** about low GPS precision, points without Area (the EU system treats them as 4 ha), overlapping plots, a declared Area that doesn't match the mapped area, and points at 0,0.

### How to use it

1. Click **Try for free**.
2. Paste a download link to your file in **Plot file links**, or paste GeoJSON, CSV or KML text.
3. If your file is in metres and has no coordinate system, enter it (for example `EPSG:32630`).
4. Click **Start**. Most files finish in seconds.
5. Download `eudr_ready.geojson` from the **Output** or **Storage** tab and upload it to the EU Information System.

The input form comes pre-filled with a small example full of typical mistakes, so you can see the repairs straight away.

### Input formats

- **GeoJSON**: FeatureCollection, Feature, a bare geometry or GeometryCollection
- **KML / KMZ**: from Google Earth or field apps; placemark names become `ProductionPlace`
- **CSV**: latitude and longitude columns, a WKT column, a single "lat, lon" column, or **one row per corner with the same `plot_id`** for polygons. Comma or semicolon separated; decimal commas understood.
- **Shapefile**: zipped `.shp`, `.shx`, `.dbf` (+ `.prj` for the coordinate system)

### Output

| Output | What it is |
|---|---|
| `eudr_ready.geojson` (or numbered parts) | Ready to upload to the EU Information System |
| `needs_attention.geojson` | Plots that need a person, each with `_eudr_errors` explaining why |
| Dataset (table) | One row per plot: status, repairs, warnings, area in hectares, output file |
| `REPORT` | The full report as JSON |

Example dataset row:

```json
{
  "plot": 1,
  "status": "fixed",
  "geometryType": "MultiPolygon",
  "areaHa": 61.6138,
  "fixes": [
    "renamed property 'country' to 'ProducerCountry'",
    "changed ProducerCountry 'Ghana' to ISO code 'GH'",
    "converted Area '2,5' into the number 2.5 (hectares)",
    "repaired an invalid shape (self-intersection)"
  ],
  "warnings": ["declared Area 2.5 ha differs from the mapped area 61.6138 ha"],
  "errors": [],
  "outputFile": "eudr_ready.geojson"
}
```

### How much does it cost?

You pay **per plot processed**. The exact price is on the **Pricing** tab. At $0.01 per plot, for example, a 1,000-plot cooperative file costs $10, and a 50-plot test file costs $0.50.

There is no subscription. You can cap the cost of any run with the maximum-charge setting, and the fixer stops at that limit and tells you how many plots were skipped. The default example run (3 plots) costs $0.03. Runs are paid from your Apify balance; the free plan's $5 monthly credit covers a few default runs. Use **Maximum cost per run** in the run options to set a hard cap.

### More tools from translucent_wire

**Next step after fixing:** the run's `OUTPUT` record has `nextStep.georiskLocations`: the centre of each ready plot, already in the format of GeoRisk Site Screener's `locations` input. Paste it there to check the plots for mapped forest, protected areas, flood and other site risks.

| Tool | What it does |
|---|---|
| [Local Business Leads](https://apify.com/translucent_wire/local-business-email-finder) | Local businesses by type and city: email, website gaps, fit score, audit pages, map |
| [Hiring Signals to Proposals](https://apify.com/translucent_wire/hiring-signals-to-proposals) | Companies hiring for a role your service can do: tasks covered, saving, email, proposal page |
| [GeoRisk Site Screener](https://apify.com/translucent_wire/georisk-site-intelligence) | Flood, contamination, climate, EUDR forest and solar risk for any site or plot, A-F grades + report |
| [Solar Roof Prospects](https://apify.com/translucent_wire/solar-roof-prospects) | Business roofs that suit commercial solar: system size, saving, payback, email, estimate page |

### Use it from an AI assistant (MCP)

Add Apify's MCP server to Claude, ChatGPT, Cursor or any MCP client and this Actor becomes a tool your assistant can run:

```json
{"mcpServers": {"apify": {"url": "https://mcp.apify.com/?tools=translucent_wire/eudr-plot-file-fixer"}}}
```

AI agents without an Apify account can also run it and pay per run in USDC through Apify's x402 support.

### FAQ

**Does this make my product EUDR compliant?**
No. It makes your **geolocation file** follow the published technical rules of the EU Information System. It doesn't check deforestation risk, legality of production, or any other due-diligence step, and it isn't legal advice.

**Will it change correct plots?**
No. A plot that already meets every rule is passed through unchanged.

**Is my data stored?**
Your files and results stay in your own Apify storage, under Apify's normal retention settings. Nothing is shared with anyone else.

**Which rules does it follow?**
The published EU Information System GeoJSON guidance: WGS 84, at least 6 decimal digits, Point/MultiPoint/Polygon/MultiPolygon only, closed counter-clockwise polygons without self-intersections or holes, the 4 ha point rule, numeric `Area` in hectares, ISO 2-letter `ProducerCountry`, 1,000 production places per commodity line and 25 MB per statement.

**Can I use it from my own system?**
Yes. Call it through the Apify API or any Apify integration (Make, Zapier, n8n, Python, JavaScript) with the same input fields.

### Feedback

Found a file it can't handle? Open an issue on the **Issues** tab, and attach a sample with the personal details removed if you can.

# Actor input Schema

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

Direct download links to GeoJSON, KML, KMZ, CSV or zipped Shapefile plot files. Several files are fixed in one run.

## `geojson` (type: `object`):

Paste a GeoJSON FeatureCollection, Feature or geometry. The prefilled example contains common mistakes so you can see the repairs.

## `textContent` (type: `string`):

CSV needs latitude and longitude columns (one row per point, or several rows with the same plot_id for a polygon), a WKT/geometry column, or a single 'coordinates' column. Comma or semicolon separated; decimal commas and degrees-minutes-seconds are understood.

## `sourceCrs` (type: `string`):

Only needed when a file has coordinates in metres and does not say its coordinate system, e.g. EPSG:32630 (UTM zone 30N). Shapefile .prj and GeoJSON crs are read automatically.

## `cattle` (type: `boolean`):

Turn on for cattle: points are then allowed at any size.

## `removeDuplicates` (type: `boolean`):

Duplicates are rejected by the EU system. Off = keep them and only warn.

## `dropUnknownProperties` (type: `boolean`):

Remove every property except ProducerName, ProducerCountry, ProductionPlace and Area to keep files small.

## `maxPlotsPerFile` (type: `integer`):

Output is split into several files above this number (EU guidance: 1,000 production places per commodity line).

## Actor input object example

```json
{
  "geojson": {
    "type": "FeatureCollection",
    "features": [
      {
        "type": "Feature",
        "properties": {
          "producer_name": "Kofi Mensah",
          "country": "Ghana",
          "area": "2,5"
        },
        "geometry": {
          "type": "Polygon",
          "coordinates": [
            [
              [
                -1.620112,
                6.680134
              ],
              [
                -1.610145,
                6.690121
              ],
              [
                -1.610133,
                6.680156
              ],
              [
                -1.620187,
                6.690178
              ],
              [
                -1.620112,
                6.680134
              ]
            ]
          ]
        }
      },
      {
        "type": "Feature",
        "properties": {
          "ProducerName": "Ama Owusu",
          "ProducerCountry": "GH"
        },
        "geometry": {
          "type": "Polygon",
          "coordinates": [
            [
              [
                -1.530021,
                6.700034,
                210
              ],
              [
                -1.530045,
                6.710012,
                211
              ],
              [
                -1.520078,
                6.710056,
                212
              ],
              [
                -1.520011,
                6.700089,
                213
              ]
            ]
          ]
        }
      },
      {
        "type": "Feature",
        "properties": {
          "ProducerName": "Budi Santoso",
          "ProducerCountry": "IDN",
          "Area": "1.8 ha"
        },
        "geometry": {
          "type": "Point",
          "coordinates": [
            -0.512345,
            110.412345
          ]
        }
      }
    ]
  },
  "cattle": false,
  "removeDuplicates": true,
  "dropUnknownProperties": false,
  "maxPlotsPerFile": 1000
}
```

# Actor output Schema

## `readyFile` (type: `string`):

No description

## `needsAttention` (type: `string`):

No description

## `plots` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `report` (type: `string`):

No description

# 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 = {
    "geojson": {
        "type": "FeatureCollection",
        "features": [
            {
                "type": "Feature",
                "properties": {
                    "producer_name": "Kofi Mensah",
                    "country": "Ghana",
                    "area": "2,5"
                },
                "geometry": {
                    "type": "Polygon",
                    "coordinates": [
                        [
                            [
                                -1.620112,
                                6.680134
                            ],
                            [
                                -1.610145,
                                6.690121
                            ],
                            [
                                -1.610133,
                                6.680156
                            ],
                            [
                                -1.620187,
                                6.690178
                            ],
                            [
                                -1.620112,
                                6.680134
                            ]
                        ]
                    ]
                }
            },
            {
                "type": "Feature",
                "properties": {
                    "ProducerName": "Ama Owusu",
                    "ProducerCountry": "GH"
                },
                "geometry": {
                    "type": "Polygon",
                    "coordinates": [
                        [
                            [
                                -1.530021,
                                6.700034,
                                210
                            ],
                            [
                                -1.530045,
                                6.710012,
                                211
                            ],
                            [
                                -1.520078,
                                6.710056,
                                212
                            ],
                            [
                                -1.520011,
                                6.700089,
                                213
                            ]
                        ]
                    ]
                }
            },
            {
                "type": "Feature",
                "properties": {
                    "ProducerName": "Budi Santoso",
                    "ProducerCountry": "IDN",
                    "Area": "1.8 ha"
                },
                "geometry": {
                    "type": "Point",
                    "coordinates": [
                        -0.512345,
                        110.412345
                    ]
                }
            }
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("translucent_wire/eudr-plot-file-fixer").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 = { "geojson": {
        "type": "FeatureCollection",
        "features": [
            {
                "type": "Feature",
                "properties": {
                    "producer_name": "Kofi Mensah",
                    "country": "Ghana",
                    "area": "2,5",
                },
                "geometry": {
                    "type": "Polygon",
                    "coordinates": [[
                            [
                                -1.620112,
                                6.680134,
                            ],
                            [
                                -1.610145,
                                6.690121,
                            ],
                            [
                                -1.610133,
                                6.680156,
                            ],
                            [
                                -1.620187,
                                6.690178,
                            ],
                            [
                                -1.620112,
                                6.680134,
                            ],
                        ]],
                },
            },
            {
                "type": "Feature",
                "properties": {
                    "ProducerName": "Ama Owusu",
                    "ProducerCountry": "GH",
                },
                "geometry": {
                    "type": "Polygon",
                    "coordinates": [[
                            [
                                -1.530021,
                                6.700034,
                                210,
                            ],
                            [
                                -1.530045,
                                6.710012,
                                211,
                            ],
                            [
                                -1.520078,
                                6.710056,
                                212,
                            ],
                            [
                                -1.520011,
                                6.700089,
                                213,
                            ],
                        ]],
                },
            },
            {
                "type": "Feature",
                "properties": {
                    "ProducerName": "Budi Santoso",
                    "ProducerCountry": "IDN",
                    "Area": "1.8 ha",
                },
                "geometry": {
                    "type": "Point",
                    "coordinates": [
                        -0.512345,
                        110.412345,
                    ],
                },
            },
        ],
    } }

# Run the Actor and wait for it to finish
run = client.actor("translucent_wire/eudr-plot-file-fixer").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 '{
  "geojson": {
    "type": "FeatureCollection",
    "features": [
      {
        "type": "Feature",
        "properties": {
          "producer_name": "Kofi Mensah",
          "country": "Ghana",
          "area": "2,5"
        },
        "geometry": {
          "type": "Polygon",
          "coordinates": [
            [
              [
                -1.620112,
                6.680134
              ],
              [
                -1.610145,
                6.690121
              ],
              [
                -1.610133,
                6.680156
              ],
              [
                -1.620187,
                6.690178
              ],
              [
                -1.620112,
                6.680134
              ]
            ]
          ]
        }
      },
      {
        "type": "Feature",
        "properties": {
          "ProducerName": "Ama Owusu",
          "ProducerCountry": "GH"
        },
        "geometry": {
          "type": "Polygon",
          "coordinates": [
            [
              [
                -1.530021,
                6.700034,
                210
              ],
              [
                -1.530045,
                6.710012,
                211
              ],
              [
                -1.520078,
                6.710056,
                212
              ],
              [
                -1.520011,
                6.700089,
                213
              ]
            ]
          ]
        }
      },
      {
        "type": "Feature",
        "properties": {
          "ProducerName": "Budi Santoso",
          "ProducerCountry": "IDN",
          "Area": "1.8 ha"
        },
        "geometry": {
          "type": "Point",
          "coordinates": [
            -0.512345,
            110.412345
          ]
        }
      }
    ]
  }
}' |
apify call translucent_wire/eudr-plot-file-fixer --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,translucent_wire/eudr-plot-file-fixer"
        }
    }
}
```

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/X3YaGrdOqe873lApr/builds/NacXsiPrt9VoF0ie2/openapi.json
