# Federal Infrastructure Milestone Monitor (`maydit/federal-infrastructure-milestone-monitor`) Actor

Track official federal infrastructure review milestones, published target dates and saved changes. Filter mining, power and industrial projects; no API key required.

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

## Pricing

from $3.00 / 1,000 public permitting milestone 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

![Keep permitting milestone dates in view — illustrative project review table](https://api.apify.com/v2/key-value-stores/nemaYfVcrTgloz8Wn/records/federal-infrastructure-milestone-monitor-c582eff4658a.png?signature=118kAYjObOVN1VZZBV0P0)

### Keep permitting milestone dates in view

Maintain a source-linked review list for mining, transmission and other infrastructure projects. Collect official review milestones, target dates, baseline dates and published completion dates from the federal Permitting Dashboard, then compare them with your last saved observations.

**One result is one milestone within a project action.** Use the data to maintain project research and flag published date revisions for review. Dashboard inclusion does not establish funding, permit approval or federal endorsement.

[Open in Console](https://console.apify.com/actors/eGiwi94kexUkxqu8j/input) · [First run](#try-five-mining-milestones) · [Output preview](#output-preview) · [Saved comparisons](#keep-a-saved-milestone-watchlist) · [Pricing](#pricing-and-run-outcomes)

### Try five mining milestones

Copy this input into Console's JSON editor. It requests up to five milestones for in-progress mining projects in the default FAST-41 Covered and Transparency categories. No API key, login or proxy subscription is required.

```json
{
  "sectors": [
    "Mining"
  ],
  "maxSourceEntries": 5,
  "maxResults": 5
}
```

Open **Saved observations** or **CSV export** for the rows, then **Run report** for coverage. Repeated project titles are expected because a project can have many milestones. Empty input saves up to five rows from a larger default source window of 100 milestones.

### Output preview

| Review question | Fields | Interpretation |
| --- | --- | --- |
| Which project and milestone? | `recordId`, `projectId`, `actionId`, `milestoneId`, `projectTitle`, `milestoneName` | Stable source identifiers; `recordId` preserves `unique_id` and matches `milestoneId` |
| Which organizations and action? | `leadAgency`, `sponsor`, `actionAgency`, `actionType`, `actionStatus` | Published organizations and review/authorization wording |
| What dates are published? | `targetDate`, `baselineTargetDate`, `actualCompletionDate`, `conditionalTargetDate` | Date-only values; unpublished dates stay null |
| How far from the agency baseline? | `baselineTargetShiftDays` | Current target minus the dashboard's baseline target |
| What changed since my saved check? | `targetDateChangeDays`, `changedFields`, `previous`, `previousObservedAt` | Current target minus your prior saved target; positive means later |
| What qualifications apply? | `complete`, `notApplicable`, `dateChangeReason` | Source flags and explanation when provided; unknown values stay null |
| Where is the evidence? | `projectUrl`, `sourceUrl`, `observedAt`, `contentHash` | Official project page, dataset source and observation metadata |

Rows also include `projectCategory`, `projectStatus`, `sector`, `state` and literal `matchedKeywords`. `sourceFetchedAt` is the source dataset's ingestion timestamp, preserved without an invented time zone. It is not the date a milestone changed. JSON preserves previous values; CSV supports a milestone register.

Without comparison, `comparisonStatus` is `not_requested`. A first saved comparison is `new`, followed by `changed` or `unchanged`. New means new to your saved snapshot, not newly announced by the government. Date revisions do not establish their cause, delay damages or future outcomes.

### Inspect transmission milestones

This example includes all project statuses while retaining the two default FAST-41 categories.

```json
{
  "sectors": [
    "Electricity Transmission"
  ],
  "projectStatuses": [],
  "maxSourceEntries": 5,
  "maxResults": 5
}
```

### Follow an exact project

```json
{
  "projectIds": [
    "116841"
  ],
  "sectors": [
    "Mining"
  ],
  "projectStatuses": [
    "In Progress"
  ],
  "maxSourceEntries": 5,
  "maxResults": 5
}
```

Project 116841 is Michigan Potash in the retained sample. A later category or status change can make this filtered watchlist empty. Missing observations do not establish cancellation or removal.

### Keep a saved milestone watchlist

1. Choose a project or focused sector filter. Add `comparePrevious: true` and a dedicated `snapshotName` to the input.
2. Run once to save initial `new` observations. Repeat with the same snapshot name to compare later values.
3. Keep `comparePrevious: true` and add `onlyChanges: true` to skip unchanged rows. This Actor requires both flags for changes-only output; an unchanged repeat can correctly save zero rows.
4. Read the completed run's SUMMARY, then upsert into your spreadsheet or CRM using `recordId`. Retain the run ID for delivery replay. Route positive `targetDateChangeDays` for review with the official project link.

History lives in `maydit-infrastructure-<snapshotName>`, separately per milestone. Only confirmed saved rows advance it; unsaved failures preserve prior values. Use **one writer per snapshot name**. Detected concurrent changes produce an explicit partial result; this check is not an atomic lock. Inspect `historyUpdated` and `failedSources` before relying on the baseline.

Ingestion and retrieval timestamps are excluded from the substantive comparison, so refreshes alone do not create milestone changes. No absence becomes cancellation, removal, permit denial or approval. Agency-maintained records can lag events. Configure daily or weekly recurrence to suit your review process; the Actor creates no schedule or downstream connection.

### Filters and source window

Sector, category, project status, project ID and state filters use exact official values. Empty lists include all values for that filter. Changing the sector leaves the default FAST-41 categories in place. Single-state filters match the exact source value, so multi-state or blank locations may not match.

Supported sector values include Mining, Electricity Transmission, Manufacturing, Energy Storage, Renewable Energy Production, Conventional Energy Production, Data Storage and Data Management, Pipelines, Broadband, Water Resources, Surface Transportation, Aviation, Ports and Waterways, Carbon Capture and Sequestration, and High-performance computing and advanced computer hardware and software.

Project statuses are In Progress, Planned, Paused, Complete, Cancelled and Class of Action Changed. Categories are FAST-41 Covered Projects, FAST-41 Transparency Projects, DOT Projects and Other Projects.

The Actor fetches at most `maxSourceEntries` milestones in stable project/action/milestone order, with pages of up to 100. Keywords then match literally without case sensitivity within that bounded window's project title, sponsor, action type and milestone name. Any keyword can match; filter groups use AND. `maxResults` caps confirmed writes. This is not a complete history or guaranteed set of all keyword matches in the dashboard.

Defaults are 100 source entries, five saved rows and 240 seconds. Bounds are 10,000 source entries, 5,000 saved rows and 30–3,600 seconds, with a separate 25-second platform reserve. Requests honor robots rules and published crawl delay, use bounded responses and remain on the official public data host.

### Official source and meaning

Source: [Permitting Dashboard full dataset](https://data.permits.performance.gov/Projects/Permitting-Dashboard-Full-Dataset/mcm3-xbid), using its public structured endpoint. See the [data dictionary](https://www.permits.performance.gov/documentation/permits-data-dictionary-full-dataset) and [project dashboard](https://www.permits.performance.gov/projects).

Each row describes a milestone within an environmental review or authorization action. The Actor returns metadata and dates, without private contacts or attachments. It is independent of the Permitting Council and supplies no legal conclusion, risk score, procurement opportunity or completion forecast.

### Pricing and run outcomes

Base result rate on the FREE tier: **$5 per 1,000 saved milestone observations**, plus the listed **Actor Start** charge. The [Pricing tab](https://apify.com/maydit/federal-infrastructure-milestone-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 an Apify maximum charge as well as your result cap.

SUMMARY and Run report show source-window coverage, saved counts, history commits, failed records/sources and stop flags. Intentional source/result caps can finish successfully. Source failures, malformed records, time limits and spending stops are incomplete. A valid no-match succeeds; an all-failed run fails. Errors never become paid data rows.

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

# Actor input Schema

## `sectors` (type: `array`):

Exact official sector names. Default Mining; examples include Electricity Transmission, Manufacturing, Energy Storage and Renewable Energy Production. Empty includes every sector.

## `categories` (type: `array`):

Exact source categories: FAST-41 Covered Projects, FAST-41 Transparency Projects, DOT Projects or Other Projects. Empty includes all four.

## `projectStatuses` (type: `array`):

Exact published status values: In Progress, Planned, Paused, Complete, Cancelled or Class of Action Changed. Empty includes all statuses.

## `projectIds` (type: `array`):

Optional numeric dashboard project IDs. Existing sector, category and status filters still apply.

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

Optional exact two-letter state values in the source. Multi-state or missing state entries do not match a single-state filter.

## `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 source milestones fetched before optional keyword filtering, ordered by project/action/milestone ID. A bounded window is not complete project history.

## `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
{
  "sectors": [
    "Mining"
  ],
  "categories": [
    "FAST-41 Covered Projects",
    "FAST-41 Transparency Projects"
  ],
  "projectStatuses": [
    "In Progress"
  ],
  "projectIds": [],
  "states": [],
  "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 = {
    "sectors": [
        "Mining"
    ],
    "categories": [
        "FAST-41 Covered Projects",
        "FAST-41 Transparency Projects"
    ],
    "projectStatuses": [
        "In Progress"
    ],
    "projectIds": [],
    "states": [],
    "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/federal-infrastructure-milestone-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 = {
    "sectors": ["Mining"],
    "categories": [
        "FAST-41 Covered Projects",
        "FAST-41 Transparency Projects",
    ],
    "projectStatuses": ["In Progress"],
    "projectIds": [],
    "states": [],
    "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/federal-infrastructure-milestone-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 '{
  "sectors": [
    "Mining"
  ],
  "categories": [
    "FAST-41 Covered Projects",
    "FAST-41 Transparency Projects"
  ],
  "projectStatuses": [
    "In Progress"
  ],
  "projectIds": [],
  "states": [],
  "keywords": [],
  "maxResults": 5,
  "comparePrevious": false,
  "onlyChanges": false,
  "snapshotName": "default",
  "maxSourceEntries": 100,
  "maxRunSeconds": 240
}' |
apify call maydit/federal-infrastructure-milestone-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,maydit/federal-infrastructure-milestone-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/eGiwi94kexUkxqu8j/builds/ls3g60cnixLgo2zCY/openapi.json
