# STB Weekly Freight Rail Service Change Monitor (`aether_studio/stb-rail-service-change-monitor`) Actor

Tracks week-over-week changes in Class I railroad service performance metrics from the Surface Transportation Board's official consolidated workbook. Detects improvements and warnings across train speed, dwell time, cars held, trains held, and past-due orders.

- **URL**: https://apify.com/aether\_studio/stb-rail-service-change-monitor.md
- **Developed by:** [AetherPromptStudio](https://apify.com/aether_studio) (community)
- **Categories:** Automation, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.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/platform/actors/running/actors-in-store#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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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

## STB Weekly Freight Rail Service Change Monitor

An [Apify Actor](https://apify.com/actors) that monitors week-over-week changes in Class I railroad service performance metrics from the [Surface Transportation Board](https://www.stb.gov/reports-data/rail-service-data/).

### How It Works

1. **Discovery** — Scrapes the STB Rail Service Data page to find the latest EP724 Consolidated Data workbook URL
2. **Download** — Fetches the XLSX directly (no browser needed)
3. **Validation** — Verifies workbook structure: 6 dimension headers, ≥1000 data rows, ≥8 date columns
4. **Diffing** — Compares the newest two weekly columns, computes absolute delta and percent change, carries 4-week trailing history
5. **Filtering** — Applies user-configured railroad, measure, threshold, and interpretation filters
6. **Output** — Writes bounded, provenance-rich change records to the default dataset

### Quick Start

```bash
## Install
npm install

## Run locally
apify run

## With custom input
apify run --input='{"railroads":["BNSF"],"measureContains":"Speed","minPercentChange":5,"maxResults":50}'

## Run tests
npm test
````

### Input Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `railroads` | string\[] | `[]` | Filter by railroad name (substring match). Empty = all. |
| `measureContains` | string | `""` | Case-insensitive filter on measure column. |
| `minAbsoluteChange` | integer | `0` | Min absolute delta. 0 = disabled. |
| `minPercentChange` | number | `0` | Min absolute percent change. 0 = disabled. |
| `interpretations` | string\[] | `[]` | `improvement`, `warning`, `neutral`. Empty = all. |
| `maxResults` | integer | `200` | Max records (1–2000). |

**Threshold logic:** Records meeting **either** `minAbsoluteChange` **or** `minPercentChange` are included (OR logic). Setting both to 0 returns all records.

### Output Fields

Each dataset item:

| Field | Type | Description |
|-------|------|-------------|
| `recordKey` | string | Stable metric key plus the current reporting period |
| `metricId` | string | Stable SHA-256 hash from all six workbook dimension fields |
| `railroad` | string | Class I railroad (e.g. BNSF, UP, CSX, NS) |
| `measure` | string | Performance category |
| `variable` / `subVariable` | string | Specific metric breakdown |
| `currentValue` | number | Latest week's value |
| `previousValue` | number | Prior week's value |
| `absoluteDelta` | number | Current − previous |
| `percentChange` | number | `(delta / previous) × 100`, null if previous was 0 |
| `movement` | string | `increased` or `decreased` |
| `interpretation` | string | `improvement`, `warning`, or `neutral` |
| `interpretationLabel` | string | Conservative human-readable label |
| `history` | object\[] | 4-week trailing history: `[{period, value}]` |
| `currentPeriod` | string | Latest data period |
| `previousPeriod` | string | Prior data period |
| `units` | string | Normalized unit inferred from the official measure label |
| `sourceUrl` | string | Direct XLSX URL |
| `sourcePageUrl` | string | Official STB rail-service archive page |
| `retrievedAt` | string | ISO timestamp of retrieval |

### Directional Interpretation

| Metric Direction | Increase | Decrease |
|-----------------|----------|----------|
| Train Speed | ✅ Improvement | ⚠️ Warning |
| Dwell Time | ⚠️ Warning | ✅ Improvement |
| Cars Held on Line | ⚠️ Warning | ✅ Improvement |
| Trains Held | ⚠️ Warning | ✅ Improvement |
| Past-Due Orders | ⚠️ Warning | ✅ Improvement |
| All other metrics | Neutral | Neutral |

**Note:** These are deliberately narrow, naming-based classifications. They do not establish causality or predict service. All other measures remain `neutral`.

### Disclaimer

This data is sourced from official Surface Transportation Board (STB) reports. Values are as reported by Class I railroads and may be subject to revision. This is not a prediction, operational guarantee, or investment advice. Directional classifications are heuristic approximations based on metric naming conventions and should not be relied upon for safety-critical decisions.

### Tech Stack

- **Runtime:** Node.js 22
- **SDK:** `apify` v3
- **Parsing:** bounded XLSX ZIP/XML extraction with `fflate`
- **HTTP:** Node.js built-in `fetch`
- **Testing:** `node:test` (built-in, zero additional dependencies)
- **Container:** `node:22-slim` (no browser or Playwright)

### Source and reuse

The Actor transforms weekly public data published by the U.S. Surface Transportation Board. It preserves the official archive and workbook URLs on every record. It does not use an STB seal or imply government endorsement.

# Actor input Schema

## `railroads` (type: `array`):

Filter by specific Class I railroads. Leave empty to include all.

## `measureContains` (type: `string`):

Case-insensitive substring filter on the Measure column. Leave empty for all measures.

## `minAbsoluteChange` (type: `number`):

Minimum absolute delta to include. Set 0 to disable this threshold.

## `minPercentChange` (type: `number`):

Minimum absolute percent change to include. Set 0 to disable this threshold. A value of 5 excludes changes less than 5%.

## `interpretations` (type: `array`):

Which directional interpretations to include. Leave empty to include all.

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

Maximum number of change records to output (1–2000).

## Actor input object example

```json
{
  "railroads": [],
  "measureContains": "",
  "minAbsoluteChange": 0,
  "minPercentChange": 0,
  "interpretations": [],
  "maxResults": 200
}
```

# Actor output Schema

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

No description

## `summary` (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 = {
    "railroads": [],
    "measureContains": "",
    "minAbsoluteChange": 0,
    "minPercentChange": 0,
    "interpretations": [],
    "maxResults": 200
};

// Run the Actor and wait for it to finish
const run = await client.actor("aether_studio/stb-rail-service-change-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 = {
    "railroads": [],
    "measureContains": "",
    "minAbsoluteChange": 0,
    "minPercentChange": 0,
    "interpretations": [],
    "maxResults": 200,
}

# Run the Actor and wait for it to finish
run = client.actor("aether_studio/stb-rail-service-change-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "railroads": [],
  "measureContains": "",
  "minAbsoluteChange": 0,
  "minPercentChange": 0,
  "interpretations": [],
  "maxResults": 200
}' |
apify call aether_studio/stb-rail-service-change-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=aether_studio/stb-rail-service-change-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "STB Weekly Freight Rail Service Change Monitor",
        "description": "Tracks week-over-week changes in Class I railroad service performance metrics from the Surface Transportation Board's official consolidated workbook. Detects improvements and warnings across train speed, dwell time, cars held, trains held, and past-due orders.",
        "version": "0.1",
        "x-build-id": "2ksEA4ytrufeLBlr6"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/aether_studio~stb-rail-service-change-monitor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-aether_studio-stb-rail-service-change-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/aether_studio~stb-rail-service-change-monitor/runs": {
            "post": {
                "operationId": "runs-sync-aether_studio-stb-rail-service-change-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/aether_studio~stb-rail-service-change-monitor/run-sync": {
            "post": {
                "operationId": "run-sync-aether_studio-stb-rail-service-change-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "railroads": {
                        "title": "Railroads",
                        "type": "array",
                        "description": "Filter by specific Class I railroads. Leave empty to include all.",
                        "items": {
                            "type": "string",
                            "minLength": 1
                        },
                        "default": []
                    },
                    "measureContains": {
                        "title": "Measure Contains",
                        "type": "string",
                        "description": "Case-insensitive substring filter on the Measure column. Leave empty for all measures.",
                        "default": ""
                    },
                    "minAbsoluteChange": {
                        "title": "Min Absolute Change",
                        "minimum": 0,
                        "type": "number",
                        "description": "Minimum absolute delta to include. Set 0 to disable this threshold.",
                        "default": 0
                    },
                    "minPercentChange": {
                        "title": "Min Percent Change",
                        "minimum": 0,
                        "type": "number",
                        "description": "Minimum absolute percent change to include. Set 0 to disable this threshold. A value of 5 excludes changes less than 5%.",
                        "default": 0
                    },
                    "interpretations": {
                        "title": "Interpretations",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Which directional interpretations to include. Leave empty to include all.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "improvement",
                                "warning",
                                "neutral"
                            ],
                            "enumTitles": [
                                "Improvement",
                                "Warning",
                                "Neutral"
                            ]
                        },
                        "default": []
                    },
                    "maxResults": {
                        "title": "Max Results",
                        "minimum": 1,
                        "maximum": 2000,
                        "type": "integer",
                        "description": "Maximum number of change records to output (1–2000).",
                        "default": 200
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
