# USFWS Wetlands Proximity Screener - Section 404 Site Risk API (`malonestar/fws-wetlands-proximity-screener`) Actor

Wetland due-diligence API for site selection: per lat/lon site, wetland presence within radius, Cowardin classification codes/systems, wetland types, total acreage nearby and a Section 404 dredge-and-fill screening flag. USFWS National Wetlands Inventory open data.

- **URL**: https://apify.com/malonestar/fws-wetlands-proximity-screener.md
- **Developed by:** [Kyle Maloney](https://apify.com/malonestar) (community)
- **Categories:** Agents, Developer tools, Real estate
- **Stats:** 2 total users, 1 monthly users, 95.2% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.40 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

## USFWS Wetlands Proximity Screener - Section 404 Site Risk API

Screen any list of US coordinates against the **USFWS National Wetlands Inventory (NWI)** and get back, per site: whether a mapped wetland sits **on** the site, whether one sits **within** your radius, the **measured distance and bearing to the nearest one**, the full **Cowardin classification** decoded into system / subsystem / class / subclass / water regime / special modifiers, acreage by type and by system, and a gated **Clean Water Act Section 404** screening verdict with the reasoning attached.

One dataset row per site. Keyless, national coverage, no API key to obtain.

> Screening tool. NWI mapping is not a wetland delineation and is not an approved jurisdictional determination. It tells you where to look and where the risk is.

### What changed in v1.1 (2026-07-30)

v1.0 shipped four defects that produced *plausible wrong answers* while the run reported SUCCESS. All four are fixed, and each is now covered by a regression test that was mutation-verified.

| Defect in v1.0 | Measured impact | v1.1 |
|---|---|---|
| One unpaginated query; `exceededTransferLimit` never read | At 47.5,-99.0 r=5000 the true count is **1,582** polygons; the actor returned **1,000** and summed acreage over that arbitrary 63.2% subset | Full pagination, `exceededTransferLimit` honoured, and `results_truncated` published. Acreage is **nulled** rather than summed over a subset |
| Screened a bounding box, not a circle | Envelope reaches sqrt(2)xR at its corners. Live: 29.55,-90.55 r=5000 -> circle **357**, envelope **518** (**+45.1%**) | True point + distance circle. The envelope builder remains only as a documented fallback |
| `PAGE_SIZE` set to 2000 | The service caps at **1000**. The actor asked for a page it could never receive and never noticed the shortfall | `PAGE_SIZE = 1000`, asserted live against the layer's own `maxRecordCount` |
| `nearest_wetland_*` was the **largest-acreage** polygon, not the nearest | A proxy reported as a measurement on a question where the number is the whole point | Measured distance + bearing, with `distance_method`, a tolerance, and a lower bound. The old semantic is preserved under `primary_wetland_*_by_acreage` |

Also new: the joined `NWI_Wetland_Codes` table (35 authoritative decode columns) was fetched by nobody in v1.0 - the actor read **three** columns and hand-decoded the system letter from a five-entry map. v1.1 reads the join. Output went from **16 to 79 fields**, append-only: every v1.0 field is still present with its original name.

### Who this is for

- **Phase I ESA consultants** - a wetlands line item on every report. `wetland_on_site`, `nearest_wetland_distance_m` and `jurisdictional_likelihood` answer it for a portfolio in one call. Pairs with the tank/spill and contaminated-site screeners below.
- **Wetland delineators and environmental planners** - `cowardin_class_names`, `cowardin_subclass_names`, `cowardin_water_regime_names` and `cowardin_special_modifiers` tell you what vegetation and hydrology to expect before you walk the site, and which features are Excavated, Farmed or Diked/Impounded.
- **Solar, BESS, wind and infrastructure siting teams** - screen hundreds of candidate parcels for Section 404 exposure before spending money on any of them. `delineation_recommended` is the triage field.
- **Mitigation bankers and land trusts** - `acres_by_wetland_type`, `acres_by_system` and the tidal / deepwater flags quantify what is actually on a tract.
- **AI agents** - every field carries a description, so this reads cleanly as an MCP tool.

### Example input

```json
{
  "assets": [
    { "lat": 36.3736, "lon": -89.385,   "label": "Reelfoot Lake, TN - site inside a mapped lake" },
    { "lat": 35.2216, "lon": -75.6913,  "label": "Cape Hatteras, NC - estuarine tidal marsh" },
    { "lat": 39.7392, "lon": -104.9903, "label": "Denver, CO - urban infill" },
    { "lat": 33.4484, "lon": -112.074,  "label": "Phoenix, AZ - dry upland reference point" }
  ],
  "radiusMeters": 500,
  "computeNearestDistance": true,
  "nearestSearchRadiusMeters": 1609,
  "maxResults": 500
}
```

Live results from exactly that input:

| Site | On site | Within 500 m | Nearest | Likelihood | 404 flag |
|---|---|---|---|---|---|
| Reelfoot Lake, TN | **true** | true (3) | 0 m (point in polygon) | high | true |
| Cape Hatteras, NC | false | true (26) | **2.4 m NNW** | high | true |
| Denver, CO | false | false (0) | **560.8 m WSW** | low | false |
| Phoenix, AZ | false | false (0) | **1,390.9 m N** | low | false |

Note Denver and Phoenix: `section_404_flag` is `false` **for the stated radius**, and the row still tells you exactly how far the nearest wetland is and in which direction. That is the difference between "clear" and "clear at 500 m".

### Input fields

| Field | Type | Default | Notes |
|---|---|---|---|
| `assets` | array | required | `{ "lat", "lon", "label" }` objects, `"lat,lon"` strings, or `[lat, lon]` arrays. One billed row per asset. |
| `radiusMeters` | integer | 300 | 10-5000. Screened as a **true circle**. The Console prefill sends this same 300 m, so the demo and an API caller who omits the field get the identical screen. |
| `computeNearestDistance` | boolean | true | Measures the real distance/bearing to the nearest wetland (up to ~10 extra small requests per site). Off -> `nearest_wetland_*` falls back to the largest-acreage feature and `nearest_basis` says `largest_acreage_proxy`. |
| `nearestSearchRadiusMeters` | integer | 1609 | How far out to look for the nearest wetland. Independent of `radiusMeters`, capped at 8000, never below `radiusMeters`. |
| `maxResults` | integer | 500 | 1-2000 assets per run. |

### Output fields (all 79)

Every field the actor emits is listed. Nothing is abbreviated - buyers pick off this table.

#### Site + v1.0 core contract

| Field | Type | Description |
|---|---|---|
| `asset_label` | string | Label of the screened site, as supplied, or "lat,lon" when none was given. |
| `asset_lat` | number | Latitude of the screened site (WGS84 decimal degrees). |
| `asset_lon` | number | Longitude of the screened site (WGS84 decimal degrees). |
| `radius_meters` | integer | Radius in metres used for the wetland presence check around this site. v1.1 screens a TRUE circle; v1.0 used a bounding box that reached sqrt(2)\*R at its corners and over-reported by 26.7-45.1 percent at the sites measured live. |
| `wetland_within_radius` | boolean | True when at least one NWI-mapped wetland polygon intersects the circular screening radius. False only when the radius query succeeded and returned nothing. NULL when the radius query was unavailable - null means NOT CHECKED, never "clear". |
| `wetland_count` | integer | Number of distinct NWI wetland polygons intersecting the screening radius. This is the exact server-side count when the count query succeeded, so it stays correct even if the feature pages were truncated. |
| `cowardin_codes` | array | Unique NWI Cowardin classification codes (ATTRIBUTE) within the radius, e.g. L1UBH, PEM1C, PFO1/2C. |
| `cowardin_systems` | array | Decoded Cowardin system names in the verbose v1.0 wording, kept unchanged for pipelines keyed to it. Prefer cowardin\_system\_names, which comes from the authoritative NWI code table. |
| `wetland_types` | array | Unique plain-English NWI wetland types (WETLAND\_TYPE) within the radius, e.g. Lake, Freshwater Emergent Wetland, Estuarine and Marine Wetland. |
| `nearest_wetland_type` | string | Plain-English NWI type of the TRUE nearest wetland polygon. In v1.0 this field held the largest-acreage feature instead; v1.1 measures the nearest and preserves the old meaning in primary\_wetland\_type\_by\_acreage. See distance\_method for how it was resolved. |
| `nearest_wetland_code` | string | Cowardin classification code of the TRUE nearest wetland polygon. |
| `total_acres_within_radius` | number | Sum of NWI ACRES across every wetland polygon intersecting the radius. NULL when the feature set was truncated - a sum over an arbitrary subset is a wrong answer, not a partial one. |
| `section_404_flag` | boolean | True when a mapped wetland or deepwater habitat is present within the radius, indicating the site may trigger Clean Water Act Section 404 permitting and a formal wetland delineation. NULL when any contributing NWI query was unavailable. Screening indicator only - NOT a jurisdictional determination. |
| `error` | string | Error message on an ERROR row (bad coordinates, or every NWI query failing for this site). Null on a successful row. |
| `checked_at` | string | ISO 8601 UTC timestamp of the screening run. |
| `source_url` | string | USFWS National Wetlands Inventory MapServer layer the wetland data came from. |

#### Per-source outcome contract (read these before trusting anything else)

| Field | Type | Description |
|---|---|---|
| `nwi_status` | string | Overall outcome of the NWI reads for this site: ok, partial (some data retrieved, some missing or truncated), or unavailable. |
| `nwi_error` | string | Concatenated per-query failure messages when anything went wrong. Null on a fully clean row. |
| `onsite_query_status` | string | Outcome of the point-in-polygon query: ok or unavailable. |
| `radius_query_status` | string | Outcome of the circular radius query: ok, partial (truncated at the page cap) or unavailable. |
| `nearest_query_status` | string | Outcome of the nearest-wetland search: ok, none\_within\_search\_radius, skipped (turned off via computeNearestDistance) or unavailable. |
| `data_partial` | boolean | True when this row was built from an incomplete set of NWI reads. Read it before trusting any count or acreage on the row. |
| `results_truncated` | boolean | True when the NWI service reported exceededTransferLimit and the page cap was reached, so not every polygon in the radius was retrieved. Acreage and composition fields are nulled out when this is true. |
| `query_geometry_method` | string | Which geometry was sent to the service: circle\_buffer (a true point + distance query, the v1.1 default) or bbox\_envelope (the v1.0 fallback, which over-reports). |
| `wetland_count_reported_by_server` | integer | Exact polygon count returned by a returnCountOnly query against the same circle. Compare against the number of retrieved features to detect truncation independently. |

#### On-site point-in-polygon

| Field | Type | Description |
|---|---|---|
| `wetland_on_site` | boolean | True when the site coordinate itself falls inside a mapped NWI wetland polygon (a true point-in-polygon test, distance parameters omitted - distance=0 returns nothing on this service). NULL when the point-in-polygon query was unavailable. |
| `on_site_wetland_code` | string | Cowardin classification code of the wetland polygon containing the site coordinate. Null when the site is not inside one. |
| `on_site_wetland_type` | string | Plain-English NWI type of the wetland polygon containing the site coordinate. |
| `on_site_wetland_acres` | number | NWI-reported acreage of the wetland polygon containing the site coordinate. |
| `on_site_system_name` | string | Cowardin system of the on-site polygon (Palustrine, Lacustrine, Riverine, Estuarine, Marine) from the NWI code table. |
| `on_site_class_name` | string | Cowardin class of the on-site polygon, e.g. Emergent, Forested, Scrub-Shrub, Unconsolidated Bottom. |
| `on_site_water_regime_name` | string | Cowardin water regime of the on-site polygon, e.g. Seasonally Flooded, Permanently Flooded, Irregularly Flooded. |
| `on_site_objectid` | integer | NWI OBJECTID of the polygon containing the site coordinate, for cross-reference against the Wetlands Mapper. |

#### Measured nearest wetland

| Field | Type | Description |
|---|---|---|
| `nearest_wetland_distance_m` | number | Measured distance in metres from the site coordinate to the boundary of the nearest NWI wetland polygon. 0 when the site is inside one. Null when no wetland lies within the nearest-search radius or the search was skipped. Always read distance\_method with this value. |
| `nearest_wetland_distance_lower_bound_m` | number | Lower bound established by the server-side distance bisection. The true distance lies between this and the reported value plus the tolerance. |
| `nearest_wetland_distance_tolerance_m` | number | Accuracy envelope of the reported distance, in metres: the polygon generalization tolerance for a geometry\_measured value, or the bisection bracket width for a ring\_bisection value. |
| `nearest_wetland_bearing_deg` | number | Compass bearing in degrees (0-360, 0 = north) from the site to the closest point on the nearest wetland. Null when the distance came from the bisection only. |
| `nearest_wetland_direction` | string | 16-point compass label for nearest\_wetland\_bearing\_deg, e.g. N, ENE, SSW. |
| `nearest_wetland_acres` | number | NWI-reported acreage of the nearest wetland polygon. |
| `nearest_wetland_objectid` | integer | NWI OBJECTID of the nearest wetland polygon. |
| `nearest_wetland_system_name` | string | Cowardin system of the nearest wetland polygon. |
| `nearest_wetland_subsystem_name` | string | Cowardin subsystem of the nearest polygon, e.g. Limnetic, Littoral, Intertidal, Lower Perennial. Blank for Palustrine, which has no subsystem. |
| `nearest_wetland_class_name` | string | Cowardin class of the nearest wetland polygon. |
| `nearest_wetland_subclass_name` | string | Cowardin subclass of the nearest polygon, e.g. Persistent, Broad-Leaved Deciduous, Needle-Leaved Evergreen. |
| `nearest_wetland_water_regime_name` | string | Cowardin water regime of the nearest wetland polygon. |
| `nearest_wetland_water_regime_subgroup` | string | Nontidal, Saltwater Tidal or Freshwater Tidal for the nearest polygon. Tidal waters are categorically waters of the United States. |
| `nearest_wetland_modifiers` | array | Cowardin special modifiers on the nearest polygon, e.g. Excavated, Diked/Impounded, Farmed, Partially Drained/Ditched, Beaver. |
| `nearest_wetland_within_search_radius` | boolean | True when a wetland was found inside nearest\_search\_radius\_m, false when the search completed and found none, null when the search did not run. |
| `nearest_search_radius_m` | integer | Radius in metres searched for the nearest wetland. Independent of radius\_meters, so a site can read "no wetland within 300 m" and still report the closest one 1,391 m away. |
| `distance_method` | string | How nearest\_wetland\_distance\_m was produced: point\_in\_polygon (exact, site is inside), geometry\_measured (measured against the polygon boundary in WGS84), ring\_bisection (bracketed by server-side distance queries, upper bound reported), none\_within\_search\_radius, skipped or unavailable. A proxy is never reported as a measurement. |
| `nearest_basis` | string | One sentence explaining exactly how the nearest wetland was resolved, for the audit trail. |

#### Largest-acreage feature (what v1.0 called "nearest")

| Field | Type | Description |
|---|---|---|
| `primary_wetland_code_by_acreage` | string | Cowardin code of the LARGEST-ACREAGE wetland within the radius. This is what v1.0 reported in nearest\_wetland\_code; it is preserved here under its true name. |
| `primary_wetland_type_by_acreage` | string | Plain-English type of the largest-acreage wetland within the radius. |
| `primary_wetland_acres` | number | Acreage of the largest-acreage wetland within the radius. |

#### Full Cowardin decode across the radius

| Field | Type | Description |
|---|---|---|
| `cowardin_system_names` | array | Authoritative Cowardin system names present within the radius, from the NWI code table join: Palustrine, Lacustrine, Riverine, Estuarine, Marine. |
| `cowardin_subsystem_names` | array | Cowardin subsystems present within the radius: Limnetic, Littoral, Subtidal, Intertidal, Tidal, Lower Perennial, Upper Perennial, Intermittent. |
| `cowardin_class_names` | array | Cowardin classes present within the radius: Emergent, Forested, Scrub-Shrub, Unconsolidated Bottom, Aquatic Bed, Unconsolidated Shore, Rocky Shore, Reef, Streambed, Rock Bottom, Moss-Lichen Wetland. |
| `cowardin_subclass_names` | array | Cowardin subclasses present within the radius, e.g. Persistent, Broad-Leaved Deciduous, Needle-Leaved Evergreen. This is the vegetation detail a delineator needs. |
| `cowardin_split_class_names` | array | Second class of any split-class polygon (a code like PFO2/SS3C is Forested over Scrub-Shrub). Present on real mixed-vegetation mapping units. |
| `cowardin_water_regime_names` | array | Cowardin water regimes present within the radius, e.g. Temporary Flooded, Seasonally Flooded, Semipermanently Flooded, Permanently Flooded, Irregularly Flooded. This drives hydrology expectations on a delineation. |
| `cowardin_water_regime_subgroups` | array | Nontidal, Saltwater Tidal and/or Freshwater Tidal across the radius. |
| `cowardin_special_modifiers` | array | Cowardin special modifiers present within the radius: Excavated, Diked/Impounded, Farmed, Partially Drained/Ditched, Artificial Substrate, Spoil, Beaver. These bear directly on whether a feature is jurisdictional. |

#### Composition and acreage

| Field | Type | Description |
|---|---|---|
| `acres_by_wetland_type` | array | Per-type breakdown within the radius: \[{ wetland\_type, count, acres }], sorted by acreage. Empty when the feature set was truncated. |
| `acres_by_system` | array | Per-system breakdown within the radius: \[{ system\_name, count, acres }], sorted by acreage. Empty when the feature set was truncated. |
| `palustrine_acres` | number | Total Palustrine (marsh, swamp, bog, pond) acreage within the radius. Null when the feature set was truncated. |
| `lacustrine_acres` | number | Total Lacustrine (lake and reservoir) acreage within the radius. |
| `riverine_acres` | number | Total Riverine (river and stream channel) acreage within the radius. |
| `estuarine_acres` | number | Total Estuarine (tidal, river-meets-sea) acreage within the radius. |
| `marine_acres` | number | Total Marine (open ocean and coastline) acreage within the radius. |
| `largest_wetland_acres` | number | Acreage of the single largest wetland polygon within the radius. |
| `smallest_wetland_acres` | number | Acreage of the single smallest wetland polygon within the radius. Small isolated Palustrine features are the ones most likely to be contested post-Sackett. |

#### Jurisdictional screen

| Field | Type | Description |
|---|---|---|
| `tidal_wetland_present` | boolean | True when an Estuarine or Marine system, or any tidal water regime, is mapped within the radius. NULL when the radius query was unavailable. |
| `deepwater_habitat_present` | boolean | True when a Cowardin deepwater habitat (Lacustrine Limnetic, Marine or Estuarine Subtidal, or perennial Riverine channel) is mapped within the radius. Deepwater habitats are waters of the United States rather than wetlands, and carry a different Section 404 posture. |
| `excavated_or_impounded_present` | boolean | True when a mapped feature carries an Excavated, Diked/Impounded, Artificial Substrate, Spoil or Artificially Flooded modifier. |
| `farmed_or_drained_present` | boolean | True when a mapped feature carries a Farmed or Partially Drained/Ditched modifier. Prior-converted cropland may be excluded from Section 404 jurisdiction. |
| `jurisdictional_likelihood` | string | Screening-level likelihood that a Section 404 water is present at or beside the site: high, moderate, low, or none\_mapped. NULL when any contributing query was unavailable. Read jurisdictional\_basis for the reasoning. Not a jurisdictional determination. |
| `jurisdictional_basis` | array | The specific facts that produced jurisdictional\_likelihood, one sentence each - the audit trail a reviewer can check. |
| `delineation_recommended` | boolean | True when the screen indicates a formal wetland delineation is warranted before ground disturbance. NULL when the screen could not be completed. |
| `section_404_basis` | array | The specific facts behind section\_404\_flag, including the caveat that a false flag applies only to the stated radius. |

Every field is nullable. `null` means **not checked**; `false` means **checked and negative**.

### How the answer is produced

1. **Layer health check (live, every run).** The layer must still expose the fully-qualified `Wetlands.*` columns and at least 20 `NWI_Wetland_Codes.*` join columns. If the join is dropped, the Cowardin decode would silently render null on every row - so the run **fails** instead.
2. **Canary (live, every run).** A point inside Reelfoot Lake, TN must read back a Cowardin code, over 100 acres, a populated `SYSTEM_NAME`, and a join whose `SYSTEM` agrees with the first letter of the code. This catches an emptied layer, a broken join, and a join keyed to the wrong column. It is exactly the assertion that would have caught the July 2026 NWI outage on the first run instead of after a month on hold.
3. **Point-in-polygon** at the coordinate (with the `distance` parameter **omitted** - `distance=0` returns `objectIds: null` on this service).
4. **Exact count** for the circle, then **every page** of features, following `exceededTransferLimit`.
5. **Nearest wetland**: 0 m if the site is inside a polygon; otherwise the buffer distance is bisected server-side to bracket the true edge, the winning polygon is identified, and its generalized boundary is fetched **in WGS84** and measured. A failed geometry read degrades to the bracket and says so - it never becomes a guess.

#### Reliability, stated plainly

- Every source records its own outcome on the row (`onsite_query_status`, `radius_query_status`, `nearest_query_status`, `nwi_status`).
- `section_404_flag`, `jurisdictional_likelihood`, `wetland_on_site` and every presence flag are **gated**: they read `null` when a contributing query did not answer. A dead upstream can never render as "no wetland found".
- A truncated fetch nulls `total_acres_within_radius` and the per-system acreage rather than publishing a sum over an arbitrary subset - while still reporting the **exact** server-side count.
- If every screened site fails, the run **fails and pushes nothing at all** - not one error row - so nothing is billed. Rows are buffered in memory and the billing decision is made **before** the first `pushData`, because Apify charges for dataset items even on a run that ends FAILED. A *partial* failure is different: every row is still emitted, including the ones that failed, so you can see exactly which sites are missing and why.
- An asset whose coordinates cannot be parsed is your input, not an outage: on an otherwise healthy run it comes back as a normal error row. If the upstream is dead as well, those rows are withheld too.
- The geometry guard checks the declared spatial reference **and** coordinate magnitude (`|lon| <= 180`), bounded by each feature's own envelope. A legitimately enormous coastal polygon passes; Web Mercator metres do not.

### Use as an MCP tool

This Actor is callable directly by any MCP-compatible AI agent through Apify's hosted
MCP server. There is no server to run and no integration code to write - the tool
schema an agent sees is generated from this Actor's own input and dataset schemas.

**Endpoint**

```
https://mcp.apify.com?tools=malonestar/fws-wetlands-proximity-screener
```

**Claude Desktop, Claude Code or Cursor** - add to `claude_desktop_config.json`,
`.mcp.json` or `.cursor/mcp.json` respectively:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=malonestar/fws-wetlands-proximity-screener",
      "headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }
    }
  }
}
```

Get a token at https://console.apify.com/settings/integrations. Claude Desktop can
also authenticate interactively via OAuth against `https://mcp.apify.com` with no
`headers` block. Full reference: https://docs.apify.com/platform/integrations/mcp

