compliance//4 min read
Building EUDR traceability: plots, batches and due diligence data
A due diligence statement is only as good as the data behind it. How to model plots, harvests and batches so every shipment traces back to its land, validate geolocation, and run deforestation checks against satellite data.

In short
- Model plots, harvest lots and batches as separate things, and record every transformation that links them.
- Store plot boundaries as geometry in PostGIS, validate them on the way in, and keep every revision.
- Run deforestation checks by intersecting plots with forest-cover and forest-loss data from after the 2020 cut-off.
- Field collection must work offline, on cheap phones, in the hands of people who are not data specialists.
The legal side of the EU Deforestation Regulation fits on a page. The engineering does not. To file a due diligence statement for a shipment you need to answer, with evidence, a question most supply chains were never built to answer: which plots of land did this exact batch come from?
The core data model
Four entities carry most of the weight:
Entity | What it is | Key fields |
|---|---|---|
Producer | A farmer, estate or forest owner | Identity, land-rights documents, cooperative membership |
Plot | A piece of land where the commodity is produced | Boundary or point, area, country and region, legality evidence |
Lot | A harvest or delivery from one or more plots | Plots, quantity, harvest dates, collection point |
Batch | What moves through processing and shipping | Input lots or batches, transformation type, output quantity |
The links between them matter more than the entities. A batch of roasted coffee is made from green-coffee batches, which were made from lots, which came from plots. If any link is missing, the trace breaks and so does the statement.
Plots as geometry
Store boundaries as real geometry, not as text. In Postgres, PostGIS gives you validation, area calculation, overlap checks and spatial indexes.
create extension if not exists postgis;
create table plots (
id bigserial primary key,
producer_id bigint not null references producers(id),
country_code char(2) not null,
boundary geometry(MultiPolygon, 4326), -- for plots over 4 ha
centroid geometry(Point, 4326), -- enough for small plots
area_ha numeric(10, 4),
valid_from timestamptz not null default now(),
check (boundary is not null or centroid is not null)
);
create index plots_boundary_idx on plots using gist (boundary);Validate on the way in
Field-collected polygons are messy: self-intersections, duplicate points, swapped latitude and longitude, plots in the sea. Reject or repair them at upload, never at filing time.
-- Problems worth catching before they reach a due diligence statement.
select id,
st_isvalid(boundary) as valid_shape,
st_area(boundary::geography) / 10000 as area_ha,
st_y(st_centroid(boundary)) between -90 and 90 as lat_ok
from plots
where boundary is not null;
-- Two producers claiming overlapping land is a red flag worth reviewing.
select a.id, b.id
from plots a join plots b on a.id < b.id
where st_overlaps(a.boundary, b.boundary);Keep history. When a boundary is corrected, add a new version rather than overwriting the old one, so you can always show what you knew when a statement was filed.
Deforestation checks
To show a plot was not deforested after 31 December 2020, intersect it with forest-cover data for 2020 and with forest-loss data since. Public sources include the EU Joint Research Centre's global forest cover map for 2020 and the tree-cover loss data published through Global Forest Watch. Treat satellite results as evidence for a risk assessment, not as a verdict: cloud cover, plantations mapped as forest and small plots near the data's resolution all produce false alarms that need a person to review.
- Flag plots where forest in 2020 overlaps the boundary and loss appears afterwards.
- Store the dataset version and date with every check, so results can be reproduced.
- Route flagged plots to a review queue with the imagery attached.
Following batches through processing
Mills, crushers and roasters blend inputs. Record every transformation with its inputs and outputs, and decide your model up front:
Model | What you can claim | Fit for EUDR |
|---|---|---|
Identity preserved | This batch comes only from these named plots | Yes |
Segregated | This batch comes only from compliant plots, mixed together | Yes |
Mass balance | Compliant volume in equals compliant volume out, but physically mixed | Generally not enough: EUDR needs the actual plots |
Data collection in the field
The data starts with a field officer at a farm. Build for that reality: an offline-first mobile app, GPS capture by walking the boundary, photos of documents, local languages, and sync when the phone finds a signal. Data quality at this step decides everything downstream.
Producing the statement
For each shipment, the system should assemble the statement automatically: product codes, quantities, the country of production and the geolocation of every contributing plot, then submit it to the EU information system and store the reference number against the shipment. Your EU customers will ask for that reference, or for the underlying data, often through an API.
If a batch cannot be traced to its plots in a query, it cannot be traced in an audit either.
Build checklist
- To do: Producers, plots, lots and batches modelled with explicit links
- To do: Plot geometry in PostGIS, validated at upload, with version history
- To do: Overlap and plausibility checks on every new or changed plot
- To do: Satellite deforestation checks with dataset versions recorded
- To do: Every processing step recorded as inputs to outputs
- To do: Offline-first field app with GPS boundary capture
- To do: Statement generation and submission references stored per shipment

