# US Storm Damage Roofing Leads - NOAA Hail + Permits (`wellbuilt_zythem/us-storm-roofing-leads`) Actor

Hail and damaging-wind reports from NOAA around 12 US cities, and the roofing permits pulled in the weeks after: which neighbourhoods are replacing roofs right now, how many more than before the storm, and which contractors are doing the work. Official NOAA storm reports and city permit registers.

- **URL**: https://apify.com/wellbuilt\_zythem/us-storm-roofing-leads.md
- **Developed by:** [Carlos Escanez](https://apify.com/wellbuilt_zythem) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 roofing permit after the storms

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

## US Storm Damage Roofing Leads: NOAA hail and wind reports, then the roofing permits that follow

**Where roofs are being replaced right now, how many more than before the storm, and who is doing the work. Official NOAA storm reports joined to official city permit registers, for 12 US cities.**

A hail storm is the best roofing lead there is, and the companies that sell it (HailTrace, Hail Recon) charge $300 to $500 a month per city for a map. This Actor gives you the two public records behind that map, joined:

1. **Every severe hail and wind report** the National Weather Service logged around the city, with size, speed, location, county and distance to the city centre, from NOAA's Storm Prediction Center.
2. **Every roofing permit** the city issued since the first storm, with the storm that explains it, how many days after, how far from the report, and how many roofs that contractor has pulled permits for since the storm.

And one number per city that says whether the storm moved anything: **roofing permits after the storm against the same number of days before it.**

### What a run looks like

```
Chicago, IL: 52 reports (0 hail, 52 wind), first 2026-08-09, last 2026-08-12
Chicago, IL: 584 roofing permits since 2026-08-09 by 301 contractors, 471 in the 45 days before (+24%)
Austin, TX: 3 reports (0 hail, 3 wind), first 2026-08-27
Austin, TX: 111 roofing permits since 2026-08-27 by 78 contractors, 91 in the 27 days before (+22%)
```

Measured on 23 September 2026 over the previous 45 days. New Orleans in the same window: 11 reports including 1-inch hail, 201 roofing permits after against 214 before (-6%). Mesa: 20 wind reports, 24 permits after against 43 before (-44%). The number is reported either way; a storm that did not move the permits is worth knowing too.

### Who runs this on a loop

- **Roofing companies and storm chasers**: the day after a storm, the reports say which side of the city got hit; two weeks later the permits say which streets are already replacing roofs, and which competitors are pulling ten permits a week there.
- **Building material suppliers**: the contractors with the most roofing permits since the storm are the ones ordering shingles this month, by name.
- **Public adjusters and insurance**: hail size and wind speed on the record, with the NWS office that logged it, next to the permits that followed.
- **Anyone selling to roofers**: "you pulled 7 permits since the 11 August storm" opens a conversation that a cold list does not.

### What every row carries

Two kinds of rows, told apart by `type`.

**`storm`**, one per NOAA report within the radius: `date`, `timeUtc`, `kind` (`hail` or `wind`), `hailInches`, `windMph` (absent when the damage was reported without a measured speed, `windMeasured: false`), `location`, `county`, `reportState`, `latitude`, `longitude`, `distanceToCityKm`, `comments` (the spotter's note, e.g. "Golf ball size hail, measured"), `nwsOffice`, `sourceUrl` (that day's NOAA report page).

**`permit`**, one per roofing permit issued since the first storm, everything the permit register publishes (`permitNumber`, `issuedDate`, `address`, `zip`, `latitude`, `longitude`, `valuation`, `description`, `contractorName`, `contractorPhone` where the city publishes it, `contractorLicense`, `trade`, `leadScore`), plus the storm join: `stormDate`, `daysAfterStorm`, `stormKind`, `stormHailInches`, `stormWindMph`, `stormLocation`, `stormDistanceKm` (from the permit address to the nearest earlier report, when the permit has coordinates), `contractorPermitsAfterStorm`, `cityPermitsAfterStorm`, `cityPermitsBeforeStorm`, `cityStormsInWindow`, `cityStrongestHailInches`.

The run summary (`RUN_SUMMARY` in the key-value store) has the per-city numbers: reports, strongest hail and wind, first and last storm date, permits after and before, `permitLiftPercent`, contractors active after the storm.

### Input

- `cities`: any of Chicago, Cincinnati, Austin, Mesa, New Orleans, Baton Rouge, Orlando, New York, Seattle, Everett, Somerville, Marin County. Empty means all.
- `lastNDays` (30): how far back to look for storms. Permits are read from the first storm to today, plus the same number of days before it for the baseline.
- `radiusKm` (40): a NOAA report is a point inside a hail swath 10 to 30 km wide, not its edge, so the radius is measured to the city centre.
- `minHailInches` (1) and `minWindMph` (58): NOAA only logs hail of 1 inch and above and wind of 58 mph and above, so the defaults keep everything; 1.75 (golf ball) is what insurers pay out on. Wind damage reported without a measured speed always counts.
- `withPermits` (true): off gives the storm reports only.
- `trades`: roofing by default; add `solar`, `hvac` or `remodel` to see what else a storm pulls.
- `maxResults`: storms and permits together; the prefilled 100 makes a first run cost cents.

### Coverage, said plainly

- **Storm reports cover the whole country**, so every city gets its reports. Whether a city gets storms is another matter: Seattle, Everett and Marin County rarely see severe hail; Chicago, Cincinnati, Austin, Mesa, New Orleans, Baton Rouge and Orlando do, most summers.
- **Cincinnati's permit register carries no roofing permits** (it publishes electrical, plumbing and mechanical trades only), so Cincinnati delivers storm reports and says so about the permits. Ohio does not license roofers either.
- **The permit is classified as roofing from its type, work class and description**, the same rule as the US Building Permits Actor. A city that files re-roofs under a generic "residential alteration" with no description shows fewer roofing permits than it really issues.
- **The lift is a comparison of two short windows**, not a forecast. A -6% after a small storm is normal; the number is there so you can tell a storm that filled the permit office from one that did not.
- **Reports are where someone saw the hail**, from spotters, the public and NWS offices. A swath that crossed farmland gets fewer reports than one that crossed a suburb.

### Pricing

Two events. A storm report is a `storm` row, cheap; a roofing permit joined to its storm is a `record` row. Filtered-out rows cost nothing, and a city with no storm in the window delivers nothing and costs nothing.

### Data sources

- NOAA Storm Prediction Center, daily storm reports (`spc.noaa.gov/climo/reports`), public domain.
- The 12 cities' official permit registers on Socrata open-data portals, the same sources as the US Building Permits Actor.

# Actor input Schema

## `cities` (type: `array`):

Leave empty for all twelve. Storm reports are matched to the city centre; permits come from that city's official register.

## `lastNDays` (type: `integer`):

How far back to look for NOAA hail and wind reports. Roofing permits are then read from the first storm in the window to today, plus the same number of days before it as the baseline.

## `radiusKm` (type: `integer`):

A NOAA report is a point where someone saw the hail, inside a swath 10 to 30 km wide. 40 km catches the metro area.

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

1 inch is the size that dents shingles; 1.75 (golf ball) is what insurers pay out on. NOAA only publishes reports of 1 inch and above.

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

58 mph is the National Weather Service severe threshold. Reports of wind damage with no measured speed always count.

## `withPermits` (type: `boolean`):

Off gives storm reports only. On adds one row per roofing permit issued since the first storm, with the storm that explains it, days after the storm, distance, and the contractor's permit count after the storm.

## `trades` (type: `array`):

Roofing by default. Add solar, HVAC or remodel to see what else a storm pulls.

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

Storm reports and permits together. 0 = no limit. The prefilled 100 makes a first run cost cents.

## `socrataAppToken` (type: `string`):

Free token from any Socrata portal; gives the permit reads their own rate limit.

## Actor input object example

```json
{
  "cities": [
    "chicago",
    "austin",
    "new_orleans",
    "mesa",
    "cincinnati"
  ],
  "lastNDays": 45,
  "radiusKm": 40,
  "minHailInches": "1",
  "minWindMph": 58,
  "withPermits": true,
  "trades": [],
  "maxResults": 100
}
```

# Actor output Schema

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

No description

## `runSummary` (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 = {
    "cities": [
        "chicago",
        "austin",
        "new_orleans",
        "mesa",
        "cincinnati"
    ],
    "lastNDays": 45,
    "maxResults": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("wellbuilt_zythem/us-storm-roofing-leads").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 = {
    "cities": [
        "chicago",
        "austin",
        "new_orleans",
        "mesa",
        "cincinnati",
    ],
    "lastNDays": 45,
    "maxResults": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("wellbuilt_zythem/us-storm-roofing-leads").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 '{
  "cities": [
    "chicago",
    "austin",
    "new_orleans",
    "mesa",
    "cincinnati"
  ],
  "lastNDays": 45,
  "maxResults": 100
}' |
apify call wellbuilt_zythem/us-storm-roofing-leads --silent --output-dataset

```

## MCP server setup

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

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/FNFfp2vYNiRVU7gMO/builds/x6z6sXKDxIaUpma5b/openapi.json