**Try asking your agent**

> Are there NWI-mapped wetlands within 300 m of 39.7392,-104.9903, and how far is the nearest one?

**Chains well with** - expose these alongside it by comma-separating the `tools`
parameter, and the agent can carry results from one into the next:

- `malonestar/nhd-surface-water-404-screener`
- `malonestar/epa-contaminated-site-screener`
- `malonestar/site-due-diligence-bundle`

```
https://mcp.apify.com?tools=malonestar/fws-wetlands-proximity-screener,malonestar/nhd-surface-water-404-screener,malonestar/epa-contaminated-site-screener,malonestar/site-due-diligence-bundle
```

Billing is unchanged when called as an MCP tool: this Actor is Pay-Per-Event and an
agent pays the same per-result price a human does. A run that cannot answer fails
without billing rather than returning an unverified negative.

### Pricing

**$8 per 1,000 results** (pay per event, Result only). One result = one screened site, whether or not a wetland is found - a verified "no wetland within 500 m, nearest is 1,391 m north" is the answer you paid for. Graduated discounts apply on paid Apify plans (Bronze -20% through Diamond -70%). There are no custom charge events.

### Related actors (they cross-sell each other)

| Actor | Why you want it alongside this one |
|---|---|
| **NHD Surface Water & Section 404 Screener** | The **surface-water half of the same question**. This actor covers NWI wetlands; that one covers NHD streams, rivers, ponds and washes with relative-permanence proxies. Run both for a complete Section 404 picture - a site can be clear of mapped wetlands and still sit on a jurisdictional tributary. |
| **EPA Impaired Waters (303d) Screener** | Once you know a water is present, this tells you whether it is listed as impaired - which changes permitting conditions. |
| **NOAA Essential Fish Habitat Consultation Screener** | The marine/estuarine consultation trigger under Magnuson-Stevens 305(b)(2), for coastal sites this actor flags as Estuarine or Marine. |
| **USFWS Critical Habitat Screener** | ESA Section 7 exposure at the same coordinates. |
| **EPA Contaminated Site Screener** | The other standard Phase I ESA line item: Superfund, RCRA, USTs and enforcement history. |
| **Site Due Diligence Bundle** | Twenty layers including this one, for a single coordinate, with a composite site score. |

