This dated snapshot contains 2,725,989 redacted NFIP claims records with loss dates from January 1, 1978 through September 7, 2026. FEMA marks the source as of September 8. All 84 source fields are preserved, alongside three diagnostic or derived columns. The latest year is partial. Future updates are not included.
FEMA describes these as claims transactions. Row counts do not measure unique properties, households, flood events or all paid claims. The unique id identifies a record in this release. There is no policy exposure denominator, so geographic counts and amounts cannot establish flood probability or comparative risk.
Load the dated snapshot
import duckdb
con = duckdb.connect()
con.execute("CREATE VIEW claims AS SELECT * FROM read_parquet('fema_flood_insurance_claims.parquet')")
rows = con.execute("SELECT count(*) FROM claims").fetchone()[0]
assert rows == 2725989
print(rows)
print(con.execute("SELECT min(dateOfLoss), max(dateOfLoss) FROM claims").fetchone())Keep incomplete payments visible
total_paid_nominal adds building, contents and increased-cost-of-compliance payments only when all three are supplied. There are 567,072 incomplete totals, 2,117,326 positive totals, 41,505 zero totals and 86 negative totals. Negative amounts remain as reported. Net-payment and recovery fields are separate. Amounts are nominal dollars and are not adjusted for inflation.
statuses = con.execute("SELECT payment_status, count(*) AS records FROM claims GROUP BY 1 ORDER BY 1").fetchall()
print(statuses)
annual = con.execute("""
SELECT yearOfLoss, count(*) AS records,
count(total_paid_nominal) AS complete_payment_records,
count(*) FILTER (WHERE payment_status='missing_component') AS incomplete_payment_records,
sum(total_paid_nominal) AS sum_of_complete_totals_only
FROM claims GROUP BY 1 ORDER BY 1
""").fetchall()
assert len(annual) == 49
print(annual)The sum above excludes incomplete records. It is not the total payment for the entire NFIP program. Do not use fillna(0) or COALESCE on missing payment components to make a complete-claims estimate.
Profile supplied geography
62,433 county codes are missing. There are 55,827 empty ZIPs and 303 irregular nonempty ZIP values. One state is empty and 16,441 records contain UN. Every city value is Currently Unavailable. The query below retains the empty and UN state groups so they remain visible.
states = con.execute("""
SELECT state, count(*) AS records,
count(*) FILTER (WHERE countyCode IS NULL) AS missing_county_records,
count(*) FILTER (WHERE reportedZipCode='') AS empty_zip_records
FROM claims GROUP BY 1 ORDER BY records DESC
""").fetchall()
print(states)41,493 coordinate pairs are missing. The remaining pairs pass numeric bounds, but FEMA rounds them to one decimal place to protect privacy. They may fall in another county or state. Use supplied geographic fields for aggregation. Do not use these points as property locations or to reconstruct addresses.
Keep flood-zone concepts separate
ratedFloodZone describes the zone used to rate a property, while floodZoneCurrent describes its current zone in the agency record. The source is missing 139,030 rated zones and 1,949,806 current zones. Zone X alone does not distinguish shaded from unshaded areas. This package provides the original codes and dictionary without a simplified risk category or a ZIP risk score.
The official CSV and Parquet files were compared by id across all 84 fields. Every original Parquet value matches the delivered output; independent Python CSV parsing and exact Decimal accumulation reconcile 49 annual financial totals. Agency accuracy and historical completeness are not independently certified.
The free 1,000-row sample spans all 49 loss years using evenly spaced IDs within each year; it is not statistically representative. The full CSV/Parquet snapshot, source dictionary, hashes and QA evidence cost $99 once. FEMA publishes the underlying source for free. This product uses OpenFEMA data and is not endorsed by FEMA.