DEV Community

Doushabao
Doushabao

Posted on

I Built a 30-Line Earthquake Monitor in Python — Here's How

Two days ago, a magnitude 6.3 earthquake struck 84 miles south of Nikolski, Alaska. I found out about it 40 minutes later scrolling through Twitter. Forty minutes.

That bugged me. There's free, real-time seismic data sitting right there — why wasn't I checking it myself? So I spent an evening building a 30-line Python script that now runs in my terminal every morning. Here's exactly how it works.

The Data Source

The USGS publishes earthquake data as a free GeoJSON feed. No API key, no registration, no rate limit headaches. You get everything from M1.0 microquakes to M8.0+ megathrust events, updated within minutes of occurrence.

The feed gives you:

  • Magnitude and magnitude type (ml, mb, mw)
  • Exact coordinates and depth
  • Timestamp (UTC)
  • Location description (human-readable)
  • Felt reports (how many people reported feeling it)
  • Alert level (PAGER: green/yellow/orange/red)

The Script

Install one dependency:

pip install rich
Enter fullscreen mode Exit fullscreen mode

Then save this as quake_check.py:

import requests
from rich.console import Console
from rich.table import Table
from rich.text import Text
from datetime import datetime

console = Console()

def get_earthquakes(min_mag=4.5, limit=20):
    """Fetch recent earthquakes from the USGS feed."""
    url = "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/significant_week.geojson"
    resp = requests.get(url, timeout=10)
    resp.raise_for_status()
    return resp.json()["features"][:limit]

def mag_color(mag):
    if mag >= 6.0: return "bold red"
    if mag >= 5.0: return "red"
    if mag >= 4.0: return "yellow"
    return "green"

def show_quakes(features):
    table = Table(title="Recent Significant Earthquakes", show_lines=True)
    table.add_column("Mag", justify="center", style="bold")
    table.add_column("Location")
    table.add_column("Depth")
    table.add_column("Time (UTC)")
    table.add_column("Reports")

    for eq in features:
        p = eq["properties"]
        coords = eq["geometry"]["coordinates"]
        t = datetime.utcfromtimestamp(p["time"] / 1000).strftime("%Y-%m-%d %H:%M")
        style = mag_color(p["mag"])
        table.add_row(
            Text(f"{p['mag']:.1f}", style=style),
            p["place"] or "Unknown",
            f"{coords[2]:.0f} km",
            t,
            str(p.get("felt") or "-"),
        )
    console.print(table)

if __name__ == "__main__":
    quakes = get_earthquakes()
    show_quakes(quakes)
    console.print(f"\n[dim]Source: USGS Earthquake Hazards Program[/dim]")
Enter fullscreen mode Exit fullscreen mode

Run it:

python3 quake_check.py
Enter fullscreen mode Exit fullscreen mode

That's it. You'll see something like this in your terminal:

         Recent Significant Earthquakes
┌───────┬──────────────────────────────────┬────────┬──────────────────┬─────────┐
│  Mag  │ Location                         │ Depth  │ Time (UTC)       │ Reports │
├───────┼──────────────────────────────────┼────────┼──────────────────┼─────────┤
│  6.3  │ 84 km SSW of Nikolski, Alaska    │ 35 km  │ 2026-09-03 14:22 │    47   │
│  5.4  │ 21 km WNW of Jiangyou, China     │ 10 km  │ 2026-09-02 08:15 │   112   │
│  5.1  │ 69 km E of Antofagasta, Argentina│ 124 km │ 2026-09-01 22:07 │     -   │
│  5.5  │ 168 km ESE of Kuril'sk, Russia   │ 55 km  │ 2026-08-31 19:44 │     -   │
│  5.0  │ Pagar Alam, Indonesia             │ 22 km  │ 2026-08-31 16:33 │     8   │
└───────┴──────────────────────────────────┴────────┴──────────────────┴─────────┘
Enter fullscreen mode Exit fullscreen mode

Making It More Useful

The script above shows only "significant" events. Here's how to filter by your own criteria:

Filter by magnitude

Change the feed URL to get all M2.5+ earthquakes from the past week:

url = "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_week.geojson"
Enter fullscreen mode Exit fullscreen mode

Different feed options:

Feed What you get
significant_week Only significant events
4.5_week M4.5+ past 7 days
2.5_week M2.5+ past 7 days
all_hour Everything in the last hour

Filter by distance from your city

from math import radians, sin, cos, sqrt, atan2

def haversine(lat1, lon1, lat2, lon2):
    """Distance in km between two coordinates."""
    R = 6371
    dlat = radians(lat2 - lat1)
    dlon = radians(lon2 - lon1)
    a = sin(dlat/2)**2 + cos(radians(lat1)) * cos(radians(lat2)) * sin(dlon/2)**2
    return R * 2 * atan2(sqrt(a), sqrt(1-a))

def near_me(features, my_lat, my_lon, max_km=500):
    """Only earthquakes within max_km of my location."""
    return [
        eq for eq in features
        if haversine(my_lat, my_lon, eq["geometry"]["coordinates"][1],
                     eq["geometry"]["coordinates"][0]) <= max_km
    ]
Enter fullscreen mode Exit fullscreen mode

Call it with your coordinates:

# San Francisco: 37.77, -122.42
# Tokyo: 35.68, 139.69
# Mexico City: 19.43, -99.13
nearby = near_me(quakes, my_lat=37.77, my_lon=-122.42, max_km=300)
Enter fullscreen mode Exit fullscreen mode

Add desktop notifications (optional)

import subprocess

def notify(title, message):
    """Send a desktop notification (Linux/macOS)."""
    subprocess.run(["notify-send", title, message])
Enter fullscreen mode Exit fullscreen mode

Hook it into the main loop:

for eq in quakes:
    if eq["properties"]["mag"] >= 5.0:
        p = eq["properties"]
        notify(f"M{p['mag']} Earthquake!", p["place"])
Enter fullscreen mode Exit fullscreen mode

What I Actually Learned

A few things surprised me building this:

  1. There are ~250 earthquakes per day worldwide. Most are tiny and nobody feels them. But M2.5+? Still about 60-70 per day. The earth is constantly moving.

  2. Depth matters more than you'd think. A M5.0 at 10 km depth causes way more damage than a M6.0 at 400 km depth. The script shows depth for a reason.

  3. The USGS feed is fast. Events typically appear within 5-10 minutes of occurrence. That's fast enough for personal monitoring, though not for early warning systems (those need seismometer networks).

  4. Alaska accounts for ~50% of US earthquakes. Looking at the data, it's kind of wild how much seismic activity happens up there versus the contiguous US.

Auto-Running It

Want it to check every hour? Add a cron job:

# Check every hour, save to file
0 * * * * /usr/bin/python3 /path/to/quake_check.py >> /tmp/quakes.log 2>&1
Enter fullscreen mode Exit fullscreen mode

Or run it as a background loop:

import time

while True:
    quakes = get_earthquakes()
    show_quakes(quakes)
    console.print(f"\n[dim]Checking again in 30 minutes...[/dim]")
    time.sleep(1800)
Enter fullscreen mode Exit fullscreen mode

Wrapping Up

Total lines of code: 30. Total cost: $0. Total setup time: 5 minutes.

This is one of those projects where the effort-to-value ratio is absurdly good. You get real-time earthquake monitoring for any location on Earth, with no API keys and no dependencies beyond rich.

If you're building something that needs earthquake data as part of a larger project — weather dashboards, disaster preparedness tools, IoT safety systems — I've been using QuotaLink which bundles several free data APIs (earthquake, weather, air quality) into a single endpoint. Could save you some glue code.


Resources:

Top comments (0)