### FAQ

**Is this a wetland delineation?** No. NWI is a remote-sensing-derived inventory at roughly 1:12,000 to 1:24,000 scale. It is the accepted desktop screen and the starting point for a delineation - `delineation_recommended` is the field that tells you when to order one.

**Why is `section_404_flag` false but `nearest_wetland_distance_m` only 600 m?** Because the flag answers your `radiusMeters` question and nothing else. `section_404_basis` says so on the row. Widen `radiusMeters` if 600 m matters to you.

**Why is a field `null` instead of `false`?** `null` means the query that would have answered it did not complete. `false` means it completed and the answer was negative. The two are never interchangeable here.

**What does `distance_method` tell me?** How the distance was obtained: `point_in_polygon` (exact 0), `geometry_measured` (measured against the polygon boundary, tolerance published), `ring_bisection` (bracketed by server-side queries, upper bound reported), `none_within_search_radius`, `skipped` or `unavailable`. A proxy is never reported as a measurement.

**Does it cover Alaska, Hawaii and the territories?** NWI coverage is national including AK, HI, PR and the Pacific territories, though mapping vintage and detail vary by region. The actor reports what the service returns.

**How current is the data?** The NWI is updated continuously by USFWS as new mapping is published; there is no per-polygon date in the service, so the actor reports `checked_at` (when it asked) rather than implying a data vintage it cannot see.

