USDA Cropland Data Layer Farmland & Land-Cover Screener
Pricing
from $3.85 / 1,000 results
USDA Cropland Data Layer Farmland & Land-Cover Screener
Farmland & land-cover API: batch coordinates to USDA Cropland Data Layer class (Corn, Soybeans, Developed, Forest, Water), an active-cropland flag, and a prime-farmland proxy. For solar-siting, land-use diligence, and farmland-protection screening. Keyless, MCP-ready. Prime-farmland is a proxy.
Pricing
from $3.85 / 1,000 results
Rating
0.0
(0)
Developer
Kyle Maloney
Maintained by CommunityActor stats
1
Bookmarked
2
Total users
1
Monthly active users
5 days ago
Last modified
Categories
Share
USDA Cropland Data Layer Farmland & Siting Screener
Classifies a batch of coordinates against the USDA Cropland Data Layer (CDL) and returns, per site, the land-cover class, an active-cropland flag, and a prime-farmland proxy. Aimed at solar and wind site developers, land-use diligence teams, and ag lenders who need to know whether a candidate parcel is in active crop production before they act on it.
How it works
For each site you supply (lat/lon, WGS84), the actor projects the point into the CDL's native CONUS Albers Equal Area projection (EPSG:5070) and samples it through USDA's public CropScape GetCDLValue point service (nassgeodata.gmu.edu). No API key, no login, no scraping.
Two USDA backends, with automatic failover. CropScape is the primary. If it cannot be reached or verified, the run is answered instead by USDA's CroplandCROS ArcGIS image service (pdi.scinet.usda.gov), which publishes the same annual Cropland Data Layer. A CropScape outage therefore degrades this actor rather than stopping it. See Which backend answered below — you can always tell, per row. The CDL is a ~30 m annual satellite crop-classification raster; the sampled pixel gives you the class code (1 = Corn, 5 = Soybeans, 176 = Grassland/Pasture, 121–124 = Developed, 141–143 = Forest, 111 = Open Water, 0 = No Data outside CONUS).
Coverage is the Contiguous US. A point in the ocean or outside CONUS returns a row with coverage_status "no_data" or "out_of_coverage" and NULL crop flags - an explicit non-answer, not a finding of "no farmland" - and a single bad coordinate produces an ERROR row without failing the run. Years 1997 to the newest published vintage are available. Leave year empty and the actor uses whichever vintage USDA publishes today, discovered live from the service rather than hard-coded — CDL 2025 was live as of 2026-08-01, and the same Iowa point is Corn in 2024 and Soybeans in 2025.
Example input
{"assets": [{ "lat": 42.45, "lon": -93.55, "label": "Iowa cornfield" },{ "lat": 42.30, "lon": -94.20, "label": "Iowa soybean field" },{ "lat": 40.75, "lon": -73.98, "label": "Manhattan, NY (developed)" }],"year": 2024}
Output fields (one row per site)
All fields are nullable. null means not checked / not published — it is never a negative finding.
Site + vintage
| Field | What it is |
|---|---|
asset_label, asset_lat, asset_lon | Your label and coordinates, echoed back |
cdl_year | The CDL vintage actually sampled |
requested_year | The vintage you asked for |
cdl_latest_available_year | The newest vintage USDA publishes, discovered live from the service on every run. null if it could not be measured |
cdl_year_is_latest | Whether cdl_year is that newest vintage. null when the newest vintage could not be verified this run — no claim is made |
cdl_year_note | Set when the requested year could not be honoured and a different one was sampled |
cdl_vintage_status | How the newest vintage was established: verified (a direct year probe and/or the service year-range message agreed), conflict (they disagreed; the direct data probe was followed), unverified (neither could be measured this run) |
cdl_vintage_method | The evidence used: probe_ladder, fault_range, or both |
cdl_drift_gate_status | passed, or passed_with_warnings when a check could not be measured |
cdl_drift_gate_warnings | Which checks could not be measured, spelled out. null on a clean run |
checked_at | Run timestamp |
Land cover
| Field | What it is |
|---|---|
cdl_code | CDL class code (0–255) |
land_cover_class | Class name from the full published legend, e.g. Corn, Herbaceous Wetlands, Pomegranates |
category | Coarse bucket: cropland, pasture, forest, water, developed, no_data, other |
land_cover_group | Finer group: cropland, orchard_vineyard, pasture_grassland, forest, shrubland, barren, wetland, water, developed, aquaculture, nonag_undefined, no_data |
is_active_cropland | Whether the pixel is in active crop production. null when the pixel was never classified |
prime_farmland_flag | The active-cropland proxy for prime farmland. null when not assessed |
prime_farmland_basis | Plain-language statement of what that flag does and does not mean |
cdl_color | Legend colour hex |
Coverage + service status
| Field | What it is |
|---|---|
coverage_status | in_coverage · no_data (CDL never classified this pixel — ocean, Canada, Mexico, cloud) · out_of_coverage (outside CONUS entirely: Alaska, Hawaii, Puerto Rico) · service_error · invalid_input |
cdl_service_status | ok, or the upstream failure text |
error | Why no determination was made |
albers_x, albers_y | The EPSG:5070 coordinate sent |
albers_echo_x, albers_echo_y | The coordinate CropScape echoed back. Measured 2026-08-04, it echoes the request verbatim rather than snapping to a pixel centre, so this restates albers_x/albers_y; it is retained as a tripwire in case that ever changes. null on a failover row — the image service does not echo a comparable value |
webmercator_x, webmercator_y | The EPSG:3857 coordinate. This is the projection the failover backend reads; emitted on every row because it is a fact about your input |
source_url, citation, disclaimer | Provenance. The citation and disclaimer name the backend that actually answered |
Backend provenance
| Field | What it is |
|---|---|
cdl_backend | cropscape (primary) or pdi_imageserver (failover) — which USDA service produced this row |
cdl_backend_failover | true when the primary was unreachable and the failover answered. false when the primary served or you pinned a backend. null when nothing answered |
cdl_backend_selection_reason | primary_healthy · failover_primary_unavailable · user_pinned_primary · user_pinned_secondary |
cdl_backend_primary_status, cdl_backend_secondary_status | Per-backend verification outcome: ok · unavailable (could not be reached or verified — nothing was measured) · drifted (was measured, and it is wrong) · disabled · not_checked. Both backends are verified on every run |
cdl_backend_primary_detail, cdl_backend_secondary_detail | Why, when a backend was not ok |
cdl_cross_backend_agreement | Did the two services agree on the shared canary pixel this run: agree · agree_group_differs_code (adjacent classes at a boundary — expected, see above) · disagree (different land-cover group — treat the run as lower confidence) · null (one backend was not consulted) |
cdl_cross_backend_detail | Both readings, when they differ |
cdl_raster_name, cdl_pixel_meters | The exact USDA raster and its ground resolution, e.g. 2025_10m_cdls / 10. CDL moved from 30 m to 10 m with the 2024 vintage. Published only by the failover backend, so null on a CropScape row — not checked, not "unknown resolution" |
Area composition (set sampleRadiusMeters > 0)
A siting decision is about a parcel, not one 30 m pixel. With a radius set, each site also gets a land-cover composition over a square box of that half-width, from USDA's GetCDLStat service — same keyless source, no extra billable rows. It is off by default because that clip service is far slower than the point lookup and does not always answer; each site gets 20 seconds for it and otherwise falls back to area_status "unavailable" without affecting the land-cover result.
| Field | What it is |
|---|---|
area_status | ok, unavailable, or unknown_class: <codes> |
| area_radius_m | Half-width sampled, in metres |
| area_acres | Total acreage of the sampled box |
| area_distinct_classes | How many different CDL classes occur in it |
| area_dominant_class, area_dominant_code, area_dominant_pct | The largest class and its share |
| area_cropland_pct | Share in cropland or orchard/vineyard — the number that matters for a farmland-conversion screen |
| area_pasture_pct, area_forest_pct, area_wetland_pct, area_water_pct, area_developed_pct, area_barren_shrub_pct, area_no_data_pct | The rest of the composition |
| area_top_classes | Up to five largest classes, each with code, name, acres and percent |
| area_source_url | The GetCDLStat request used |
Which backend answered
The same USDA Cropland Data Layer is published through two independent public services. This actor uses both.
| Primary | Failover | |
|---|---|---|
cdl_backend | cropscape | pdi_imageserver |
| Service | NASS CropScape GetCDLValue | USDA CroplandCROS ArcGIS Image Service |
| Host | nassgeodata.gmu.edu | pdi.scinet.usda.gov |
| Projection sampled in | EPSG:5070 CONUS Albers (CDL native) | EPSG:3857 Web Mercator |
| Names its raster / resolution | no (cdl_raster_name is null) | yes (e.g. 2025_10m_cdls, 10 m) |
How to tell which one you got. Every row carries cdl_backend,
cdl_backend_failover and cdl_backend_selection_reason, plus a status and
reason for each backend (cdl_backend_primary_status,
cdl_backend_secondary_status). cdl_backend_failover: true means the primary
was unreachable and the secondary answered. The citation and disclaimer
strings on the row name the service that actually answered, so a failover row is
never presentable as a primary row.
Should you care? For the cropland and prime-farmland answer, almost never —
but here is the honest measurement rather than a reassurance. Both services
serve the same CDL, reprojected differently, and their pixel grids are offset
by about one pixel. Measured live on 2026-08-04 across 21 point/year probes,
18 returned the identical CDL code and 3 differed — all three within one pixel
of a class boundary or inside the urban mosaic (Manhattan 2024: Developed/Medium
vs Developed/High). Zero differed at the land-cover group level, so
is_active_cropland and prime_farmland_flag agreed on every probe. A 20 m
north-south transect through a soybean/corn boundary in Webster County, Iowa
agreed at every step except the one where the boundary itself sits.
So: within roughly 10-30 m of a field edge the two services can name adjacent
crops. Away from edges they agree exactly. Every run compares them on a shared
canary pixel and publishes the verdict in cdl_cross_backend_agreement
(agree, agree_group_differs_code, disagree, or null when one backend was
not consulted). A disagreement is reported, never silently resolved in favour of
whichever one answered.
Pinning a backend. Set backend to cropscape or pdi_imageserver if you
need every answer to come from one named service — useful when you are diffing
runs over time and want the pixel grid held constant. A pinned backend is
never silently substituted: if it is unhealthy the run fails loudly and bills
nothing, because a silent swap would destroy the reproducibility you asked for.
The default, auto, is the one you want otherwise.
Reliability: how this actor fails
CDL is published annually, so the two things that can quietly go wrong are a stale vintage and a changed legend. Both are checked live, before any billable row is emitted - against whichever backend is about to answer:
- Vintage is discovered two independent ways, not assumed. The primary check is a direct probe: candidate years are requested in descending order and the first that returns real CDL data is the newest published vintage. The service's own out-of-range message is read as a second, corroborating measurement (and is the only thing that reveals the earliest published year). If the two disagree, the direct data probe wins and the row says so. If the service ever publishes less than the vintage this build was verified against, the run fails.
- "Could not measure" is reported separately from "measured and wrong." An upstream outage that silences a probe is a measurement failure, not evidence the data has drifted. The run continues, every row carries
cdl_drift_gate_status: passed_with_warningsplus the specific caveat, andcdl_year_is_latestreportsnullrather than claiming the fallback year is current. A drift that is actually measured still fails the run and bills nothing. - Four positive canaries and a negative control run every time. Known row-crop pixels in Iowa, Illinois and Nebraska must classify as active cropland (the crop rotates year to year — Corn in 2024, Soybeans in 2025 — so the assertion is the stable property, not the class). Checking several points across several states means one field changing use cannot take the actor down, while a broken coordinate transform — which moves every point at once — still fails the run. A known North Atlantic ocean point must come back as No Data; if it ever returns a land-cover class, the transform or the product footprint has changed.
- Projection is checked by magnitude and by end-to-end behaviour. CropScape echoes back the coordinate it was sent, verbatim (it does not snap to a pixel centre - measured 2026-08-04), so the echo comparison is a change-detector rather than live projection coverage; the real projection guard is the canary/negative-control pair plus a CONUS envelope bound on the projected coordinate. The failover backend additionally reports the spatial reference it interpreted the request in, and the run fails if that ever stops being Web Mercator.
- An unrecognised CDL class code fails the run. The full published legend ships with the actor. A code outside it means USDA changed the legend, which invalidates every cropland and prime-farmland flag derived from it — so nothing is emitted rather than something plausible and wrong.
nullmeans not checked. A pixel USDA never classified (CDL "No Data" — ocean, Canada, Mexico, cloud) and a point outside CONUS both returnnullcrop flags with an explicitcoverage_status, never a confident "not farmland".- If neither backend can be verified, the run fails and bills nothing. Rows are buffered and gated before anything is written.
- A measured drift is never "failed over" around. Failover is for availability - a timeout, a 5xx, an unreadable body, a backend that verified nothing. If a backend is reached and its answer proves something has actually changed (superseded vintage, a canary on the wrong land cover, an unknown legend code), the run fails loudly instead, even when the other backend looks healthy. Two USDA services publishing the same product disagreeing about whether the world changed is a contradiction this actor will not resolve silently in your favour.
Pricing
Pay-per-result: one billable dataset row per site screened. Setting sampleRadiusMeters adds upstream calls but no extra rows — the composition fields ride on the same row. A failed run emits nothing and bills nothing.
About the prime-farmland flag
The CDL does not carry the legal "prime farmland" soil classification — that lives in NRCS SSURGO as the farmlndcl attribute. So prime_farmland_flag is a transparent proxy: true when the point is in active crop production, which strongly indicates farmland but is not a substitute for an SSURGO determination. For an authoritative answer (for example, a Farmland Protection Policy Act / AD-1006 review), use NRCS Web Soil Survey / SSURGO.
Who uses it
- Solar and renewable-energy developers screening candidate parcels for active cropland or farmland-conversion sensitivity before acquisition.
- Land-use and environmental diligence teams (Phase I / ESA-adjacent) needing a fast land-cover read at many coordinates.
- Ag lenders, appraisers, and CRE analysts checking whether collateral is productive cropland.
- Farmland-protection and conservation planners flagging active-cropland parcels.
- AI agents needing a coordinate-to-land-cover lookup.
Use as an MCP tool
This is a Pay-Per-Result API with field-level output descriptions, so AI agents (Claude, Cursor, and others) can call it over mcp.apify.com as a coordinate-to-land-cover tool. Empty input costs nothing beyond the actor start.
FAQ
Is this the legal prime-farmland determination? No. It is a CDL active-cropland proxy; use NRCS SSURGO for the authoritative soil class.
Does it need an API key? No. Both USDA backends are public and keyless.
What happens for an ocean or non-US point? You get a valid No Data (code 0, category no_data) row with null crop flags and an explicit coverage_status — an honest non-answer, not an error and not a finding of "no farmland".
What happens if USDA CropScape goes down? The run is answered by USDA's CroplandCROS image service instead, and every row is stamped cdl_backend: "pdi_imageserver", cdl_backend_failover: true. Both publish the same Cropland Data Layer. This is why v1.4 exists: on 2026-08-02 CropScape was down for about an hour, and for that hour this actor was simply offline.
Can a failover answer differ from a primary answer? Yes, marginally, and the row tells you so. The two services reproject the same CDL and their pixel grids sit about one pixel apart, so within roughly 10-30 m of a field boundary they can name adjacent crops. Across 21 live probes on 2026-08-04 the two agreed on the land-cover group — and therefore on is_active_cropland and prime_farmland_flag — every single time. See Which backend answered.
Can I force one backend? Yes — set backend to cropscape or pdi_imageserver. A pinned backend is never silently substituted; if it is unhealthy the run fails and bills nothing.
What is simulateOutage? A diagnostic switch that forces a backend to be treated as unreachable, so the failover path can be exercised on demand rather than only discovered during a real outage. Leave it at none.
How is billing calculated? One dataset row per site.