If you've ever tried to build an app that accounts for natural disaster risk — whether it's a real estate platform, a relocation tool, or an insurance estimator — you know how hard it is to find clean, standardized environmental risk data. Most hazard data sources are buried in government PDFs, locked behind expensive subscriptions, or require you to stitch together a dozen different datasets. That's why I was excited to discover a free environmental risk API that serves up standardized hazard data for every US zip code, city, county, and state through a dead-simple REST endpoint.
In this tutorial, I'll walk you through how to query the API, parse the results, and build something actually useful with it.
What Data Is Available?
The API returns risk scores on a 0–100 scale across 12 environmental hazard categories:
| Hazard Category | What It Measures |
|---|---|
| Earthquake | Seismic activity risk |
| Flood | Flood zone exposure |
| Wildfire | Fire risk based on vegetation, climate, topology |
| Tornado | Tornado frequency and severity |
| Hurricane | Hurricane/storm surge exposure |
| Air Quality | Long-term air pollution levels |
| Heat | Extreme heat event frequency |
| Winter Weather | Blizzard/ice storm risk |
| Landslide | Terrain-based landslide susceptibility |
| Volcanic Activity | Proximity to active volcanic zones |
| Drought | Long-term drought probability |
Scores are normalized to a 0–100 range, where higher values mean greater risk. This makes it trivially easy to compare locations side-by-side or build color-coded visualizations.
Getting Started: Your First API Call
The base endpoint is:
https://environmental-hazards-api-425658670453.europe-west1.run.app/api/v3/hazards
You query it by passing location parameters. No API key required for basic usage. Let's start with the simplest case — looking up risk scores by zip code.
Example: Get Risk Scores for a Zip Code (cURL)
curl -s "https://environmental-hazards-api-425658670453.europe-west1.run.app/api/v3/hazards?zip=33101" | python3 -m json.tool
This returns a JSON object with risk scores for Miami's 33101 zip code. You'll get something like:
{
"location": {
"zip": "33101",
"city": "Miami",
"state": "FL",
"county": "Miami-Dade County"
},
"risk_scores": {
"earthquake": 12,
"flood": 78,
"wildfire": 15,
"tornado": 35,
"hurricane": 92,
"air_quality": 42,
"heat": 88,
"winter_weather": 3,
"landslide": 8,
"volcanic_activity": 0,
"drought": 45
}
}
Right away you can see — Miami has a hurricane risk of 92 and heat risk of 88, but essentially zero volcanic activity. Makes sense.
Querying by City and State
If you don't have a zip code handy, you can query by city and state code:
curl -s "https://environmental-hazards-api-425658670453.europe-west1.run.app/api/v3/hazards?city=los_angeles&state_code=ca"
The API also supports county-level and state-level lookups. For a full state summary:
curl -s "https://environmental-hazards-api-425658670453.europe-west1.run.app/api/v3/hazards?state_code=CA&level=state"
This is useful when you want aggregate risk profiles at a higher level — say, comparing California to Florida.
Python Example: Batch Risk Comparison
Here's where things get practical. Let's say you're helping a user compare environmental risk across multiple zip codes — maybe they're deciding where to buy a house or relocate.
import requests
import pandas as pd
BASE_URL = "https://environmental-hazards-api-425658670453.europe-west1.run.app/api/v3/hazards"
def get_risk_scores(zip_code: str) -> dict:
"""Fetch environmental risk scores for a given zip code."""
response = requests.get(BASE_URL, params={"zip": zip_code})
response.raise_for_status()
data = response.json()
return {
"zip": zip_code,
"city": data["location"]["city"],
"state": data["location"]["state"],
**data["risk_scores"]
}
# Zip codes to compare (from different regions of the US)
zip_codes = ["33101", "90210", "10001", "77001", "98101"]
# Fetch data for all locations
results = [get_risk_scores(zc) for zc in zip_codes]
# Build a DataFrame for easy comparison
df = pd.DataFrame(results)
# Show only the risk columns, sorted by hurricane risk
risk_cols = ["earthquake", "flood", "wildfire", "tornado", "hurricane",
"air_quality", "heat", "winter_weather", "landslide",
"volcanic_activity", "drought"]
print(df[["zip", "city", "state"] + risk_cols].sort_values("hurricane", ascending=False).to_string(index=False))
This script pulls risk data for five zip codes across the country and builds a comparison table. You could easily extend this to loop through hundreds of zip codes, pipe the results into a CSV, or feed them into a visualization library.
Finding the Highest Risk
Want to quickly identify which hazard is the biggest threat for a given location?
def get_top_risks(zip_code: str, count: int = 3) -> list[dict]:
"""Return the top N highest risk categories for a zip code."""
response = requests.get(BASE_URL, params={"zip": zip_code})
response.raise_for_status()
scores = response.json()["risk_scores"]
sorted_risks = sorted(scores.items(), key=lambda x: x[1], reverse=True)
return [{"hazard": hazard, "score": score} for hazard, score in sorted_risks[:count]]
top_risks = get_top_risks("33101")
for risk in top_risks:
print(f" {risk['hazard']}: {risk['score']}/100")
JavaScript Example: Frontend Risk Widget
If you're building a web app, here's how to fetch and display risk data using the Fetch API. This pattern works great in React, Vue, Svelte, or vanilla JS.
const API_BASE = "https://environmental-hazards-api-425658670453.europe-west1.run.app/api/v3/hazards";
/**
* Fetch environmental risk scores for a zip code
* and render a color-coded risk bar for each category.
*/
async function renderRiskWidget(zipCode, containerId) {
const container = document.getElementById(containerId);
container.innerHTML = "<p>Loading risk data...</p>";
try {
const response = await fetch(`${API_BASE}?zip=${zipCode}`);
if (!response.ok) throw new Error(`API returned ${response.status}`);
const data = await response.json();
const { location, risk_scores } = data;
// Build the widget
let html = `<h3>Environmental Risk: ${location.city}, ${location.state} (${location.zip})</h3>`;
for (const [hazard, score] of Object.entries(risk_scores)) {
const color = score >= 70 ? "#e74c3c" : score >= 40 ? "#f39c12" : "#27ae60";
const label = hazard.replace(/_/g, " ").replace(/\b\w/g, c => c.toUpperCase());
html += `
<div style="margin-bottom: 8px;">
<div style="display: flex; justify-content: space-between; margin-bottom: 2px;">
<span>${label}</span>
<strong>${score}/100</strong>
</div>
<div style="background: #eee; border-radius: 4px; height: 10px;">
<div style="background: ${color}; width: ${score}%; height: 10px; border-radius: 4px;"></div>
</div>
</div>`;
}
container.innerHTML = html;
} catch (err) {
container.innerHTML = `<p style="color: red;">Error: ${err.message}</p>`;
}
}
// Usage: renderRiskWidget("90210", "risk-widget");
Drop this into any HTML page with a <div id="risk-widget"></div> and you've got an instant visual risk profile. The color coding (red/orange/green based on severity) makes it immediately scannable.
Comparing Two Locations Side-by-Side
One of the more useful features is the comparison endpoint. Let's say someone is deciding between Los Angeles and New York:
curl -s "https://environmental-hazards-api-425658670453.europe-west1.run.app/api/v3/hazards?zip=90210&compare_zip=10001"
This returns risk data for both locations in a single response, making it easy to build comparison tables or dual-bar charts. In a real app, you'd parse this and render something like:
# Python: Parse comparison data and find the biggest differences
import requests
response = requests.get(BASE_URL, params={"zip": "90210", "compare_zip": "10001"})
data = response.json()
loc_a = data["locations"][0] # Beverly Hills
loc_b = data["locations"][1] # New York
print(f"Comparing {loc_a['location']['city']} vs {loc_b['location']['city']}\n")
for hazard in loc_a["risk_scores"]:
score_a = loc_a["risk_scores"][hazard]
score_b = loc_b["risk_scores"][hazard]
diff = score_a - score_b
direction = "↑" if diff > 0 else "↓"
print(f" {hazard:20s}: {score_a:3d} vs {score_b:3d} ({direction} {abs(diff):2d})")
The comparison output immediately highlights where the real differences are — Los Angeles has higher earthquake and wildfire risk, while New York has higher winter weather risk. This kind of side-by-side view is incredibly useful for relocation tools.
Practical Project: Environmental Risk Email Alerts
Here's a more complete project idea — a script that checks risk scores for a list of zip codes and sends an email alert when any location crosses a danger threshold. This could be useful for property managers, insurance agents, or just cautious homeowners.
import requests
import smtplib
from email.mime.text import MIMEText
from typing import List, Dict
API_BASE = "https://environmental-hazards-api-425658670453.europe-west1.run.app/api/v3/hazards"
THRESHOLD = 75 # Alert when any risk score exceeds this value
def check_risks(zip_codes: List[str]) -> List[Dict]:
"""Check all zip codes and return any with high-risk scores."""
alerts = []
for zc in zip_codes:
try:
resp = requests.get(API_BASE, params={"zip": zc})
resp.raise_for_status()
data = resp.json()
for hazard, score in data["risk_scores"].items():
if score >= THRESHOLD:
alerts.append({
"zip": zc,
"city": data["location"]["city"],
"state": data["location"]["state"],
"hazard": hazard,
"score": score,
})
except requests.RequestException as e:
print(f"Error fetching {zc}: {e}")
return alerts
def send_alert_email(alerts: List[Dict], recipient: str) -> None:
"""Send a summary email of all high-risk alerts."""
if not alerts:
print("No alerts to send.")
return
body_lines = ["⚠️ Environmental Risk Alert Report ⚠️\n"]
for alert in alerts:
body_lines.append(
f"- {alert['city']}, {alert['state']} ({alert['zip']}): "
f"{alert['hazard']} risk = {alert['score']}/100"
)
msg = MIMEText("\n".join(body_lines))
msg["Subject"] = f"Environmental Risk Alert: {len(alerts)} high-risk items"
msg["From"] = "alerts@example.com"
msg["To"] = recipient
# Configure your SMTP server here
# with smtplib.SMTP("smtp.example.com", 587) as server:
# server.starttls()
# server.login("user", "password")
# server.send_message(msg)
print(f"Would send {len(alerts)} alerts to {recipient}")
# Run the check
monitored_zips = ["33101", "90210", "77001", "94102", "02101"]
alerts = check_risks(monitored_zips)
send_alert_email(alerts, "user@example.com")
Wire this up to a cron job or a serverless function (AWS Lambda, Cloudflare Workers, etc.) and you've got automated environmental monitoring. You could extend it to track changes over time, push to Slack instead of email, or generate weekly summary reports.
A Few Things to Keep in Mind
Rate limiting: The API is free, which means it has reasonable rate limits. If you're batching thousands of requests, add a small delay between calls (time.sleep(0.5) in Python). For production use, check the RapidAPI listing for higher rate limits and guaranteed uptime.
Caching: Risk scores don't change every day. Cache responses locally (Redis, SQLite, even a JSON file) if you're building something that queries the same locations repeatedly. This speeds up your app and reduces API load.
Score interpretation: A score of 50 doesn't mean "moderate danger" in absolute terms — it means the location is at the 50th percentile relative to other US locations for that hazard type. Always present scores as comparative rather than absolute.
What Could You Build?
Here are a few ideas beyond what we covered:
- Real estate listing enhancer: Automatically display risk badges on property listings
- Relocation decision tool: Let users input their priorities (e.g., "I care most about flood and wildfire risk") and rank cities accordingly
- Insurance premium estimator: Factor environmental risk into rough premium calculations
- Interactive US risk map: Fetch scores for thousands of zip codes and render a choropleth map with D3.js or Mapbox
- School safety dashboard: Show environmental risk profiles for school districts
The data comes from environmental hazard data API, which aggregates and standardizes hazard data from multiple federal and state sources into a single, developer-friendly endpoint. The platform covers every US zip code, city, county, and state — and it's free to use.
Wrapping Up
Environmental risk data has traditionally been one of those things that's technically public but practically inaccessible. Having it available through a clean REST API with consistent scoring makes a huge difference.
Here's what we covered:
- Querying by zip code, city, or state using simple GET requests
- Comparing two locations with the built-in comparison endpoint
- Building a visual risk widget in vanilla JavaScript
- Batch processing in Python with pandas for analysis
- Automated alerting with a threshold-based email script
All the code in this article is ready to copy, paste, and run. The API returns consistent JSON with no authentication needed for basic usage, so you can literally start building in under five minutes.
If you build something with this data, I'd love to hear about it — drop a comment below.
Tags: python api tutorial datascience
Top comments (0)