**Source:** USFWS National Wetlands Inventory, `fwspublicservices.wim.usgs.gov/wetlandsmapservice/rest/services/Wetlands/MapServer/0`. Public domain, keyless.

# Actor input Schema

## `assets` (type: `array`):

Sites to screen for wetlands. Each entry is an object { "lat": number, "lon": number, "label": "optional name" }. Also accepts "lat,lon" strings or \[lat, lon] arrays. One dataset row (one billed result) is produced per asset, even when no wetland is found; a bad entry yields an ERROR row and the run continues.

## `radiusMeters` (type: `integer`):

Radius around each asset used for the wetland-presence check, in meters (10-5000). Screened as a TRUE circle. Default 300 (~984 ft, roughly a parcel-scale buffer).

## `computeNearestDistance` (type: `boolean`):

When on (default), the actor measures the true distance and bearing to the nearest NWI wetland polygon instead of reporting a largest-acreage proxy. Costs up to ~10 small extra requests per site. Turn off for very large batches; nearest\_wetland\_\* then falls back to the largest-acreage feature and nearest\_basis says so.

## `nearestSearchRadiusMeters` (type: `integer`):

How far out to look for the nearest wetland, in meters (up to 8000). Independent of the screening radius, so a site can correctly read 'no wetland within 300 m' and still report the closest one 1,391 m away. Default 1609 (1 mile). Raised automatically to at least the screening radius.

