# US Grid Capacity & Interconnection Monitor (`huykenny/us-grid-capacity-interconnection-monitor`) Actor

Monitor US grid hosting capacity and interconnection queues. Track new and changing solar, BESS, wind, and generation projects across public energy datasets.

- **URL**: https://apify.com/huykenny/us-grid-capacity-interconnection-monitor.md
- **Developed by:** [Kenny Ha](https://apify.com/huykenny) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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

## US Grid Capacity & Interconnection Monitor

Monitor US hosting capacity and interconnection queues from multiple public energy datasets in one normalized workflow.

**45,000+ normalized records across 5 live energy data sources.**

Track:

- new interconnection projects
- project status and capacity changes
- battery storage and BESS activity
- solar and wind development
- project removals
- utility hosting capacity

Instead of manually downloading spreadsheets and utility datasets, run one Actor and receive normalized structured data with persistent change detection.

**Built for recurring monitoring:** once your baseline is established, a scheduled run that finds no changes costs approximately **$0.05** — see [Pricing](#how-much-does-it-cost).

#### Why use this Actor?

**Hosting capacity + interconnection queues + automated change monitoring in one Actor.**

Most interconnection datasets only tell you what exists right now. This Actor also remembers previous runs, so scheduled monitoring can tell you what's actually new, updated, unchanged, or removed — turning fragmented public utility data into an ongoing lead feed instead of a one-off download.

### What can you use this Actor for?

- Monitor new interconnection projects as they enter a public queue
- Track changes to existing queue projects (status, capacity, target completion date)
- Research solar development activity in a specific state or utility territory
- Research battery storage and BESS project activity
- Monitor renewable-energy development across multiple public datasets at once
- Analyze public utility hosting-capacity datasets for available headroom
- Watch competitor or developer project activity
- Research regional grid activity by state, county, or utility
- Build structured energy datasets for internal tools or BI
- Automate recurring grid-data monitoring on a schedule
- Detect projects added or removed since the previous run

### Who is this Actor for?

**Solar developers** — research public hosting-capacity data and monitor new or changing solar projects in interconnection queues.

**Battery storage and BESS developers** — track storage projects, queue activity, capacity information, and changing interconnection records.

**Renewable-energy developers** — monitor public interconnection datasets without repeatedly downloading and comparing spreadsheets manually.

**Energy investors** — follow project-development activity, technologies, developers, capacities, and queue changes.

**Energy consultants** — aggregate multiple public grid datasets into one normalized structured schema.

**Competitive-intelligence teams** — track changes in project activity by developer, geography, technology, capacity, and status where available.

**Infrastructure and data-center researchers** — use public grid and hosting-capacity information as one input into broader infrastructure research.

Hosting-capacity data alone does not prove that a location is suitable for a data center or that power can actually be delivered to a project — see [Limitations](#limitations).

### Supported sources

| Source | Region | Dataset type | Status |
| --- | --- | --- | --- |
| NYSEG / RG\&E (Avangrid) Hosting Capacity | New York | Hosting capacity | Live |
| CAISO Public Generator Interconnection Queue | California | Interconnection queue | Live |
| NYISO Interconnection Queue | New York | Interconnection queue | Live |
| LBNL Queued Up | United States (national) | Interconnection queue | Live |
| PSCo / Xcel Energy Colorado Hosting Capacity | Colorado | Hosting capacity | Live |

The full current dataset across all five sources contains **approximately 45,000 records** as of the last verified full run — this changes over time as source data changes, so treat it as an order of magnitude, not a fixed count. Full technical detail per source (exact endpoints, fields, update cadence, and sources we researched but rejected): [`docs/SOURCES.md`](docs/SOURCES.md).

### Hosting-capacity data

The Actor integrates selected public utility hosting-capacity datasets (NYSEG/RG\&E and PSCo/Xcel Colorado today). These can help you research:

- distribution circuits and feeders
- available hosting capacity headroom (in MW)
- regional capacity patterns across a utility's territory
- utility infrastructure identifiers (substation, feeder, voltage)

A value in a hosting-capacity dataset does **not** guarantee that a specific interconnection request will be approved — it's a utility-published estimate, not a commitment.

### Interconnection queue data

The Actor combines public queue datasets (CAISO, NYISO, LBNL Queued Up) into one normalized schema. Depending on the source, a record may include:

- project name and, where the source publishes it, developer/owner
- technology (`projectType`, plus the original source text in `rawTechnology`)
- capacity in MW
- queue status (normalized `status`, plus the original source text in `rawStatus`)
- interconnection point / point of interconnection
- state and county
- queue date and target completion date, where available

Field availability genuinely differs by source — for example, CAISO's public queue report doesn't publish a developer name at all, so `developer` is `null` for CAISO records; NYISO and LBNL do publish it when the source itself has it.

### Delta monitoring

Every record gets a deterministic `recordId` (stable across runs — never based on a timestamp) and a `fingerprint` computed from the fields that actually matter commercially (capacity, status, dates, location, point of interconnection). Every run tags each record:

- **NEW** — a record seen for the first time. On a source's very first-ever run this is your baseline; from then on, `NEW` means a genuinely new project entered that source.
- **UPDATED** — an existing record whose tracked information changed since last seen. `changedFields` and `previousValues` tell you exactly what changed.
- **UNCHANGED** — an existing record with no detected change. These do not generate item-level billing (see [Pricing](#how-much-does-it-cost)).
- **REMOVED** — a record that disappeared from a source since last seen.

**Removal safety:** a source only ever reports `REMOVED` records when it completed a full, successful, unfiltered fetch. If a source temporarily fails, or you scope a run with `states`/`counties`/`maxItems`, the Actor will never mistake "we didn't look at everything this time" for "everything we didn't see is gone" — no false mass-removals.

### Snapshot vs. monitoring mode

Set with the `deltaMode` input field:

| `deltaMode` value | What you get |
| --- | --- |
| `all` (default) | Every current record, tagged `NEW`/`UPDATED`/`UNCHANGED` (plus `REMOVED` if enabled) — a full current snapshot with change context. |
| `changes-only` | Only `NEW`, `UPDATED`, and `REMOVED` — skip everything unchanged. |
| `new-only` | Only brand-new records — the cleanest feed for a scheduled lead alert. |

Your **first run for a given `stateStoreName`** establishes the baseline for whichever sources you selected — everything comes back as `NEW`. If you'd rather not see that initial flood, set `initializeStateOnly: true` on the first run: it saves the baseline silently and returns no dataset items, so your next real run starts clean.

### Example use cases

**Track new grid projects** — run on a schedule with `deltaMode: "new-only"` and read only newly discovered projects each time.

**Monitor battery-storage projects** — set `projectTypes: ["battery-storage", "hybrid"]` (paired solar/wind+storage projects normalize to `hybrid`, storage-only projects to `battery-storage`) and watch for new or updated records.

**Watch California interconnection activity** — set `sourceIds: ["caiso-public-queue"]` and monitor queue changes on a schedule.

**Research US interconnection projects broadly** — set `sourceIds: ["lbnl-queued-up"]` for the broadest national interconnection dataset in this Actor.

**Research hosting capacity** — set `sourceIds: ["nyseg-rge-hosting-capacity"]` or `["psco-colorado-hosting-capacity"]` for utility-published available-capacity data.

### How much does it cost?

This Actor uses **Pay-Per-Event pricing** — you pay for what you get, not for compute time:

| Event | Fires when | Price |
| --- | --- | --- |
| Actor start | Once per run | $0.05 |
| Initial item | A record from a source's first-ever baseline population | $0.0002 |
| New item | A genuinely new record found during ongoing monitoring | $0.005 |
| Updated item | A record whose tracked data changed | $0.005 |
| Removed item | A record safely confirmed removed from a source | $0.002 |
| Unchanged | — | **$0, never charged** |

A full run across all five sources contains around 45,000 normalized records and costs approximately **$9** on a fresh baseline. After that baseline is established, an identical monitoring run with no changes costs approximately **$0.05** — because unchanged records are never billed.

| Monitoring result | Approximate price |
| --- | ---: |
| No changes | $0.05 |
| 10 changes | $0.10 |
| 100 changes | $0.55 |
| 1,000 changes | $5.05 |

Actual cost depends on which sources you select, how many records populate your baseline, and how many changes a given run detects. Full pricing rationale and how it's implemented: [`docs/MONETIZATION.md`](docs/MONETIZATION.md).

**If you run all five sources for your first baseline**, set a run cost limit of at least $10 (Console's "Cost limit" field, or `maxTotalChargeUsd` via the API). Without one, Apify caps spending at your currently available balance — the Actor will stop cleanly and safely partway through rather than overcharging you, but you'd get an incomplete baseline. Running sources one at a time, or starting with `initializeStateOnly: true`, avoids this entirely.

### Example input

**Full dataset, default settings** (all five sources, first run establishes your baseline):

```json
{}
```

**Establish a baseline quietly on your first run** (no dataset items, just seeds the monitor):

```json
{ "initializeStateOnly": true }
```

**Monitor CAISO for new and updated records only:**

```json
{
  "sourceIds": ["caiso-public-queue"],
  "deltaMode": "changes-only",
  "stateStoreName": "my-caiso-monitor"
}
```

**Track new battery-storage and hybrid projects above 20 MW:**

```json
{
  "projectTypes": ["battery-storage", "hybrid"],
  "minCapacityMw": 20,
  "deltaMode": "new-only",
  "stateStoreName": "my-storage-monitor"
}
```

**Research hosting capacity in New York:**

```json
{
  "sourceIds": ["nyseg-rge-hosting-capacity"],
  "minAvailableCapacityMw": 1,
  "deltaMode": "all"
}
```

See the **Input** tab for every available field and its default.

### Example output

```json
{
  "recordId": "626a22fa6d633851e7abdb6e",
  "sourceId": "caiso-public-queue",
  "sourceName": "CAISO Public Generator Interconnection Queue",
  "sourceType": "interconnection-queue",
  "projectName": "TULE WIND",
  "developer": null,
  "projectType": "hybrid",
  "rawTechnology": "Wind Turbine + Battery",
  "capacityMw": 193.8,
  "state": "CA",
  "county": "SAN DIEGO",
  "utility": "SDGE",
  "isoRto": "CAISO",
  "pointOfInterconnection": "Boulevard East Substation 138 kV",
  "queueDate": "2004-05-24",
  "status": "active",
  "rawStatus": "Active",
  "changeType": "NEW",
  "changedFields": null,
  "sourceUrl": "https://www.caiso.com/library/interconnection-queue-reports",
  "scrapedAt": "2026-08-21T22:12:47.560Z"
}
```

This is a real record from a live run — a 193.8 MW wind+battery hybrid project in San Diego County, CA. Fields not relevant to a given record (e.g. `substation`/`voltageKv` for a queue-type source, or `latitude`/`longitude` when a source doesn't publish coordinates) are `null` rather than guessed.

### Scheduling

Use Apify **Schedules** to run this Actor automatically — daily or weekly monitoring is the primary intended use. Keep `stateStoreName` identical across scheduled runs so persistent state keeps working: that's what lets the Actor tell a genuinely new record apart from one it already showed you.

### API

**JavaScript (apify-client):**

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });

const run = await client.actor('huykenny/us-grid-capacity-interconnection-monitor').call({
    sourceIds: ['caiso-public-queue'],
    deltaMode: 'new-only',
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

**Python (apify-client):**

```python
from apify_client import ApifyClient

client = ApifyClient('YOUR_APIFY_TOKEN')

run = client.actor('huykenny/us-grid-capacity-interconnection-monitor').call(run_input={
    'sourceIds': ['caiso-public-queue'],
    'deltaMode': 'new-only',
})

items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

**curl:**

```bash
curl "https://api.apify.com/v2/acts/huykenny~us-grid-capacity-interconnection-monitor/runs?token=YOUR_APIFY_TOKEN" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"sourceIds": ["caiso-public-queue"], "deltaMode": "new-only"}'
```

### Output formats

Results land in a standard Apify dataset — export as JSON, CSV, Excel, or XML directly from the Console, or read them via the Apify API/SDKs.

### Integrations

Works with anything that connects to an Apify dataset: the Apify API, Schedules, webhooks, Make, Zapier, or a direct pull into your own database or workflow.

### Reliability

- Each source is isolated — one source failing (a utility endpoint down, a spreadsheet format change) doesn't stop the run; the others still complete, and the failure is reported in the run's `RUN_SUMMARY`.
- Parsing is defensive: unexpected values are left `null`/`unknown` rather than guessed, and known source quirks (footer rows, broken header rows, Excel serial dates) are handled explicitly per source.
- Removal safety (above) protects against a temporary source failure ever being mistaken for real removals.
- Every source's raw schema is normalized into one consistent output schema, with the original source text preserved in `rawTechnology`/`rawStatus` for traceability.

### Limitations

- This Actor does not cover every US utility or interconnection authority — five sources today, across NY, CA, CO, and one national dataset. See [`docs/SOURCES.md`](docs/SOURCES.md) for what was researched and rejected.
- Public source datasets can contain inaccuracies, and the utilities/operators can change their formats or update cadence without notice.
- Hosting capacity is not guaranteed interconnection capacity, and interconnection-queue presence does not guarantee a project gets built.
- Normalized fields (`developer`, `capacityMw`, dates, etc.) are genuinely absent for some sources — this reflects what the source actually publishes, not a parsing gap.
- Some source-specific values (e.g. NYISO's short fuel-type codes) are kept in their original source-native form pending a verified lookup table.
- External sources can occasionally be temporarily unavailable; that source is skipped for the run rather than failing everything.

### Disclaimer

This is an independent, community-built Actor and is not affiliated with, endorsed by, or sponsored by CAISO, NYISO, LBNL, NYSEG, RG\&E, Xcel Energy, PSCo, or any other referenced utility, grid operator, government organization, or data publisher. All trademarks and organization names belong to their respective owners. The Actor aggregates publicly accessible data for structured research and monitoring purposes.

### Support

If a source stops working, a field looks incorrect, you hit an error, or you need help configuring a run, please open an issue through this Actor's **Issues** tab on Apify Store.

# Actor input Schema

## `sourceIds` (type: `array`):

Pick one or more datasets, or leave empty to run all of them.

## `deltaMode` (type: `string`):

"Full current snapshot": every current record, tagged NEW/UPDATED/UNCHANGED. "New + updated + removed": skip unchanged records. "New records only": the cleanest feed for scheduled lead alerts.

## `stateStoreName` (type: `string`):

Identifies this monitor so the Actor remembers what it saw last time. Use the exact same value on every scheduled run for the same purpose; use a different value to start a separate, independent monitor.

## `initializeStateOnly` (type: `boolean`):

Turn this on for your very first run of a new monitoring name: it quietly saves the current data as your baseline and returns no dataset items, so your next real run starts clean instead of showing thousands of "NEW" records at once.

## `emitRemovedRecords` (type: `boolean`):

Include records that safely disappeared from a source since the last run. Only applies where the Actor can confirm a full, unfiltered fetch — see the README's "Removal safety" section.

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

Two-letter US state codes, e.g. "CA", "NY". Leave empty for no state filter.

## `counties` (type: `array`):

County names, matched exactly as the source publishes them (usually uppercase, e.g. "SAN DIEGO"). Leave empty for no county filter.

## `projectTypes` (type: `array`):

Only include these technology types. Paired solar/wind + storage projects normalize to "hybrid"; storage-only projects normalize to "battery-storage".

## `statuses` (type: `array`):

Only include records with these normalized interconnection statuses. The original source-specific status text is always preserved in the output's rawStatus field.

## `minCapacityMw` (type: `integer`):

Only include records with a total capacity at or above this many megawatts.

## `maxCapacityMw` (type: `integer`):

Only include records with a total capacity at or below this many megawatts.

## `minAvailableCapacityMw` (type: `integer`):

For hosting-capacity sources (NYSEG/RG\&E, PSCo/Xcel Colorado): only include feeders/circuits with at least this much available headroom for new interconnections.

## `maxItems` (type: `integer`):

Caps how many records each source returns, to bound run time and cost — useful for a quick test. Leave empty for full source coverage. Setting this disables removed-record detection for the run, since the fetch becomes intentionally partial.

## `debug` (type: `boolean`):

Enable verbose debug-level logs for troubleshooting.

## Actor input object example

```json
{
  "deltaMode": "all",
  "stateStoreName": "my-california-solar-monitor",
  "initializeStateOnly": false,
  "emitRemovedRecords": true,
  "states": [
    "CA",
    "NY"
  ],
  "debug": false
}
```

# Actor output Schema

## `records` (type: `string`):

Delta-tagged (NEW/UPDATED/UNCHANGED/REMOVED) records from every requested source, normalized into one schema.

## `runSummary` (type: `string`):

Per-source health, record counts, and charged event totals for this run.

# 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("huykenny/us-grid-capacity-interconnection-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("huykenny/us-grid-capacity-interconnection-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 '{}' |
apify call huykenny/us-grid-capacity-interconnection-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,huykenny/us-grid-capacity-interconnection-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/amJ6dUFyEfg6IIWYv/builds/J8KvjkzUJe9KtBgNg/openapi.json
