# Hail Hit Addresses - Yesterday's Hail Swaths to Roofing Leads (`that_red_bird/hail-storm-address-leads`) Actor

Roofers: turn NOAA SPC hail reports into street addresses inside the hail zone, with hail size and time. Public OpenStreetMap addresses only (not verified homeowners), deduped across storms. Comply with local solicitation laws.

- **URL**: https://apify.com/that_red_bird/hail-storm-address-leads.md
- **Developed by:** [mohamed alaya](https://apify.com/that_red_bird) (community)
- **Categories:** Lead generation, Business, Other
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 addresses

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 Hit Addresses - Hail Reports to Roofing Lead Addresses

Turns **NOAA Storm Prediction Center hail reports** into a list of **public street addresses near each report**, with hail size and time. For roofing, restoration and storm-marketing teams who want a cheap first pass at where to canvass after a hail day.

**Public addresses only. These are address candidates from OpenStreetMap, not verified homeowners, and not every house is in the data. Comply with local solicitation laws, do-not-knock lists and TCPA / CAN-SPAM rules before any outreach.**

### Quick start - three copy-paste inputs

Demo (empty input works; it takes the latest day with hail reports):

```json
{}
```

A specific storm day, big hail only, Colorado and Texas:

```json
{
  "date": "2026-08-15",
  "minHailSize": "1.25",
  "states": ["CO", "TX"],
  "radiusMeters": 1000,
  "maxReports": 10,
  "maxAddressesPerReport": 25
}
```

Include businesses (for commercial roofing) so the output can feed the Google Maps email enricher:

```json
{ "date": "2026-08-15", "includeBusinesses": true, "maxAddresses": 100, "stateStoreName": "my-roofing-company" }
```

### How it works

1. Reads the SPC daily hail report file (storm day = 12:00 UTC to 12:00 UTC), largest hail first.
2. For each report it asks OpenStreetMap (Overpass) for address points within your radius. A report is a **point**, not a swath outline, so the radius is an estimate of the affected area.
3. If OpenStreetMap has no addresses there (common in rural areas) it can return the nearest **street name** from Nominatim instead (not charged, no house number).
4. Addresses already delivered in earlier runs (same memory store, 90 days) are skipped, so overlapping storms do not give you the same address twice.

### Input guide

| Field | Meaning |
|---|---|
| `date` | `YYYY-MM-DD` storm day. Empty = latest day in the last 30 days with reports of the minimum size. |
| `minHailSize` | Minimum hail diameter in inches. |
| `states` | Optional two-letter filter. |
| `radiusMeters` | Search radius around each report (default 800 m). |
| `maxReports`, `maxAddressesPerReport`, `maxAddresses` | Caps. `maxAddresses` is also your spending cap. |
| `includeBusinesses` | Also return shops/offices with their public name and website. |
| `includeStreetFallback` | Return the nearest street when there are no address points. |
| `onlyNew`, `stateStoreName` | Dedupe across runs and storms. |

### Output

| Field | Meaning |
|---|---|
| `type` | `address`, `street`, `error`, `run-summary` |
| `address`, `houseNumber`, `street`, `city`, `state`, `postcode` | The public address |
| `buildingType` | OpenStreetMap building tag (house, residential, apartments, industrial ...) when present |
| `title`, `website` | Only for businesses (`includeBusinesses`), from OpenStreetMap |
| `hailSizeInches`, `reportDate`, `reportTimeUtc`, `reportLocation` | The SPC hail report behind it |
| `distanceFromReportMeters` | Distance from the report point |
| `source` | Attribution: OpenStreetMap contributors (ODbL) and NOAA SPC. Keep it if you republish. |

Sample row:

```json
{"type":"address","address":"8329 Feather Grass Court, Parker CO 80134","buildingType":"house","hailSizeInches":1.75,"reportDate":"2026-08-15","reportLocation":"2 SSW Foxfield","distanceFromReportMeters":499}
```

### Use it with

- **Google Maps scraper -> this Actor?** The other way round: run this with `includeBusinesses: true`, then pass the dataset (it carries `title` and `website`) to the **Google Maps Emails** Actor (`google-maps-email-enricher`) to get public business emails.
- Export CSV into your canvassing or CRM tool.

### FAQ

**Are these homeowners?** No. They are addresses that exist in OpenStreetMap near a hail report. There is no owner, resident or phone data, and none is collected.

**Why so few addresses in some places?** OpenStreetMap address coverage varies; most hail reports are rural. Use a larger radius or accept the street-only rows.

**Is the data licence-safe?** Addresses come from OpenStreetMap (ODbL, attribution required). Lookups follow the Overpass and Nominatim usage policies: identified User-Agent, about one request per second, no bulk reverse geocoding. Hail reports are public NOAA data.

### Honest limits

- Hail reports are points with an estimated size, not a verified damage swath. Treat the list as where to look, not where damage happened.
- Address candidates, not verified homeowners; a house in the list may be a rental, vacant or already repaired.
- Public address lookups are rate-limited, so a run with 10 reports takes a few minutes. The OpenStreetMap servers sometimes time out; affected reports give an `error` row and are retried on the next run.

### Price

**$0.002 per address delivered** (street-only fallback rows are free). 200 addresses cost $0.40.

# Actor input Schema

## `date` (type: `string`):

The SPC convective day (12:00 UTC to 12:00 UTC) to read, for example 2026-09-20. Leave empty to use the most recent day in the last 30 days that has hail reports of the minimum size.

## `minHailSize` (type: `string`):

Only use reports with at least this hail diameter. 1.00 is roughly roof-damage territory for many shingles; 1.75 is golf-ball size.

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

Optional two-letter US state codes (for example TX, CO). Leave empty for all states.

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

Addresses are collected within this distance of each hail report point. A report is a point, not a swath outline, so this is an estimate of the affected area. 800 m is about half a mile.

## `maxReports` (type: `integer`):

Reports are used largest hail first. Each one needs one OpenStreetMap query, which is rate limited to about one per second, so this also bounds run time.

## `maxAddressesPerReport` (type: `integer`):

Nearest addresses to the report point are kept first.

## `maxAddresses` (type: `integer`):

Hard stop for the whole run. You are charged per address delivered, so this is also your spending cap.

## `includeBusinesses` (type: `boolean`):

Also return addresses tagged as shops, offices, amenities and similar, with their public name and website when OpenStreetMap has them. This output can be fed to the Google Maps email enricher Actor. Off = residential-style addresses only.

## `includeStreetFallback` (type: `boolean`):

When OpenStreetMap has no address points near a report (common in rural areas), return the nearest street name from Nominatim instead. These rows have no house number and are not charged.

## `onlyNew` (type: `boolean`):

Skip addresses already delivered by earlier runs that used the same memory store name (dedupe across storms and days). The memory is kept for 90 days.

## `stateStoreName` (type: `string`):

Named key-value store that remembers delivered addresses. Use the same name on every run and a different name per client or territory. Empty = no dedupe across runs.

## `timeBudgetSeconds` (type: `integer`):

Stop looking up new hail reports after this many seconds so the run always finishes. Remaining reports are picked up on the next run. The public OpenStreetMap servers are sometimes slow.

## Actor input object example

```json
{
  "date": "",
  "minHailSize": "1.00",
  "states": [],
  "radiusMeters": 800,
  "maxReports": 10,
  "maxAddressesPerReport": 20,
  "maxAddresses": 200,
  "includeBusinesses": false,
  "includeStreetFallback": true,
  "onlyNew": true,
  "stateStoreName": "hail-address-leads-seen",
  "timeBudgetSeconds": 120
}
```

# Actor output Schema

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

No description

## `downloadCsv` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `count` (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 = {
    "timeBudgetSeconds": 120
};

// Run the Actor and wait for it to finish
const run = await client.actor("that_red_bird/hail-storm-address-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 = { "timeBudgetSeconds": 120 }

# Run the Actor and wait for it to finish
run = client.actor("that_red_bird/hail-storm-address-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 '{
  "timeBudgetSeconds": 120
}' |
apify call that_red_bird/hail-storm-address-leads --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,that_red_bird/hail-storm-address-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/jn5P5D3UdEmjedZrV/builds/fLTDjBMCPiNhFFXaU/openapi.json