## `maxResults` (type: `integer`):

Maximum number of assets processed in one run (1-2000). One result row is emitted (and billed) per asset. Default 500.

## Actor input object example

```json
{
  "assets": [
    {
      "lat": 36.3736,
      "lon": -89.385,
      "label": "Reelfoot Lake, TN - site inside a mapped lake"
    },
    {
      "lat": 35.2216,
      "lon": -75.6913,
      "label": "Cape Hatteras, NC - estuarine tidal marsh"
    },
    {
      "lat": 45.8918,
      "lon": -123.9615,
      "label": "Cannon Beach, OR - marine shoreline"
    },
    {
      "lat": 47.5,
      "lon": -99,
      "label": "Prairie pothole, ND - farmed and drained wetlands"
    },
    {
      "lat": 39.7392,
      "lon": -104.9903,
      "label": "Denver, CO - urban infill, nearest wetland 561 m"
    },
    {
      "lat": 33.4484,
      "lon": -112.074,
      "label": "Phoenix, AZ - dry upland reference point"
    }
  ],
  "radiusMeters": 300,
  "computeNearestDistance": true,
  "nearestSearchRadiusMeters": 1609,
  "maxResults": 500
}
```

# Actor output Schema

## `results` (type: `string`):

The default dataset (one row per asset).

