# EIA Short-Term Energy Outlook API — STEO Forecasts & History (`nexgensignal/eia-steo-short-term-energy-outlook-points`) Actor

EIA's Short-Term Energy Outlook as data: monthly, quarterly and annual forecasts and history for oil, gas, power, coal, renewables, prices and the economy. Every point marked forecast or history, with its release date. No API key. Part of NexGen Signal — official-source data products

- **URL**: https://apify.com/nexgensignal/eia-steo-short-term-energy-outlook-points.md
- **Developed by:** [NexGen Signal](https://apify.com/nexgensignal) (community)
- **Categories:** News, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $33.50 / 1,000 eia steo 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

## 🔮 EIA Short-Term Energy Outlook API — STEO Forecasts & History

Get EIA's Short-Term Energy Outlook (STEO) as data — monthly, quarterly and annual history and forecasts for crude oil and fuel prices, oil and gas production and consumption, electricity, coal, renewables, weather and the economy — from the U.S. Energy Information Administration's official Open Data bulk file `STEO.zip`.

Analysts, traders, planners and researchers use STEO as the reference near-term outlook. Every record says whether it is history or forecast (`is_forecast`, against the series' last historical period) and which outlook it comes from (`steo_release`), so forecasts from different months never get mixed up. 4,420 series, no API key.

The unit of output is one observation (one series, one period). You pay per observation delivered; a run that finds nothing costs nothing.

### 📊 Sample Output

![Table of STEO observations: Henry Hub natural gas price forecasts by month with forecast flags.](https://api.apify.com/v2/key-value-stores/IXCaMKjxSmUTLHhmq/records/eia-steo-short-term-energy-outlook-points.png)

| series_id | period | value | is_forecast | steo_release |
|---|---|---|---|---|
| STEO.NGHHMCF.M | 202712 | 4.161858 | true | 2026-09-09 |
| STEO.NGHHMCF.M | 202711 | 3.669787 | true | 2026-09-09 |
| STEO.NGHHMCF.M | 202710 | 3.371803 | true | 2026-09-09 |
| STEO.NGHHMCF.M | 202709 | 3.366505 | true | 2026-09-09 |
| STEO.NGHHMCF.M | 202708 | 3.313929 | true | 2026-09-09 |

Rows from live run `AmiRxgMAayW797bbl` on Apify (input: name contains henry hub, from 2026, 40 records). Notice the forecast months flagged `true` and the release date of the outlook on every row.

### ✅ What you get

Every field of each record:

- `record_id` — `<series_id>:<period>`, unique per observation.
- `series_id` — EIA series id, e.g. `STEO.BREPUUS.M`.
- `series_name` — series name as EIA publishes it.
- `units` — units, e.g. `dollars per barrel`.
- `units_short` — short units, when EIA gives them.
- `frequency` — `A`, `Q`, `M`, `W`, `D` or `4` (four-week average).
- `frequency_label` — annual, quarterly, monthly, weekly, daily, four-week average.
- `period` — period exactly as published: `2025`, `2025Q2`, `202506` or `20250613`.
- `period_start` — first day of the period as an ISO date.
- `value` — the observation. Only non-null observations are delivered.
- `geography` — EIA geography code(s), e.g. `USA-TX`.
- `geography2` — second geography for flows between two areas.
- `iso3166` — ISO 3166 code, when given.
- `latitude`, `longitude` — plant-level series only.
- `series_description` — EIA's description of the series, when given.
- `series_start`, `series_end`, `series_last_updated` — the series' first and last period, and when EIA last updated it.
- `last_historical_period` — last period that is history; later periods are forecasts.
- `is_forecast` — true when the period is after the last historical period.
- `steo_release` — release date (vintage) of the outlook file, so forecasts from different months stay apart.
- `source`, `source_dataset`, `licence`, `attribution`, `observed_at` — provenance on every record: EIA and the dataset, the bulk file and its last-modified date, EIA's public-domain statement quoted, the acknowledgment EIA asks for (e.g. `Source: U.S. Energy Information Administration (Sep 2026)`), and the UTC time the record was read.

### ⚙️ Sample inputs

**1. Store example — Brent and WTI price outlook**

```json
{
  "seriesIdPrefixes": ["STEO.BREPUUS.", "STEO.WTIPUUS."],
  "maxRecords": 10
}
```

The 10 newest points of the first matching series in file order (annual WTI, forecast years first); about $0.50 on the Free plan.

**2. Narrowed — Henry Hub monthly outlook, 2026 onward**

```json
{
  "seriesIds": ["STEO.NGHHUUS.M"],
  "periodFrom": "2026",
  "maxRecords": 50
}
```

Monthly Henry Hub history and forecast from January 2026 to the end of the outlook.

**3. Bulk — forecast months of every monthly price series**

```json
{
  "frequencies": ["M"],
  "nameContains": ["price"],
  "periodFrom": "2026-09",
  "maxRecords": 5000
}
```

Monthly series with "price" in the name, from September 2026 on. In the 9 September 2026 outlook, history ends by August 2026 for all 137 monthly price series, so every record here is a forecast (`is_forecast` true).

Input fields:

| Field | Meaning |
|---|---|
| `seriesIdPrefixes` | series ids starting with any of these — end with a dot to take every frequency of one series |
| `seriesIds` | exact series ids |
| `nameContains` | series whose name has every word of an entry, any order; put a phrase in double quotes to keep its words together |
| `geography` | text in the geography or ISO code, e.g. `USA-TX` |
| `frequencies` | any of `A`, `Q`, `M`, `W`, `D`, `4` |
| `periodFrom` | first period wanted: `2024`, `2024Q2`, `2024-06` or `2024-06-15` |
| `periodTo` | last period wanted (same formats) |
| `latestOnly` | one record per series: its newest observation inside the window |
| `maxRecords` | most observations delivered and billed in this run (default 1,000) |

### 🧾 JSON sample record

```json
{
  "record_id": "STEO.NGHHMCF.M:202712",
  "series_id": "STEO.NGHHMCF.M",
  "series_name": "Natural Gas Henry Hub Spot Price ($/mcf), Monthly",
  "units": "dollars per thousand cubic feet",
  "units_short": null,
  "frequency": "M",
  "frequency_label": "monthly",
  "period": "202712",
  "period_start": "2027-12-01",
  "value": 4.161858,
  "geography": null,
  "geography2": null,
  "iso3166": null,
  "latitude": null,
  "longitude": null,
  "series_description": null,
  "series_start": "199701",
  "series_end": "202712",
  "series_last_updated": "2026-09-09T16:03:00-04:00",
  "last_historical_period": "202608",
  "is_forecast": true,
  "steo_release": "2026-09-09",
  "source": "U.S. Energy Information Administration (EIA) — Short-Term Energy Outlook (EIA Open Data bulk download)",
  "source_dataset": "EIA Open Data bulk file STEO.zip (STEO.txt), last modified Wed, 09 Sep 2026 19:49:55 GMT",
  "licence": "Public domain. EIA: \"U.S. government publications are in the public domain and are not subject to copyright protection. You may use and/or distribute any of our data, files, databases, reports, graphs, charts, and other information products that are on our website or that you receive through our email distribution service.\" (eia.gov/about/copyrights_reuse.php)",
  "attribution": "Source: U.S. Energy Information Administration (Sep 2026)",
  "observed_at": "2026-10-04T03:48:37Z"
}
```

### 🔧 How it works

1. **Robots check.** `www.eia.gov/robots.txt` is read on every run; it allows `/opendata/bulk/`. A real disallow stops the run with nothing charged.

2. **Streamed download.** The actor opens `https://www.eia.gov/opendata/bulk/STEO.zip` and decompresses the ZIP line by line as it arrives. Nothing is saved to disk and the file is never downloaded first.

3. **Filter before parsing.** Each line is one series. Its id is checked against your prefixes, ids and frequencies before the line is parsed, so a narrow request skips most of the file. Name and geography filters parse every series line.

4. **Deliver, then charge.** Non-null observations inside your period window become records, newest first, pushed in batches; each batch is charged after delivery, so records and charges always match. The download stops the moment `maxRecords` or your maximum charge is reached.

5. **Receipt.** `RUN_RECEIPT` records the file and its date, lines read, series matched, whether the file was read to the end, and delivered and charged counts.

No login, API key, proxy or bot workaround — one public EIA file, and no personal data in it.

### 💰 Pricing example

Per observation delivered, no start fee, no monthly charge:

| Apify plan | Price per observation |
|---|---|
| Free | $0.05 |
| Bronze | $0.045 |
| Silver | $0.04 |
| Gold, Platinum, Diamond | $0.0335 |

- 10 observations (the Store example): $0.50 on the Free plan, $0.335 on Gold.
- 1,000 observations (the default cap): $50 on Free, $45 on Bronze, $40 on Silver, $33.50 on Gold.

**Coverage and size.** Live count from the file read on 3 October 2026 (STEO.zip, release of 9 September 2026): **753,105 observations in 4,420 series** (plus 177 category lines = 4,597 lines; the planning index counted 4,597 series and 753,105 observations — they agree). The file is 5.4 MB compressed. A filter is required; a whole-file read takes seconds, and a full pull is 753,105 records, billed per observation. Each STEO release replaces the previous one in the bulk file; to keep a history of forecasts, run this actor after each release and keep the records (they carry `steo_release`).

### ⚖️ Legal & ToS

Data: U.S. Energy Information Administration, Open Data bulk download (`STEO.zip`). EIA's copyright and reuse page says: "U.S. government publications are in the public domain and are not subject to copyright protection. You may use and/or distribute any of our data, files, databases, reports, graphs, charts, and other information products that are on our website or that you receive through our email distribution service." EIA asks for an acknowledgment with the publication date; every record carries one in `attribution`.

The actor reads only this public file with a declared User-Agent; `www.eia.gov/robots.txt` allows the path and is checked on every run. No login, key, proxy or form. Energy statistics and facility-level series only — no personal data.

This actor is not affiliated with or endorsed by EIA. Figures are EIA's as published in the file; check EIA's release notes for revisions.

### ❓ FAQ

**Do I need an EIA API key or account?**
No. The actor reads EIA's public bulk file, which needs no key, login or registration.

**Why must I give a series prefix, id, name or geography?**
Because the file is large (753,105 observations). A filter keeps runs fast and bills only what you asked for; the actor refuses an unfiltered run with a clear message.

**Why did my run return 0 records?**
Nothing in the file matched — usually a prefix that is too specific or a period window with no data. The receipt shows how many series matched. A zero-record run is not charged.

**How fresh is the data?**
As fresh as EIA's `STEO.zip`, which EIA republishes as its releases update; each record names the file's last-modified date.

**Can I get the whole file?**
Yes: widen the filters and raise `maxRecords`. The file is streamed, never held in memory; the receipt states how far it was read. Large pulls take a long time and are billed per observation.

**How do I know which points are forecasts?**
`is_forecast` is true when the period is after `last_historical_period`; `steo_release` is the outlook's release date.

**Can I compare outlooks over time?**
Yes — schedule a run after each monthly STEO release and keep the records; `steo_release` tells them apart.

### 🆘 Troubleshooting

- **0 records** — STEO ids start with `STEO.`; check the series on EIA's STEO data browser.
- **Mixed forecasts and history** — filter on `is_forecast` in your dataset, or set `periodFrom` after the last historical period.
- **Stopped at maxRecords** — raise `maxRecords` or use `latestOnly`.
- **CAPPED message** — your maximum total charge was reached; raise it in the run options.

### 🔗 Related Actors

- [CFTC Commitments of Traders (COT) Data — Weekly Positions](https://apify.com/nexgensignal/cftc-commitments-of-traders-records) — weekly futures positioning in crude oil, natural gas and power alongside EIA prices.
- [EU Fuel Prices — Weekly Oil Bulletin by Country Since 2005](https://apify.com/nexgensignal/eu-weekly-oil-bulletin-records) — European pump prices to compare with US gasoline and diesel.
- [Spain Fuel Prices by City & Station — Cheapest (MINCOTUR)](https://apify.com/nexgensignal/es-fuel-station-price-records) — station-level fuel prices in Spain.
- [ENERGY STAR Product Records — EPA Certified Products](https://apify.com/nexgensignal/energy-star-product-records) — efficiency ratings for appliances and equipment.

🏢 **About NexGen Signal** — official-source data products from government and regulator publications. Browse the catalog: [apify.com/nexgensignal](https://apify.com/nexgensignal)

### ⭐ Found this useful?

If this actor saved you time, a rating on its Apify Store page helps other buyers find it.

Part of NexGen Signal — official-source data products.

# Actor input Schema

## `seriesIdPrefixes` (type: `array`):

Series ids starting with any of these, e.g. STEO.BREPUUS. (end with a dot to include every frequency of one series). Ids in this dataset start with STEO.

## `seriesIds` (type: `array`):

Exact series ids, e.g. STEO.NGHHUUS.M.

## `nameContains` (type: `array`):

Series whose name has every word of an entry, in any order (not case-sensitive), e.g. henry hub. Reads the whole file.

## `geography` (type: `array`):

Geography or ISO code text, e.g. USA-TX. Reads the whole file.

## `frequencies` (type: `array`):

Any of A (annual), Q (quarterly), M (monthly), W (weekly), D (daily), 4 (four-week average).

## `periodFrom` (type: `string`):

Only observations from this period: 2024, 2024Q2, 2024-06 or 2024-06-15.

## `periodTo` (type: `string`):

Only observations up to this period (same formats).

## `latestOnly` (type: `boolean`):

One record per series: its most recent observation (inside the period window).

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

Most observations delivered and billed in this run. One record = one observation.

## Actor input object example

```json
{
  "seriesIdPrefixes": [
    "STEO.BREPUUS.",
    "STEO.WTIPUUS."
  ],
  "seriesIds": [],
  "nameContains": [],
  "geography": [],
  "frequencies": [],
  "latestOnly": false,
  "maxRecords": 10
}
```

# Actor output Schema

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

The delivered (and billed) observations.

## `receipt` (type: `string`):

File used, lines read, series matched, delivered and charged counts.

# 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 = {
    "seriesIdPrefixes": [
        "STEO.BREPUUS.",
        "STEO.WTIPUUS."
    ],
    "maxRecords": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("nexgensignal/eia-steo-short-term-energy-outlook-points").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 = {
    "seriesIdPrefixes": [
        "STEO.BREPUUS.",
        "STEO.WTIPUUS.",
    ],
    "maxRecords": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("nexgensignal/eia-steo-short-term-energy-outlook-points").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 '{
  "seriesIdPrefixes": [
    "STEO.BREPUUS.",
    "STEO.WTIPUUS."
  ],
  "maxRecords": 10
}' |
apify call nexgensignal/eia-steo-short-term-energy-outlook-points --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nexgensignal/eia-steo-short-term-energy-outlook-points"
        }
    }
}
```

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/hl5BeWjuYCoxrIu0m/builds/3Tau4LPYSzUKH7Jml/openapi.json
