# EIA Power Project Monitor (`maydit/eia-power-project-monitor`) Actor

Monitor planned US generators, capacity and scheduled operation months from official EIA reporting. Filter project watchlists and compare confirmed saved observations.

- **URL**: https://apify.com/maydit/eia-power-project-monitor.md
- **Developed by:** [Brandt May](https://apify.com/maydit) (community)
- **Categories:** News, Automation
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 planned generator observations

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

![Follow planned power project revisions — illustrative generator watchlist](https://api.apify.com/v2/key-value-stores/nemaYfVcrTgloz8Wn/records/eia-power-project-monitor-0a9e4653425d.png?signature=vUYMtdou7dWaiB8PiKyl)

### Follow planned power project revisions

Build a focused research list from EIA's official planned-generator table. Review the published entity, technology, capacity, project status and scheduled operation month, then compare later observations with your saved baseline. Useful for equipment sales research, engineering teams and project development watchlists.

**One result is one planned generator.** The data describes monthly reporting, with publication lag. It does not verify current construction, forecast completion, or establish that a project serves a data center.

[Open in Console](https://console.apify.com/actors/l7DzOEjLHsxsaExoe/input) · [First run](#try-five-texas-generators) · [Output preview](#output-preview) · [Saved comparisons](#turn-a-project-list-into-a-saved-watchlist) · [Pricing](#pricing-and-run-outcomes)

### Try five Texas generators

Copy this input into Console's JSON editor. It selects up to 100 matching source entries and saves at most five generator observations. No API key, login or proxy subscription is required.

```json
{
  "states": [
    "TX"
  ],
  "maxSourceEntries": 100,
  "maxResults": 5
}
```

Open **Saved observations** or **CSV export** for the data, then **Run report** for counts and coverage. Check `reportingMonth` and `sourcePublishedDate` before using a row. Empty input reads the same official table and saves up to five rows across the unfiltered sample.

### Output preview

| Project review | Fields | How to read them |
| --- | --- | --- |
| Generator identity | `plantId`, `generatorId`, `plantName` | A plant can have several generators; use both IDs |
| Published organization | `entityId`, `entityName`, `producerType` | Source entity and classification, without contact enrichment |
| Technology and location | `state`, `technology`, `energySourceCode`, `primeMoverCode` | Published classifications |
| Reported project status | `statusCode`, `status` | Official planned-generator status and wording |
| Scheduled operation | `plannedYear`, `plannedMonth`, `plannedOperationMonth` | Month precision; no day or construction milestone is inferred |
| Capacity | `nameplateCapacityMw`, `netSummerCapacityMw` | Published MW values; unavailable values stay null |
| Reporting age | `reportingMonth`, `sourcePublishedDate` | Actual reporting period and release date, separate from `observedAt` |
| Saved revisions | `plannedOperationChangeMonths`, `nameplateCapacityChangeMw`, `netSummerCapacityChangeMw` | Current values minus the last saved values; positive month change means a later scheduled period |
| Supporting evidence | `sourceUrl`, `comparisonStatus`, `changedFields`, `previous`, `previousObservedAt`, `contentHash`, `matchedKeywords` | Official source, saved comparison and literal filter evidence |

Without comparison, status is `not_requested` and prior values/deltas are null. With comparison, `new` means new to your saved observations. It does not establish when a project was first announced. JSON preserves the prior snapshot; CSV works well for your project register.

### Find planned battery storage of at least 50 MW

```json
{
  "technologies": [
    "Batteries"
  ],
  "minimumCapacityMw": 50,
  "maxSourceEntries": 100,
  "maxResults": 5
}
```

### Follow an exact EIA plant ID

```json
{
  "plantIds": [
    "68847"
  ],
  "maxSourceEntries": 5,
  "maxResults": 5
}
```

Plant 68847 identifies 1000 Mile Solar in the retained source sample. A later release may change or omit its planned-generator entry, so this watchlist can legitimately become empty.

### Turn a project list into a saved watchlist

1. Choose plant IDs or a focused filter. Add `comparePrevious: true` and a dedicated `snapshotName` to the input.
2. Run once to save `new` generator observations. Repeat with the same snapshot name to receive `changed` or `unchanged` rows with prior values.
3. Keep `comparePrevious: true` and add `onlyChanges: true` to skip unchanged observations. This Actor requires both flags for changes-only output; a healthy repeat can save zero rows.
4. Read the completed run's SUMMARY before sending data to a spreadsheet or CRM. Upsert by `plantId + ":" + generatorId`. Retain the run ID for delivery replay. Route positive `plannedOperationChangeMonths` or nonzero capacity deltas for source review.

History is stored per generator in `maydit-eia-power-<snapshotName>`. Only confirmed saved output advances its entry; failed writes, spending stops and deadlines preserve unsaved baselines. Use **one writer per snapshot name**. Detected concurrent changes produce a partial result; the check is not an atomic lock. Inspect `historyUpdated` and `failedSources` before relying on a saved baseline.

Reporting period, release date and retrieval time alone do not create a project change. The snapshot covers substantive published generator fields. Missing entries never produce cancellation, retirement or removal records. Configure your own recurrence around EIA's monthly publication cycle; the Actor creates no schedule or downstream connection.

### Filters and bounded coverage

- States and plant IDs match exactly. Technology phrases and keywords match literally without case sensitivity; any listed term can match within its group. Keywords search plant name, entity name, technology and status. Separate filter groups use AND.
- `minimumCapacityMw` applies to published nameplate capacity; missing capacity cannot satisfy the threshold.
- The table is downloaded once. Filters run before stable plant-ID/generator-ID ordering and the `maxSourceEntries` selection. `maxResults` then caps confirmed dataset writes. Increasing the window does not fetch historical months.
- Defaults are 100 source entries, five saved results and a 240-second run budget. Supported bounds are 10,000 source entries, 5,000 saved rows and 30–3,600 seconds. The platform deadline retains a separate 25-second reserve.

Intentional source/result caps can finish successfully and remain visible in SUMMARY. Check `windowLimited`, matching/source counts and stop flags before calling the selected scope complete. Requests honor robots rules and use bounded responses, public-address checks and fixed source-origin restrictions. No private or user-supplied destination is fetched.

### Source and interpretation

The source is [EIA Electric Power Monthly, Table 6.5](https://www.eia.gov/electricity/monthly/epm_table_grapher.php?t=table_6_05), based on EIA-860/EIA-860M reporting. It excludes facilities with total generator nameplate capacity below 1 MW and covers planned additions, rather than a full operating/retired/cancelled catalog or interconnection queue.

The retained sample reported **July 2026 data released September 24, 2026**. Each run preserves the dates supplied by its response; the run date never replaces the reporting period. Preliminary reports can be revised, and a schedule/status change may be a correction. Verify consequential project decisions with current official records and the sponsor.

[EIA permits reuse of public-domain data with source and publication-date attribution](https://www.eia.gov/about/copyrights_reuse.php). This independent Actor is not endorsed by EIA and does not use its logo.

### Pricing and run outcomes

Base result rate on the FREE tier: **$5 per 1,000 saved generator observations**, plus the listed **Actor Start** charge. The [Pricing tab](https://apify.com/maydit/eia-power-project-monitor/pricing) is authoritative for your plan's current rates. Saved unchanged rows are billable; changes-only skips create no dataset-item charge. Platform usage charges may apply. Set both a result cap and an Apify maximum charge for recurring runs.

SUMMARY and Run report show saved counts, unchanged skips, history commits, errors and limit flags. Source failures and malformed records never become paid diagnostic rows. An all-failed run fails; a genuine no-match succeeds with an explanatory warning. Source/time/spending stops are incomplete, even when some rows remain useful.

For help, open **Issues** with the run URL, public plant ID or filter and expected field. Remove credentials and private information before posting.

# Actor input Schema

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

Optional two-letter state codes such as TX or AZ. Empty selects every state in the official table.

## `technologies` (type: `array`):

Optional literal technology phrases, matched without case sensitivity. Any phrase may match; for example Solar or Batteries.

## `plantIds` (type: `array`):

Optional exact numeric plant IDs. All generators at each selected plant are eligible.

## `minimumCapacityMw` (type: `number`):

Keep published nameplate capacities at or above this amount. Records with an unpublished capacity do not meet the threshold.

## `keywords` (type: `array`):

Optional literal terms matched without case sensitivity in project names and selected published text. Any term may match. For the milestone Actor, filtering applies only inside the selected source window.

## `maxResults` (type: `integer`):

Maximum confirmed dataset rows. Unchanged rows skipped by changes-only mode do not consume this limit.

## `comparePrevious` (type: `boolean`):

Use a named history store. The first observation is new and is saved as a baseline only after a confirmed dataset write. Use one writer per snapshot name.

## `onlyChanges` (type: `boolean`):

Requires comparison. A repeated unchanged window can validly save zero rows. Do not enable for a nonempty health sample.

## `snapshotName` (type: `string`):

History namespace (1–40 letters, numbers, underscores or hyphens). Reuse it to compare; choose a fresh name to start separately. Never schedule overlapping writers.

## `maxSourceEntries` (type: `integer`):

Maximum matching generators selected after filtering and stable plant/generator ordering. The official table is downloaded once; this does not reduce download size.

## `maxRunSeconds` (type: `integer`):

Own wall-clock budget; also stops 25 seconds before the platform deadline. Partial work and unsaved history are reported honestly.

## Actor input object example

```json
{
  "states": [],
  "technologies": [],
  "plantIds": [],
  "minimumCapacityMw": 0,
  "keywords": [],
  "maxResults": 5,
  "comparePrevious": false,
  "onlyChanges": false,
  "snapshotName": "default",
  "maxSourceEntries": 100,
  "maxRunSeconds": 240
}
```

# Actor output Schema

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

Normalized official-source records and optional saved comparisons. Failed requests are never dataset rows.

## `runReport` (type: `string`):

Readable summary of saved rows, source window, failures and history updates.

## `csvExport` (type: `string`):

Download confirmed saved rows for your spreadsheet.

## `summary` (type: `string`):

Machine-readable source coverage, filters, output count and stop conditions.

# 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 = {
    "states": [],
    "technologies": [],
    "plantIds": [],
    "minimumCapacityMw": 0,
    "keywords": [],
    "maxResults": 5,
    "comparePrevious": false,
    "onlyChanges": false,
    "snapshotName": "default",
    "maxSourceEntries": 100,
    "maxRunSeconds": 240
};

// Run the Actor and wait for it to finish
const run = await client.actor("maydit/eia-power-project-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 = {
    "states": [],
    "technologies": [],
    "plantIds": [],
    "minimumCapacityMw": 0,
    "keywords": [],
    "maxResults": 5,
    "comparePrevious": False,
    "onlyChanges": False,
    "snapshotName": "default",
    "maxSourceEntries": 100,
    "maxRunSeconds": 240,
}

# Run the Actor and wait for it to finish
run = client.actor("maydit/eia-power-project-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 '{
  "states": [],
  "technologies": [],
  "plantIds": [],
  "minimumCapacityMw": 0,
  "keywords": [],
  "maxResults": 5,
  "comparePrevious": false,
  "onlyChanges": false,
  "snapshotName": "default",
  "maxSourceEntries": 100,
  "maxRunSeconds": 240
}' |
apify call maydit/eia-power-project-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,maydit/eia-power-project-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/l7DzOEjLHsxsaExoe/builds/UAlGSVsMOAf0wit9C/openapi.json