# 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 = {
    "assets": [
        {
            "lat": 36.3736,
            "lon": -89.385,
            "label": "Reelfoot Lake, TN - site inside a mapped lake"
        },
        {
            "lat": 35.2216,
            "lon": -75.6913,
            "label": "Cape Hatteras, NC - estuarine tidal marsh"
        },
        {
            "lat": 45.8918,
            "lon": -123.9615,
            "label": "Cannon Beach, OR - marine shoreline"
        },
        {
            "lat": 47.5,
            "lon": -99,
            "label": "Prairie pothole, ND - farmed and drained wetlands"
        },
        {
            "lat": 39.7392,
            "lon": -104.9903,
            "label": "Denver, CO - urban infill, nearest wetland 561 m"
        },
        {
            "lat": 33.4484,
            "lon": -112.074,
            "label": "Phoenix, AZ - dry upland reference point"
        }
    ],
    "radiusMeters": 300,
    "computeNearestDistance": true,
    "nearestSearchRadiusMeters": 1609
};

// Run the Actor and wait for it to finish
const run = await client.actor("malonestar/fws-wetlands-proximity-screener").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 = {
    "assets": [
        {
            "lat": 36.3736,
            "lon": -89.385,
            "label": "Reelfoot Lake, TN - site inside a mapped lake",
        },
        {
            "lat": 35.2216,
            "lon": -75.6913,
            "label": "Cape Hatteras, NC - estuarine tidal marsh",
        },
        {
            "lat": 45.8918,
            "lon": -123.9615,
            "label": "Cannon Beach, OR - marine shoreline",
        },
        {
            "lat": 47.5,
            "lon": -99,
            "label": "Prairie pothole, ND - farmed and drained wetlands",
        },
        {
            "lat": 39.7392,
            "lon": -104.9903,
            "label": "Denver, CO - urban infill, nearest wetland 561 m",
        },
        {
            "lat": 33.4484,
            "lon": -112.074,
            "label": "Phoenix, AZ - dry upland reference point",
        },
    ],
    "radiusMeters": 300,
    "computeNearestDistance": True,
    "nearestSearchRadiusMeters": 1609,
}

