# FEMA Flood Zone Batch Lookup - Pay Only for Hits (`the-stack-underflow/fema-flood-zone-batch`) Actor

Bulk FEMA flood zone check for US addresses, a CSV, or a property scraper's dataset: zone, SFHA, base flood elevation, FIRM panel, LOMRs. Charged only for rows FEMA answered.

- **URL**: https://apify.com/the-stack-underflow/fema-flood-zone-batch.md
- **Developed by:** [The Stack Underflow](https://apify.com/the-stack-underflow) (community)
- **Categories:** Real estate, Automation, Developer tools
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 answered flood zone rows

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/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

## FEMA Flood Zone Batch Lookup: pay only for hits

Check a list of US addresses against **FEMA's flood maps** in one run. Paste
the addresses, upload a CSV, or feed in another Actor's results, and get one
row per property: **flood zone, SFHA yes/no, base flood elevation, FIRM panel
and date, NFIP community and Letters of Map Revision**. Export it to Excel,
CSV or JSON.

**You are charged only for rows FEMA answered.** Addresses the geocoder cannot
place, ambiguous addresses, points outside the US, points with no digital FEMA
map, service errors and repeated lines are listed in the output and cost
nothing.

**Price:** $4–$8 per 1,000 answered rows ($0.008 a row on Apify's Free plan,
down to $0.004 on Gold); nothing else, no compute charge. **Try it on Apify's
free plan:** its $5 monthly credit covers about 600 answered rows.

**Why not the cheapest per-row lookup?** You pay per *answered* row, not per
input line: not-found, unmapped, ambiguous and repeated addresses are free. Each
row carries SFHA, floodway, base flood elevation with its datum, FIRM panel and
date, and LOMRs, keeps your own columns, and links to FEMA's Map Service Center
so you can verify it.

### Flood zones for your Zillow, Redfin or Realtor.com scrape

Already scraping listings? Feed the results in and see which properties sit in
FEMA's Special Flood Hazard Area, where lenders generally require flood
insurance. You get zone, base flood elevation and FIRM panel per listing, next
to the scraper's own top-level columns (zpid, URL, status...). 1,000 new
listings take about 9 minutes.

1. Open your scraper's finished run → **Storage** → copy the **dataset ID**.
2. Paste it into **Dataset from another Actor** here and start.

Listing sites show a flood *risk score*. Lenders and insurers go by the FEMA
*zone*, and this Actor reports that, with the panel and LOMRs to back it up.

Built for the published output format of
[Zillow Scraper](https://apify.com/maxcopell/zillow-scraper),
[Zillow Detail Scraper](https://apify.com/maxcopell/zillow-detail-scraper),
[Zillow ZIP Search](https://apify.com/maxcopell/zillow-zip-search),
[Realtor.com Scraper](https://apify.com/epctex/realtor-scraper),
[Redfin Search](https://apify.com/tri_angle/redfin-search) and
[Redfin Detail](https://apify.com/tri_angle/redfin-detail): their coordinates are
used when present, otherwise their address fields. Any other dataset works
too if it has an address, street + city + state, or latitude + longitude field.
(Not affiliated with those Actors or sites.)

### What you get per row

| Column                                          | Meaning                                                                                                                                                                        |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `zone`, `zone_subtype`                          | FEMA zone as published (A, AE, AH, AO, VE, X, D...) and its subtype (e.g. FLOODWAY, 0.2 PCT ANNUAL CHANCE)                                                                     |
| `risk_level`                                    | high, coastal_high, moderate, minimal, undetermined, other (open water), or unmapped (no digital FEMA map: *not* low risk)                                                     |
| `sfha`                                          | Inside the Special Flood Hazard Area, where lenders generally require flood insurance                                                                                          |
| `floodway`                                      | Inside a regulatory floodway                                                                                                                                                   |
| `bfe`, `bfe_unit`, `bfe_datum`                  | Base flood elevation with its vertical datum (NAVD88, NGVD29). Empty, never 0, where the zone carries none (along rivers FEMA publishes BFEs as separate lines: check the map) |
| `depth`, `depth_unit`                           | Flood depth in AO zones                                                                                                                                                        |
| `firm_id`, `firm_panel`, `panel_effective_date` | The FIRM study and panel that answered, and when it took effect                                                                                                                |
| `community_id`, `community_name`                | The NFIP community                                                                                                                                                             |
| `lomr_cases`, `lomr_effective_date`             | Letters of Map Revision in effect at the point                                                                                                                                 |
| `on_zone_boundary`, `other_zones`               | The point touches more than one zone; the higher-risk zone is reported                                                                                                         |
| `matched_address`, `lat`, `lon`                 | Where the Census geocoder placed the address: check this against your input                                                                                                    |
| `summary`                                       | One plain-English sentence, ready for a report                                                                                                                                 |
| `msc_link`                                      | FEMA Map Service Center search for the point                                                                                                                                   |
| `status`, `charged`, `error`, `candidates`      | ok / unmapped / not_found / ambiguous / invalid / error / skipped_limit; for an ambiguous address, the places it could be                                                      |
| `id`, `source_row`                              | Your own id column, and your original columns (the first 40 plain-value columns), copied through                                                                               |
| `fema_dataset_version`, `retrieved_at`          | Which FEMA panel answered, and when it was read                                                                                                                                |

Rows come back in your input order. The **Flood zones** view of the dataset
shows the key columns; export the full dataset for everything.

### Input

Use any of these, or several at once (up to **50,000 rows** per run):

- **Addresses or coordinates:** one per line, a US street address with city and
  state (`1700 Convention Center Dr, Miami Beach, FL 33139`) or `latitude, longitude`
  (`39.059, -75.399`).
- **CSV file:** upload one or give its URL. It needs a header row and either an
  `address` column (also `full_address`, `property_address`), or `street` +
  `city` + `state` (+ `zip`), or `lat` + `lon`. Name the column in **Address
  column** if it is called something else. An `address` column that holds only
  the street line is combined with the `city`, `state` and `zip` columns, and ZIP
  codes that lost their leading zero in Excel (2134) are restored (02134). When a
  row has usable `lat` and `lon`, those win over the address. Your columns,
  including your loan or property id, are copied into the output. Comma,
  semicolon and tab separated files work; save Excel workbooks as CSV first.
- **Dataset from another Actor:** run straight on a property scraper's results
  (see above): the `address` / `listingAddress` objects and the coordinates of
  the scrapers listed there are read, plus flat `latitude` / `longitude` fields.

Example CSV:

```csv
loan_id,address
L-1001,"1700 Convention Center Dr, Miami Beach, FL 33139"
L-1002,"411 Legislative Ave, Dover, DE 19901"
```

### Pricing

One `flood-zone-row` event per answered row: $0.008 (Free plan), $0.006
(Bronze), $0.005 (Silver), $0.004 (Gold and above). Nothing else is charged:

- not found, unmapped, ambiguous, invalid or failed rows: **free**;
- the same address twice in one run (ignoring case, spacing and commas):
  answered twice, **charged once**;
- your **maximum charge per run** is respected: when it is reached the run stops
  cleanly and the remaining rows are listed as `skipped_limit`, uncharged.
- rows are saved before they are charged, so you never pay for a row you
  did not receive.

### How it works

Addresses are placed with the **U.S. Census Bureau geocoder**, then the zone is
read **live from FEMA's National Flood Hazard Layer** at that point, so the
answer is FEMA's current effective map at the time it was read; answers are
reused for up to 30 days, and `retrieved_at` says when each was read.

### Coverage and limits

- Wherever FEMA has a digital flood map. Areas with only paper maps, or none,
  come back as `unmapped`: that is not low risk.
- US addresses only (states, DC and territories the Census geocoder covers).
  New-build and rural addresses the Census geocoder does not know come back
  `not_found`, uncharged; give `lat, lon` for those.
- An address is placed at an interpolated street position, not the building
  itself. Large parcels can straddle zones: `on_zone_boundary` flags the cases
  where the point itself touches more than one.

### Important: what a flood answer is, and is not

Informational screening only. It is **not** an official FEMA flood zone
determination (Standard Flood Hazard Determination Form, FEMA Form 086-0-32),
not an elevation certificate, and not insurance or lending advice. Maps change
through revisions. Zone X does not mean no flood risk. Verify at msc.fema.gov.
Data is provided as is, without warranty.

### FAQ

**Is the data free to use?** It is US federal government data (17 U.S.C. §105).
You pay for the hosted lookup. Keep the FEMA attribution when you publish
results.

**How fast is it?** About 2 new addresses per second, measured: FEMA's map
service is queried at a polite rate. 10,000 new addresses take about 90
minutes; addresses looked up in the last 30 days come back much faster. The
default run timeout (12 hours) covers the full 50,000 rows.

**One property at a time, from an AI agent?** Use the
[US Flood Zone & Property Risk MCP](https://apify.com/the-stack-underflow/datum-property):
the same lookup, plus disaster, storm and earthquake history and demographics.

**What if a row looks wrong?** Open an issue on the **Issues** tab with the
input line and the `matched_address`.

### Notices

Flood hazard data: FEMA National Flood Hazard Layer, provided as is and
not endorsed by FEMA. The Federal Government or FEMA cannot vouch for the data or
analyses derived from these data after the data have been retrieved from the
Agency's website(s).

Geocoding: U.S. Census Bureau Geocoder. This product uses the Census Bureau Data
API but is not endorsed or certified by the Census Bureau.

# Actor input Schema

## `addresses` (type: `array`):

One per line: a US street address with city and state (ZIP helps), or "latitude, longitude".

## `csvFile` (type: `string`):

Upload a CSV or give its URL. Needs a header row with an address column (address, full_address, property_address), or street + city + state (+ zip), or lat + lon. Your columns, including your own id, are copied into the output (the first 40). Save Excel workbooks as CSV first.

## `datasetId` (type: `string`):

Run on the items of a dataset, for example a Zillow, Redfin or Realtor.com scraper's results: open that run's Storage tab and copy the dataset ID. Their address and coordinate fields are recognised, and their top-level columns are copied into the output.

## `addressColumn` (type: `string`):

The CSV column or dataset field holding the full address, if it is not detected automatically.

## Actor input object example

```json
{
  "addresses": [
    "1700 Convention Center Dr, Miami Beach, FL 33139",
    "411 Legislative Ave, Dover, DE 19901",
    "39.059, -75.399"
  ]
}
```

# Actor output Schema

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

No description

## `summary` (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 = {
    "addresses": [
        "1700 Convention Center Dr, Miami Beach, FL 33139",
        "411 Legislative Ave, Dover, DE 19901",
        "39.059, -75.399"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("the-stack-underflow/fema-flood-zone-batch").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 = { "addresses": [
        "1700 Convention Center Dr, Miami Beach, FL 33139",
        "411 Legislative Ave, Dover, DE 19901",
        "39.059, -75.399",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("the-stack-underflow/fema-flood-zone-batch").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 '{
  "addresses": [
    "1700 Convention Center Dr, Miami Beach, FL 33139",
    "411 Legislative Ave, Dover, DE 19901",
    "39.059, -75.399"
  ]
}' |
apify call the-stack-underflow/fema-flood-zone-batch --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,the-stack-underflow/fema-flood-zone-batch"
        }
    }
}
```

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/RuJFhu95p5ZJ5I9X8/builds/eQrBORoHWStIVNJQ5/openapi.json
