# USGS Water Levels & Gauges — New API, Daily Values (`extensive_necklace_zmp/usgs-water-levels-gauges`) Actor

River and lake water levels, gauge heights, and streamflow for any US state or gauge list — daily values with recent history, freshness status, and validation — from the NEW official USGS Water Data API (the legacy API every other water actor uses shuts down in early 2027).

- **URL**: https://apify.com/extensive\_necklace\_zmp/usgs-water-levels-gauges.md
- **Developed by:** [Glass Operations](https://apify.com/extensive_necklace_zmp) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 results

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## USGS Water Levels & Gauges — New API, Daily Values

Get **river water levels, lake/reservoir elevations, and streamflow** for
any US state or any list of USGS gauges — validated daily values with
recent history, freshness status, and a source link on every record —
straight from the **official USGS Water Data API**.

### Why this actor

- **Built on the NEW USGS API — the one that survives 2027.** USGS is
  decommissioning its legacy `waterservices.usgs.gov` API in early 2027.
  Every other USGS water actor on the store reads that dying API (checked
  their docs — none even mention the shutdown). This actor talks only to
  the replacement, `api.waterdata.usgs.gov`, so it keeps working — and
  your pipeline built on it does too.
- **Daily values with history, not just a snapshot.** Each record carries
  the gauge's daily values for your chosen window (up to a year) plus the
  latest reading — enough to see trend, not just a number.
- **Validated, never guessed.** Readings outside physical plausibility
  bounds are dropped and counted, never published. Single-day sensor
  glitches in level data (a lake "rising" 125 ft for one day — real
  example) are filtered out. Streamflow is deliberately NOT glitch-filtered
  — flash floods are real and this actor won't erase them.
- **Honest freshness.** The USGS "latest" feed includes gauges that died
  in 2012 (measured). State queries return only gauges reporting within
  the last 21 days; every record carries `freshness`
  (`active`/`delayed`/`inactive`) and `age_days`, so a stale gauge can
  never masquerade as current.
- **A format change never becomes silent garbage.** Every parser opens
  with a signature check on the API's own payload structure. If USGS
  changes the format, the affected query **fails loudly** in
  `SOURCE_STATUS` — you will never quietly get wrong columns. States are
  fetched independently: one state failing leaves the others' data intact.
- **Provenance on every record**: the official USGS gauge page
  (`official_url`) and the exact API query that produced the data
  (`source_url`). Verify any row in one click.

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `states` | array | `["Texas"]` | 2-letter codes or full names. Clear it (`[]`) for site-id-only runs |
| `siteIds` | array | — | USGS site numbers, e.g. `08158000` or `USGS-08158000`. Returned even if stale (freshness tells the truth) |
| `parameters` | array | Gage height + Lake/reservoir elevation | Also: `Streamflow`. One record per gauge per measurement |
| `periodDays` | integer | 30 | Daily-history window, 1–365 |
| `includeSeries` | boolean | true | Off = latest readings only — a much faster, much cheaper run |
| `maxSites` | integer | 100 | Distinct gauge sites per run (Texas alone has ~600 active gage-height sites; the default is moderate because of the API's volume rate limit — raise it freely for occasional runs) |
| `maxRecords` | integer | 5000 | One record = one gauge × one measurement |

```json
{
  "states": ["CO", "New Mexico"],
  "parameters": ["Streamflow"],
  "periodDays": 90
}
```

```json
{
  "states": [],
  "siteIds": ["08158000", "USGS-02169000"],
  "parameters": ["Gage height", "Streamflow"],
  "periodDays": 365
}
```

### Output

One dataset item per gauge site per measurement:

```json
{
  "site_id": "USGS-08158000",
  "site_number": "08158000",
  "site_name": "Colorado Rv at Austin, TX",
  "site_type_code": "ST",
  "state": "Texas",
  "county": "Travis County",
  "latitude": 30.2461, "longitude": -97.6801,
  "vertical_datum": null,
  "parameter": "Gage height",
  "parameter_code": "00065",
  "statistic": "daily mean",
  "statistic_id": "00003",
  "unit": "ft",
  "latest_date": "2026-09-04",
  "latest_value": 4.18,
  "freshness": "active",
  "age_days": 1,
  "period_start": "2026-08-06",
  "period_end": "2026-09-05",
  "series": [["2026-08-06", 3.92], ["2026-08-07", 3.95]],
  "n_readings": 30,
  "dropped_readings": 0,
  "official_url": "https://waterdata.usgs.gov/monitoring-location/08158000/",
  "source_url": "https://api.waterdata.usgs.gov/ogcapi/v0/collections/daily/items?...",
  "fetched_at": "2026-09-05T21:14:09Z"
}
```

- `freshness` — `active` (reading within 7 days), `delayed` (within 45),
  `inactive` (older). Computed, never assumed.
- `series` — `[date, value]` pairs for the window, validated and (for
  level parameters) glitch-filtered; `null` if the history fetch failed
  for that gauge (reported in `SOURCE_STATUS`, the latest reading still
  returns).
- `dropped_readings` — how many raw points validation removed for this
  gauge (out-of-bounds or isolated single-day spikes).
- `statistic` — the daily statistic USGS publishes for this series (mean
  preferred, then min/max/observation; tidal gauges publish tidal
  high-high/low-low statistics instead and are carried honestly as such —
  for those, `tidal high-high` = the day's peak water level).
- Where a site publishes several elevation datums, one is chosen by fixed
  ranking (NGVD 29 → NAVD 88 → local datum) — no double records.

The run also writes **`SOURCE_STATUS`** to the key-value store: per-state
status (`ok`/`failed`), record/site counts, failed-series counts, API
request count, timing, and a floor warning if a state returned
suspiciously few gauges.

### Choosing a run shape (cost control)

- **Latest levels for a state, cheapest:** `{"states": ["WA"],
  "includeSeries": false}` — a handful of API calls, seconds.
- **Monitoring dashboard, one basin:** put your gauge list in `siteIds`,
  `periodDays: 30`, schedule daily.
- **Research pull:** `periodDays: 365` on a specific site list. (State ×
  365-day runs are the slowest shape — the actor paces itself to respect
  the API's rate limits; prefer site lists for long windows.)

### Honest limitations

- **Daily values, not real-time.** This is the daily-values feed (the
  right one for levels/trend history). The most recent value is usually
  yesterday's; a reading taken 5 minutes ago won't be here.
- Recent values carry USGS's `Provisional` status upstream and may be
  revised by USGS later; this actor reports what USGS publishes at fetch
  time.
- A state query returns gauges reporting within the last 21 days —
  long-dead gauges are excluded on purpose (use `siteIds` to fetch a
  specific gauge regardless of freshness).
- Coverage is whatever USGS itself operates. Some reservoirs are run by
  other agencies (TVA, USACE) and have no USGS gauge; this actor cannot
  invent them.
- The API enforces a volume-weighted rate limit (~1,000 requests/hour).
  The actor paces itself and honors the API's `Retry-After`; a very large
  run (many states × long windows) will be slow rather than wrong.

### Typical usages

- **Flood/drought monitoring feed:** schedule daily,
  `{"states": ["LA", "MS"], "parameters": ["Gage height", "Streamflow"], "periodDays": 14}`.
- **Lake levels for a property/recreation site:**
  `{"states": ["SC"], "parameters": ["Lake or reservoir elevation"]}`.
- **Hydrology research:** site lists with `periodDays: 365`.
- **Migrating off the legacy API before 2027:** the output carries the
  new API's identifiers (`site_id`, `parameter_code`, `statistic_id`) —
  a working reference for your own migration.

### Legality

USGS water data is US-government public-domain data, published
specifically for reuse via the official API this actor reads. No logins,
no paywalls, no scraping of private sites, no personal data.

# Actor input Schema

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

US states to pull gauges for — 2-letter codes (TX) or full names (Texas) both work. A state query returns every gauge with a reading in the last 21 days for the chosen parameters, up to the site limit below. Leave empty if you're using specific site ids instead.

## `siteIds` (type: `array`):

USGS site numbers, e.g. 08158000 or USGS-08158000 (find them on any waterdata.usgs.gov gauge page). These are returned even if stale — the freshness field tells the truth. Combines with states.

## `parameters` (type: `array`):

Which measurements to return, one record per gauge per measurement. Gage height is the river water level; lake/reservoir elevation is the pool level above a datum; streamflow is discharge in cubic feet per second.

## `periodDays` (type: `integer`):

How many days of daily values to include per gauge (when the history series is on). Longer windows make runs slower.

## `includeSeries` (type: `boolean`):

Attach the daily values for the history window to each record (validated and glitch-filtered). Turn off for a fast latest-reading-only run — that mode needs only a handful of API calls per state.

## `maxSites` (type: `integer`):

Stop after this many distinct gauge sites across the whole run. Big states have many hundreds of active gauges (Texas alone has ~600 gage-height sites); the default is kept moderate because the USGS API rate-limits by volume — raise it freely for occasional runs.

## `maxRecords` (type: `integer`):

Stop after this many records (one record = one gauge × one measurement).

## Actor input object example

```json
{
  "states": [
    "Texas"
  ],
  "siteIds": [],
  "parameters": [
    "Gage height",
    "Lake or reservoir elevation"
  ],
  "periodDays": 30,
  "includeSeries": true,
  "maxSites": 100,
  "maxRecords": 5000
}
```

# Actor output Schema

## `results` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("extensive_necklace_zmp/usgs-water-levels-gauges").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("extensive_necklace_zmp/usgs-water-levels-gauges").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 '{}' |
apify call extensive_necklace_zmp/usgs-water-levels-gauges --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,extensive_necklace_zmp/usgs-water-levels-gauges"
        }
    }
}
```

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/ldnJI69vFWfQVVC4x/builds/hZhL7owidhBvDjqfj/openapi.json
