# USGS Earthquake Data Scraper (New Events JSON) (`steadfetch/usgs-earthquake-monitor`) Actor

Scrape USGS earthquakes from the official GeoJSON feeds: one validated JSON item per new event (event_id, magnitude, place, time, coordinates, depth, tsunami flag, event-page URL). Events are deduplicated by event_id, so no event is emitted or charged twice. No browser, no login, no API key.

- **URL**: https://apify.com/steadfetch/usgs-earthquake-monitor.md
- **Developed by:** [Steadfetch](https://apify.com/steadfetch) (community)
- **Categories:** News, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 earthquake delivereds

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

## USGS Earthquake Data Scraper (New Events JSON)

Monitor earthquakes worldwide from the official, keyless [USGS GeoJSON feeds](https://earthquake.usgs.gov/earthquakes/feed/v1.0/geojson.php). Choose a feed and a minimum magnitude, and get one structured dataset item per new event. No browser, no login, no API key.

### What it does

The Actor reads one official USGS summary feed on each run and returns one dataset item per earthquake: event ID, magnitude and magnitude type, place, origin time, last update, coordinates and depth, contributing network, event type, review status, tsunami flag, and the official USGS event-page URL.

- **Feeds:** `1.0_day`, `2.5_day` (default), `4.5_day`, `all_day`, `all_week` and `all_month`, all under `https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/`.
- **Magnitude filter:** `minMagnitude` is applied locally after reading the feed, so you never download or pay for events below your threshold.
- **Monitor deduplication:** every delivered `event_id` is stored in a named key-value store that survives between runs (the default store is run-scoped in Apify). An event is emitted at most once, even if USGS later updates its magnitude or status; updates are not re-emitted or re-charged.
- **Budget:** `maxEvents` caps how many new events a run can deliver, keeping cost predictable.
- **Schema validation:** every item is validated against `.actor/dataset_schema.json` before it reaches the dataset. With `strictSchema: true` (the default) an invalid item fails the run instead of pushing malformed data. The item schema is strict (`additionalProperties: false`).

The data is public US government geophysical data. The Actor returns events only: no personal data and no contact fields. USGS provides the feeds for programmatic use and requires no login, API key or CAPTCHA.

### Example output

```json
{
    "url": "https://earthquake.usgs.gov/earthquakes/eventpage/nc75452606",
    "event_id": "nc75452606",
    "mag": 1.04,
    "mag_type": "md",
    "place": "1 km SW of Anderson Springs, CA",
    "time": "2026-10-20T17:02:30.890Z",
    "updated": "2026-10-20T17:04:04.742Z",
    "detail_url": "https://earthquake.usgs.gov/earthquakes/eventpage/nc75452606",
    "coordinates": {
        "lon": -122.701667785645,
        "lat": 38.7693328857422,
        "depth_km": 1.4099999666214
    },
    "net": "nc",
    "event_type": "earthquake",
    "status": "automatic",
    "tsunami": 0,
    "scrapedAt": "2026-10-20T17:20:00.000Z",
    "source_url": "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.geojson"
}
```

`url` is the mandatory Steadfetch envelope field and is identical to `detail_url`: both point at the official USGS event page. It is the only field added to the STE-99 example so every Steadfetch Actor satisfies the same dataset envelope enforced by the repository publish gate. `source_url` is the exact USGS feed used in the run. Records missing a required field are skipped and counted; the Actor never invents data.

### Input

Minimal run (magnitude 2.5+ feed, no local magnitude filter, up to 1,000 new events):

```json
{
    "feed": "2.5_day"
}
```

A focused monitor:

```json
{
    "feed": "all_week",
    "minMagnitude": 4.5,
    "maxEvents": 200
}
```

| Field | Type | Description |
| --- | --- | --- |
| `feed` | `1.0_day`, `2.5_day`, `4.5_day`, `all_day`, `all_week` or `all_month` | USGS summary feed to read. Default `2.5_day` (last 24 hours, magnitude 2.5+). |
| `minMagnitude` | number | Only emit events with magnitude greater than or equal to this value. Default `0`, range 0-10. |
| `maxEvents` | integer | Maximum number of events saved to the dataset per run. Default `1000`, range 1-5000. |
| `monitorMode` | boolean | Default `true`: only event_ids not delivered by an earlier run are emitted (global dedupe). `false` re-delivers the selected feed up to `maxEvents` for a one-off backfill; the daily Store/QA probe uses `false` so it always has a small, non-empty deterministic input. |
| `strictSchema` | boolean | Default `true`; fail the run on output-schema violations. |

The monitor state is global to the Actor: with `monitorMode: true`, an `event_id` already delivered is never emitted again, even if it appears in a wider feed later. That is what makes a scheduled monitor idempotent and cheap. Set `monitorMode: false` only for a deliberate backfill (it can re-deliver and charge events already seen by another run).

### Project structure

```
.actor/actor.json                 Actor definition (payPerEvent, dataset schema, output schema)
.actor/input_schema.json          INPUT options (feed, minMagnitude, maxEvents)
.actor/dataset_schema.json        Strict item JSON Schema (fields) + table view for the Store
.actor/pay_per_event.json         PPE pricing (two synthetic platform events)
src/usgs-client.ts                USGS feed client: validated URL, retries, payload checks
src/extract.ts                    Pure mapping, magnitude filter and deduplication (fixture-tested, no network)
src/monitor-state.ts              Pure monitor-state parse and merge rules
src/main.ts                       Entry point: fetch, filter, validate, push, persist state
src/validate-output.ts            Ajv validator shared by the run and the tests
test/                             Offline GeoJSON fixtures and Vitest suites
```

### Pay-per-event pricing

The Actor uses Apify **pay-per-event** pricing with the two synthetic platform events:

| Event | Charged when | Price |
| --- | --- | --- |
| `apify-actor-start` | a run starts (synthetic, automatic) | 0.00005 USD per run (Apify-recommended default; includes 5 seconds of free compute) |
| `apify-default-dataset-item` | a new, validated event is saved to the dataset (synthetic, automatic) | 0.0015 USD per event = **1.50 USD per 1,000 events** |

There is no custom per-item event and no `Actor.charge()` call: the platform already charges `apify-default-dataset-item` per pushed item, so adding another event would bill users twice. Empty results, feed errors, retries and events skipped by monitor deduplication are never charged.

The price sits 50% above the Store leader (1.00 USD per 1,000 events, 16 users and no ratings at the time of the STE-99 spec) and inside Steadfetch's 1-10 USD band. It is justified by the strict validated schema, cross-run monitor deduplication and daily QA, which the leader does not advertise.

#### Cost per 1,000 events

USGS charges nothing for the feeds. A 1,000-event run is one HTTP request (the `all_month` feed is about 7 MB), a few seconds of a 256 MB container and no proxy. Measured locally with the committed fixtures: 1,000 events fetched from memory, mapped, magnitude-filtered, schema-validated and serialized in **under 0.2 seconds**, using 256 MB. At Apify compute rates that is well below **0.02 USD per 1,000 events**, so the gross margin at 1.50 USD per 1,000 is above 98%.

### Development

```bash
npm install
npm test                 # lint + typecheck + offline Vitest suites (no credit)
npm run publish:check    # Steadfetch publish gate
npm run schemas:validate # apify-cli schema validation
npm run smoke            # local Apify run against the live feed (no platform credit)
```

The default test suite runs against committed USGS GeoJSON fixtures and never touches the network or the Apify platform. It covers the real feed shape, the magnitude filter, `maxEvents`, monitor deduplication, malformed records and strict schema validation. A live feed check runs only with `USGS_LIVE_TEST=1`.

### FAQ

**Do I need a USGS API key?**
No. The summary feeds are keyless and public.

**Does it need a browser?**
No. USGS returns structured GeoJSON; plain HTTP is cheaper and faster than a browser-based Actor.

**How does monitor deduplication work?**
Every delivered `event_id` is stored in a named key-value store that persists between runs (the default store is run-scoped in Apify). The next run filters those IDs out before applying `maxEvents`, so only new events are pushed and billed. The state keeps the 50,000 most recent event IDs, enough for several months of the `all_month` feed.

**Does it return personal data?**
No. Only geophysical event fields and USGS URLs are returned. There are no personal names, email addresses or phone numbers in the output schema.

**When am I charged?**
Once per run start (`apify-actor-start`) and once per new event saved to the dataset (`apify-default-dataset-item`). Failed requests, retries, empty results and events already delivered by a previous monitor run are not charged.

**Is the output schema stable?**
Yes. The strict schema is versioned with the Actor; new fields would be an additive, reviewed change and the required fields do not change silently.

### Maintenance

This Actor is **tested daily**: automated runs check that the official USGS feeds are reachable and that the output still matches the published schema. Failures are reported as issues in the Steadfetch Actors repository.

# Actor input Schema

## `feed` (type: `string`):

USGS summary feed to read. 2.5_day (default) is the last 24 hours of magnitude 2.5+ events; all_month covers the last 30 days. Larger feeds take longer and may exceed maxEvents.

## `minMagnitude` (type: `number`):

Only emit events with a magnitude greater than or equal to this value (local filter).

## `maxEvents` (type: `integer`):

Maximum number of new events to save to the dataset per run.

## `monitorMode` (type: `boolean`):

Enabled: deliver only event_ids not delivered by an earlier run (global dedupe, never charge twice). Disabled: deliver the whole selected feed up to maxEvents (useful for a one-off backfill and for the daily Store/QA probe).

## `strictSchema` (type: `boolean`):

Fail the run when an item does not match the output schema. Keep enabled: Steadfetch never publishes Actors without output-schema validation.

## Actor input object example

```json
{
  "feed": "2.5_day",
  "minMagnitude": 2.5,
  "maxEvents": 10,
  "monitorMode": true,
  "strictSchema": true
}
```

# Actor output Schema

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

Dataset items validated against the item schema in dataset_schema.json (fields).

# 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 = {
    "feed": "2.5_day",
    "minMagnitude": 2.5,
    "maxEvents": 10,
    "monitorMode": false,
    "strictSchema": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadfetch/usgs-earthquake-monitor").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 = {
    "feed": "2.5_day",
    "minMagnitude": 2.5,
    "maxEvents": 10,
    "monitorMode": False,
    "strictSchema": True,
}

# Run the Actor and wait for it to finish
run = client.actor("steadfetch/usgs-earthquake-monitor").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 '{
  "feed": "2.5_day",
  "minMagnitude": 2.5,
  "maxEvents": 10,
  "monitorMode": false,
  "strictSchema": true
}' |
apify call steadfetch/usgs-earthquake-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,steadfetch/usgs-earthquake-monitor"
        }
    }
}
```

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/fdchFrhGnWbWVcM7a/builds/sK6QQ7EJBNgdJwAwE/openapi.json
