AAFC Annual Crop Inventory Layer
Status: Planned Issue: #159Bundle: Ag Bundle (Farmer + Investor tiers; raster summary statistics available at Lite).
Goal
Render the AAFC Annual Crop Inventory (ACI) as a togglable raster overlay on the DLS grid. Each year's inventory shows the dominant crop class per pixel (~30m resolution) for the entire Canadian agricultural land base, derived from optical and SAR satellite imagery. Lets users see what was actually grown on any quarter section in any year from 2009 forward.
Source
AAFC publishes ACI as a national raster product each spring covering the previous growing season. Released under Open Government Licence — Canada.
| Source | Coverage | Resolution | Format |
|---|---|---|---|
| AAFC Annual Crop Inventory (latest year) | National | 30m | GeoTIFF |
| AAFC ACI historical archive (2009–previous year) | National | 30m | GeoTIFF |
| AAFC Crop Class codebook | n/a | n/a | XLSX |
Each pixel carries a single integer crop class. The codebook maps integers to crop names (e.g., 146 = "Canola", 153 = "Spring Wheat") and to broader groups (small-grain cereals, pulses, oilseeds, etc.).
Customer-facing layer model
A single raster layer with a year selector. The legend follows AAFC's published colour table — same colours customers already see on the AAFC Crop Inventory web viewer:
- Pre-defined colour ramp per crop class (canola yellow, wheat tan, soybean green, etc.)
- Year selector defaulting to the most recent published year (typically the previous growing season)
- Pixel value inspection on hover: shows crop class name from the codebook
- Toggle to display "dominant crop in the last 5 years" derived view (PostGIS-side rollup)
API surface
Two endpoints:
GET /api/parcels/[lld]/crop-history?years=5
→ {
parcel: { lld, area_acres },
history: [
{ year: 2025, dominant: "Canola", area_pct: 78 },
{ year: 2024, dominant: "Wheat", area_pct: 65 },
...
],
dominant_5yr: "Canola/Wheat rotation"
}
GET /api/regions/[rm]/crop-summary?year=2025
→ {
region: { rm, name, area_acres },
crops: [
{ class: "Canola", area_pct: 32.5 },
{ class: "Spring Wheat", area_pct: 24.1 },
...
]
}
Storage and rendering
The full ACI raster is large at national scale. Storage and rendering:
- Re-encode each year's raster to PMTiles (Cloud-Optimized GeoTIFF → PMTiles via
rio-rgbifyor equivalent) - Host at
maps.townshipcanada.com/aci_<year>.pmtiles - Per-pixel queries hit a PostGIS-side
app.aci_<year>table built from the raster (orST_Valueagainst a stored COG)
Per-parcel aggregation queries take advantage of the existing parcel geometry in public.dls_quarters etc.
Acceptance criteria progress
- AAFC ACI ingestion pipeline (annual run when AAFC publishes the new year)
- PMTiles archive per year for the most recent 5 years
- Layer config:
app/config/mapLayers/dataCatalog/aafcCropInventory.jswith year selector - Catalog entry in
app/config/mapLayers/index.js -
GET /api/parcels/[lld]/crop-historyendpoint -
GET /api/regions/[rm]/crop-summaryendpoint - Crop class colour table matching the published AAFC legend
- Year selector UI control wired to the layer source URL
- Entitlement gating: Farmer+ for the overlay; Lite gets the per-parcel summary in the free parcel report only
Customer use cases
- Farmers and agronomists — confirm what was grown on a leased quarter before signing for the upcoming season; identify rotations on neighbouring land
- Farmland investors — score acquisition pipeline parcels by historical crop intensity; identify under-utilized parcels
- Ag retailers / agronomy service providers — territory-level crop mix for planning, prospecting, and trial-site selection (Investor tier via Territory & Prospecting tool)
- Carbon project developers — Conservation Cropping protocol requires historical crop history per parcel; the per-parcel API serves this directly
Related layers / features
- LSRS Productivity Score — same ag-customer audience
- Soil Landscapes of Canada (existing
soilLandscapesCanadalayer) - One-click Parcel Report (#157) — includes crop history snippet
- Territory & Prospecting Tool (#162)
- Land Portfolio Manager (#160)