# Storm & Hail Damage Leads: NOAA Hail Reports by ZIP Code (`clearfeedlabs/storm-roofing-feed`) Actor

ZIP codes hit by hail, damaging wind, tornadoes and hurricanes from official NWS warnings, NOAA Storm Events and OpenFEMA declarations, scored by severity and joined with city roofing-permit surges. Street-level permit counts, no homeowner data. Incremental runs.

- **URL**: https://apify.com/clearfeedlabs/storm-roofing-feed.md
- **Developed by:** [Clearfeed Labs](https://apify.com/clearfeedlabs) (community)
- **Categories:** Lead generation, Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 storm zip rows

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Hail & Storm Damage Leads API: ZIP Codes Hit by Hail, Wind & Tornadoes

**Storm-to-Roofing Feed** turns official U.S. storm data into a clean list of the ZIP codes that were just hit by hail, damaging wind, tornadoes or hurricanes, scored by severity, tagged with any FEMA disaster declaration, and (in covered cities) joined with **roofing-permit surges** so you can see where re-roof work is actually climbing. One row per ZIP code per storm event. Run it on a schedule and you only get, and pay for, ZIP-events that are new or changed since your last run.

Built for **licensed roofing, siding, gutter and restoration contractors**, storm-response sales teams, insurance and claims operations, building-supply distributors and market analysts.

### Why use it

- **Official sources only.** National Weather Service warnings (api.weather.gov), NOAA NCEI Storm Events, OpenFEMA, and city open-data permit portals. No logins, no proxies, no scraping of private sites.
- **ZIP-level, ready to act on.** Max hail size, max wind gust, tornado flag, report count, county, ZIP centroid and a 0-100 severity score with a tier (low / moderate / severe / extreme).
- **Roofing-permit surge layer.** In Austin, Dallas and Fort Worth TX, Miami-Dade County FL, Minneapolis MN, New Orleans LA and Baton Rouge LA, each storm ZIP gets the number of unique addresses with roof permits issued since the storm, the ZIP's normal weekly rate over the prior 52 weeks, a surge ratio, a z-score, a `permitSurge` flag, and the top streets by permit count.
- **No homeowner data.** No names, no phone numbers, no house numbers. Streets are reported only as street name + count of unique permitted addresses from public permit records.
- **Incremental.** `onlyNewSinceLastRun` (on by default) remembers what you've already received per `stateKey`.
- **About 90% cheaper** than per-report hail tools. Note: this is point-report and warning data, not radar-derived hail swaths.

### Example runs

Live example pages:

- [Austin hail + roofing-permit surge ZIPs](https://apify.com/clearfeedlabs/storm-roofing-feed/examples/austin-hail-roof-permit-surge)
- [Dallas & Fort Worth roofing-permit surge ZIPs](https://apify.com/clearfeedlabs/storm-roofing-feed/examples/dallas-fort-worth-roof-permit-surge)
- [Florida hurricane & FEMA-declared county ZIPs](https://apify.com/clearfeedlabs/storm-roofing-feed/examples/florida-hurricane-wind-fema-zips)

More input ideas:

- **Texas hail ≥ 1" ZIP alerts:** `{"states":["TX"],"eventTypes":["hail"],"minHailInches":"1","lookbackDays":3}`
- **Austin hail + roof-permit surge:** `{"states":["TX"],"includePermitSurgeZips":true,"permitCities":["austin"]}`
- **Florida hurricane/extreme wind + FEMA ZIPs:** `{"states":["FL"],"eventTypes":["hurricane","wind","tornado"],"minWindMph":74,"lookbackDays":7,"includeFemaCountyZips":true}`
- **Territory planning (last 6 months of verified reports):** `{"states":["CO","KS","OK"],"includeStormEventsHistory":true,"historyDays":180,"includeNwsAlerts":false}`

### Input

| Field | Default | What it does |
|---|---|---|
| `states` | `["TX"]` | 2-letter state codes |
| `lookbackDays` | 3 | Days of live NWS warnings (1-7) |
| `eventTypes` | all | `hail`, `wind`, `tornado`, `hurricane` |
| `minHailInches` / `minWindMph` | 1 / 58 | Severity thresholds |
| `bufferMiles` | 3 | ZIPs whose centre is within this distance of a storm report |
| `includeNwsAlerts` | true | Live Severe Thunderstorm, Tornado, Hurricane and Extreme Wind warnings |
| `includeStormEventsHistory` | false | NOAA NCEI verified reports (lag 2-4 months) |
| `includeFema` | true | Tag ZIPs in counties with a matching declaration |
| `includePermits` | true | Roof-permit layer in covered cities |
| `includeFemaCountyZips` | false | Also output every ZIP in FEMA-declared counties (last 120 days), even with no matched warning |
| `includePermitSurgeZips` | false | Also output covered ZIPs with a permit surge but no matched storm |
| `permitWindowDays` / `baselineWeeks` / `surgeRatio` / `minSurgePermits` | 14 / 52 / 2 / 5 | Surge definition |
| `onlyNewSinceLastRun` / `stateKey` | true / `default` | Delta memory |
| `maxRows` | 500 | Hard cap on billed rows |

### Output

Real row from an Austin run on Nov 1, 2026 (permit-surge ZIP, `includePermitSurgeZips: true`):

```json
{
  "eventId": "permit-surge-austin-2026-10-19",
  "eventDate": "2026-10-19T01:15:55.587Z",
  "eventType": "permit-surge",
  "source": [
    "PERMITS"
  ],
  "state": "TX",
  "county": "Travis County",
  "countyFips": "48453",
  "zip": "78653",
  "zipCentroidLat": 30.33969,
  "zipCentroidLon": -97.52349,
  "maxHailInches": null,
  "maxWindMph": null,
  "tornadoEF": null,
  "reportCount": 0,
  "nwsWarningIds": [],
  "headline": "Roof-permitted addresses up 14x vs 52-week baseline",
  "femaDeclarationNumber": null,
  "femaIncidentType": null,
  "femaDeclarationTitle": null,
  "severityScore": 0,
  "severityTier": "low",
  "permitCoverage": true,
  "permitCity": "Austin, TX",
  "roofPermitsSinceEvent": 7,
  "roofPermitWindowDays": 14,
  "roofPermitBaselineWeekly": 0.25,
  "permitSurgeRatio": 14,
  "permitSurgeZScore": 2.89,
  "permitSurge": true,
  "topStreets": [
    {
      "street": "PAMPERING DR",
      "permitCount": 5
    },
    {
      "street": "GAMBOL DR",
      "permitCount": 2
    }
  ],
  "sourceUrls": [
    "https://data.austintexas.gov/d/3syk-w9eu"
  ],
  "disclaimer": "Public U.S. government data (NOAA National Weather Service, NOAA NCEI Storm Events, OpenFEMA) and city open-data permit ...",
  "retrievedAt": "2026-11-02T01:15:55.587Z",
  "isNew": true,
  "changeType": "new"
}
```

Real FEMA county row from a Florida run (`includeFemaCountyZips: true`):

```json
{
  "eventId": "fema-EM-3655-FL",
  "eventDate": "2026-10-06T00:00:00.000Z",
  "eventType": "hurricane",
  "source": [
    "FEMA"
  ],
  "state": "FL",
  "county": "Lafayette County",
  "zip": "32008",
  "severityScore": 85,
  "severityTier": "extreme",
  "femaDeclarationNumber": "EM-3655-FL",
  "femaIncidentType": "Tropical Storm",
  "femaDeclarationTitle": "HURRICANE ISAIAS",
  "permitCoverage": false,
  "sourceUrls": [
    "https://www.fema.gov/disaster/3655"
  ]
}
```

`eventId` is stable: `nws-<office.phenomenon.significance.ETN.year>` for NWS warnings (all updates of one warning collapse into one event), `ncei-ep<episode>` for NOAA Storm Events, `permit-surge-<city>-<week>` for permit-only rows, `fema-<declaration>` for FEMA county rows. A run summary (sources used, row counts, permit cities, request counts) is saved as `RUN_SUMMARY` in the key-value store.

#### How the join works

1. **Storms → ZIPs.** NWS warning polygons are intersected with Census ZIP Code Tabulation Area (ZCTA) centroids (plus a small buffer); warnings without a polygon (e.g. hurricanes) use their county codes. NOAA point reports use ZIP centroids within `bufferMiles`.
2. **FEMA.** A declaration matches when the ZIP's county (or the whole state) is designated and the storm falls within the incident period.
3. **Permits.** Roof permits are pulled from each city's official open-data API, filtered to roof work (re-roof, roof, shingle; solar-only installs excluded), mapped to ZIP, counted as **unique addresses** (a property or complex with many permits counts once; the address key is hashed internally and never output), and compared with the ZIP's weekly mean of unique addresses over the prior 52 weeks. `permitSurge` = at least `minSurgePermits` permits and a weekly rate ≥ `surgeRatio` × baseline.

#### Permit coverage (v0.1)

| City | Portal | Notes |
|---|---|---|
| Austin, TX | data.austintexas.gov (Issued Construction Permits) | ZIP from permit record |
| Minneapolis, MN | City of Minneapolis CCS Permits (ArcGIS) | ZIP from nearest ZCTA centroid to permit point |
| New Orleans, LA | data.nola.gov (Permits, code ROOF) | ZIP from nearest ZCTA centroid |
| Baton Rouge, LA | data.brla.gov (EBR Building Permits, Re-Roof) | ZIP from permit record |
| Dallas, TX | dallasopendata.com (Building Permits, type "Residential Roofing Permit") | ZIP from permit record |
| Fort Worth, TX | City of Fort Worth Development Permits (ArcGIS, mapit.fortworthtexas.gov) | ZIP from permit record; uses file date; queried at most once per 60 s and cached 12 h; owner fields never requested |
| Miami-Dade County, FL | Miami-Dade County building permits (ArcGIS, BLDG roof work) | ZIP from the official U.S. Census Geocoder (batched, cached; only a hashed address key and ZIP are kept) |

Other ZIPs get storm rows with `permitCoverage: false`. Not covered today: Denver (its open permit layers exclude roofing permits), Houston (most residential re-roofs don't need a permit there), Oklahoma, Kansas and Nebraska (no official open permit API found). Permit data is cached for 12 hours per account, so repeat runs are fast.

### What to expect

A daily run for one state usually returns 0-200 ZIP rows depending on the weather; quiet days return nothing and cost only the start fee. Requests are throttled per host (≥1.5 s apart) with an identifying User-Agent. Live NWS warnings cover roughly the last 7 days; NOAA Storm Events are verified but published 2-4 months after the storm.

### Pricing

Pay per event:

- **Actor start:** $0.00005
- **Storm ZIP row:** $0.005 ($5 per 1,000)
- **Permit-enriched ZIP row** (ZIP in a covered permit city): $0.02 instead of the storm ZIP row price

A typical one-state daily alert is about $0.10-$1 per day. Use `maxRows` and Apify's max-charge setting to cap spend.

### Use with AI agents (MCP)

This Actor works as a tool for AI agents through the [Apify MCP server](https://mcp.apify.com). Add `clearfeedlabs/storm-roofing-feed` to your MCP client (Claude, Cursor, ChatGPT and others) and ask things like "Which Texas ZIP codes had 1.5-inch hail this week?" or "Where in Minneapolis are roof permits surging after last week's storm?" The structured fields (severity tier, hail size, FEMA number, surge ratio) are easy for an agent to filter, rank and explain.

### Alerts and integrations

- **Webhook:** In the Actor's Integrations tab add a webhook on `ACTOR.RUN.SUCCEEDED` and fetch `.../datasets/{defaultDatasetId}/items?view=overview` from your endpoint.
- **Zapier:** Trigger "Finished Actor Run" (Apify app) → "Get Dataset Items" → filter `severityTier` is `severe` or `extreme` → post to your team's Slack channel or add a CRM territory task.
- **Make:** Apify "Watch Actor Runs" → "Get Dataset Items" → Iterator → Google Sheets "Add a Row" or Email to your own sales team.
- **Google Sheets:** Use Apify's Google Sheets integration (or `=IMPORTDATA("https://api.apify.com/v2/datasets/<id>/items?format=csv&view=overview&token=<your token>")` in a private sheet) for a daily list of hit ZIPs.
- **Schedule:** Create a Task per territory with its own `stateKey`, schedule it hourly or daily, and you'll only receive new or changed ZIP-events.

### Also from Clearfeed Labs

- [Local Business Leads](https://apify.com/clearfeedlabs/local-business-leads) — find roofing and restoration businesses by city (B2B).
- [SEC Form D Funding Feed](https://apify.com/clearfeedlabs/form-d-funding-feed) and [SEC Form 4 Insider Trades](https://apify.com/clearfeedlabs/form4-insider-trades).

### Compliance and data use

- Data comes from public U.S. government sources (NOAA National Weather Service, NOAA NCEI Storm Events, OpenFEMA) and city open-data portals, each used under its published terms, with throttled requests and an identifying User-Agent. No logins, keys, proxies or anti-bot evasion.
- **This product uses the FEMA OpenFEMA API but is 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 FEMA's website. Do not use this data to identify individuals or to make decisions about anyone's eligibility for rights, benefits or services.
- Storm reports and warnings are preliminary. This is not a damage assessment, insurance determination or official warning. For life-safety information use weather.gov.
- **No homeowner names or phone numbers.** Permit data is aggregated to street name + count.
- **Your outreach is your responsibility.** If you contact consumers you must comply with the TCPA (no autodialed or prerecorded calls/texts to mobiles without prior express written consent), the National Do-Not-Call Registry and state DNC lists, CAN-SPAM for email, and state and local rules on post-disaster solicitation: contractor licensing/registration, door-to-door permits and quiet hours, 3-day (or longer) cancellation rights for storm contracts, bans on offering to pay or waive insurance deductibles, public-adjusting restrictions, and price-gouging laws during declared emergencies (for example in TX, FL, LA, CO, OK and MN). Check your state and city rules and hold all required licenses before marketing.
- Every row carries a `disclaimer` field with this notice. Data is provided as is, without warranty.

### FAQ

**Is this the same as a hail swath map?** No. It uses official warnings and point reports, not radar-estimated hail swaths. It's best as a fast, cheap trigger list of ZIPs to check.

**Why do some ZIPs have no permit data?** Only seven cities/counties publish roof permits in a usable open format today. More cities will be added as their portals allow.

**Why is NOAA Storm Events months behind?** NOAA verifies reports before publishing the bulk files. Use it for history and territory planning; use live NWS warnings for alerts.

***

Built by **Clearfeed Labs**: clean, compliant data feeds. Found an issue or want a city added? Open an issue on the Actor's Issues tab with a small example input. If the Actor helped your workflow, an honest review helps other users decide.

***

More Clearfeed Labs tools: [clearfeedlabs.com](https://clearfeedlabs.com/actors/storm-roofing-feed/)

# Actor input Schema

## `states` (type: `array`):

2-letter U.S. state codes to watch, e.g. TX, CO, FL.

## `lookbackDays` (type: `integer`):

How many days of National Weather Service warnings to include (api.weather.gov keeps about a week).

## `eventTypes` (type: `array`):

Which storm types to include.

## `minHailInches` (type: `string`):

Hail warnings and reports smaller than this are ignored.

## `minWindMph` (type: `integer`):

58 mph is the NWS severe threshold.

## `bufferMiles` (type: `integer`):

ZIP codes whose center is within this distance of a storm report are included.

## `includeNwsAlerts` (type: `boolean`):

Severe Thunderstorm, Tornado, Hurricane and Extreme Wind warnings from the official api.weather.gov API.

## `includeStormEventsHistory` (type: `boolean`):

Verified storm reports from NOAA NCEI bulk files. Lags 2-4 months; good for territory planning and backfill.

## `historyDays` (type: `integer`):

Used when NOAA Storm Events history is on.

## `includeFema` (type: `boolean`):

Tag ZIPs in counties with a matching OpenFEMA major-disaster or emergency declaration.

## `includeFemaCountyZips` (type: `boolean`):

Adds one row per ZIP in each county named in a matching OpenFEMA declaration (last 120 days), even when no warning or storm report matched. Can produce many rows; use Max rows to cap spend.

## `includePermits` (type: `boolean`):

Join roof permits from official city open-data portals and flag surges vs. a 52-week baseline. Rows in covered ZIPs are billed as permit-enriched.

## `permitCities` (type: `array`):

Only cities in your selected states are queried.

## `permitWindowDays` (type: `integer`):

Roof permits counted from the storm date.

## `baselineWeeks` (type: `integer`):

Weeks before the storm used for the normal weekly roof-permit rate.

## `surgeRatio` (type: `string`):

Flag a surge when the weekly permit rate is at least this multiple of baseline.

## `minSurgePermits` (type: `integer`):

A surge also needs at least this many roof permits in the window.

## `maxGeocodePerRun` (type: `integer`):

Miami-Dade permits have no ZIP, so addresses are matched to ZIPs with the official U.S. Census Geocoder (batched, cached across runs; only a hashed key and ZIP are stored).

## `includePermitSurgeZips` (type: `boolean`):

Adds rows for covered ZIPs whose roof permits surged in the last window even when no storm matched this run.

## `onlyNewSinceLastRun` (type: `boolean`):

Scheduled runs output (and bill) only ZIP-event rows that are new or changed since the last run with the same state key.

## `stateKey` (type: `string`):

Use a different key per schedule/task to keep their 'since last run' memory separate.

## `maxRows` (type: `integer`):

Hard cap on billed rows per run.

## Actor input object example

```json
{
  "states": [
    "TX"
  ],
  "lookbackDays": 3,
  "eventTypes": [
    "hail",
    "wind",
    "tornado",
    "hurricane"
  ],
  "minHailInches": "1",
  "minWindMph": 58,
  "bufferMiles": 3,
  "includeNwsAlerts": true,
  "includeStormEventsHistory": false,
  "historyDays": 120,
  "includeFema": true,
  "includeFemaCountyZips": false,
  "includePermits": true,
  "permitCities": [
    "austin",
    "minneapolis",
    "new-orleans",
    "baton-rouge",
    "dallas",
    "fort-worth",
    "miami-dade"
  ],
  "permitWindowDays": 14,
  "baselineWeeks": 52,
  "surgeRatio": "2",
  "minSurgePermits": 5,
  "maxGeocodePerRun": 15000,
  "includePermitSurgeZips": false,
  "onlyNewSinceLastRun": true,
  "stateKey": "default",
  "maxRows": 500
}
```

# Actor output Schema

## `zips` (type: `string`):

No description

## `permits` (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 = {
    "states": [
        "TX"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("clearfeedlabs/storm-roofing-feed").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 = { "states": ["TX"] }

# Run the Actor and wait for it to finish
run = client.actor("clearfeedlabs/storm-roofing-feed").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 '{
  "states": [
    "TX"
  ]
}' |
apify call clearfeedlabs/storm-roofing-feed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,clearfeedlabs/storm-roofing-feed"
        }
    }
}
```

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/irxaF4xuJOCepocya/builds/4hrMsPONA1dfHUc2M/openapi.json