# Run the Actor and wait for it to finish
run = client.actor("malonestar/fws-wetlands-proximity-screener").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 '{
  "assets": [
    {
      "lat": 36.3736,
      "lon": -89.385,
      "label": "Reelfoot Lake, TN - site inside a mapped lake"
    },
    {
      "lat": 35.2216,
      "lon": -75.6913,
      "label": "Cape Hatteras, NC - estuarine tidal marsh"
    },
    {
      "lat": 45.8918,
      "lon": -123.9615,
      "label": "Cannon Beach, OR - marine shoreline"
    },
    {
      "lat": 47.5,
      "lon": -99,
      "label": "Prairie pothole, ND - farmed and drained wetlands"
    },
    {
      "lat": 39.7392,
      "lon": -104.9903,
      "label": "Denver, CO - urban infill, nearest wetland 561 m"
    },
    {
      "lat": 33.4484,
      "lon": -112.074,
      "label": "Phoenix, AZ - dry upland reference point"
    }
  ],
  "radiusMeters": 300,
  "computeNearestDistance": true,
  "nearestSearchRadiusMeters": 1609
}' |
apify call malonestar/fws-wetlands-proximity-screener --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,malonestar/fws-wetlands-proximity-screener"
        }
    }
}

```

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/GcI5b5BkG7v9241kV/builds/KalFlV3mAUfLbg6oZ/openapi.json
