# FMCSA Carrier Scraper (`normdata/fmcsa-carrier-scraper`) Actor

Search 2M+ US trucking carriers from FMCSA / DOT open data by state, cargo or fleet size: contact, officers, fleet, CSA safety scores, authority + insurance history (revocations, lapses, coverage), crashes and inspections. Lead lists, a change monitor, or full safety profiles. No API key.

- **URL**: https://apify.com/normdata/fmcsa-carrier-scraper.md
- **Developed by:** [Norm Data](https://apify.com/normdata) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.35 / 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.
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?

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

![Norm Data](https://i.ibb.co/rGbhM5Y8/Chat-GPT-Image-Sep-8-2026-02-20-50-PM.png)

## 🚚 FMCSA Carrier Scraper

Search **US trucking carriers and brokers** from the official **FMCSA / DOT open data** with no
API key. Filter 2M+ carriers by state, cargo, fleet size, operation class, safety rating and
registration date for a clean B2B lead list, then enrich every row with **CSA / SMS BASIC safety
scores, the full authority and insurance history** (grants, revocations, reinstatements, coverage
amounts, lapses), crashes, roadside inspections and out-of-service orders. Run a
**lifecycle-change monitor** for daily alerts, or pull a complete **safety profile** for a list
of carriers.

Here is one real row (trimmed), for an established carrier with safety + history on:

```json
{
  "dot_number": "370617",
  "mc_numbers": ["MC386188"],
  "legal_name": "JFC INTERNATIONAL INC",
  "entity_type": "carrier",
  "status": "active",
  "operation_class": "Interstate",
  "hazmat": false,
  "registration_date": "1998-06-11",
  "phone": "3105551234",
  "email": "dispatch@example.com",
  "officer_1": "...",
  "physical_address": "...  LOS ANGELES, CA, 90001",
  "physical_state": "CA",
  "power_units": 210,
  "drivers_total": 190,
  "cargo_carried": ["General Freight", "Refrigerated Food"],
  "safety_rating": "C",
  "safety_rating_label": "Conditional",
  "prior_authority_revocation": false,
  "out_of_service": false,
  "safety_scores": {
    "inspections_total": 506,
    "driver_oos_rate": 0.041,
    "vehicle_oos_rate": 0.19,
    "any_basic_alert": false,
    "basics": {
      "vehicle_maintenance": { "measure": 3.21, "alert": false },
      "hours_of_service": { "measure": 1.08, "alert": false }
    }
  },
  "authority_granted": true,
  "authority_revoked": false,
  "authority_types": ["MOTOR PROPERTY COMMON CARRIER", "MOTOR PROPERTY CONTRACT CARRIER"],
  "last_authority_action": "REINSTATED",
  "last_authority_action_date": "2019-04-02",
  "insurance_on_file": true,
  "current_insurer": "TOKIO MARINE AMERICA INSURANCE COMPANY",
  "liability_coverage_thousands": 750,
  "last_cancellation_date": "2023-06-30",
  "crashes_total": 122,
  "crashes_24mo": 8,
  "inspections_24mo": 514,
  "oos_rate_24mo": 0.093,
  "safer_url": "https://safer.fmcsa.dot.gov/query.asp?searchtype=ANY&query_type=queryCarrierSnapshot&query_param=USDOT&query_string=370617",
  "scraped_at": "2026-09-10T14:09:24.000Z"
}
```

### What it does

Reads the FMCSA datasets published on `data.transportation.gov` (Socrata, keyless, updated
daily): the carrier census, the SMS BASIC safety measures, authority and insurance history, the
crash and inspection files, and out-of-service orders. It joins them by USDOT and MC docket
number. Four modes:

- **Search** - filter the census for a lead list, then batch-enrich every match.
- **Look up** - resolve exact USDOT numbers, MC/MX docket numbers or company names. One row per
  identifier; ids that do not resolve come back as an `error` row.
- **Monitor** - carriers with a **new registration, authority revocation, reinstatement,
  insurance lapse or out-of-service order** since a date, each tagged with the change type.
- **Safety** - the full safety profile (CSA BASIC scores, authority + insurance history,
  24-month inspection and crash detail) for the carriers you name.

### Why this scraper

- **CSA / SMS BASIC safety scores.** The seven Behavior Analysis categories with their raw
  measures and above-threshold alert flags, plus driver and vehicle out-of-service rates. No
  other FMCSA Actor on Apify parses these - they stop at the census snapshot.
- **Authority lifecycle, not just current status.** Every grant, involuntary revocation and
  reinstatement with dates - so you can see a carrier that has been revoked three times, or one
  reinstated last week.
- **Insurance history with coverage and lapses.** Current insurer and liability limit, plus
  every past filing with its cancellation date - the signal an underwriter or a factoring
  company actually acts on.
- **Crash and inspection detail.** 24-month crash counts (fatal / injury / tow) and inspection
  out-of-service rates, computed from the crash and inspection files, not just a headline number.
- **A real change monitor.** Not "USDOT numbers not seen before" - an actual lifecycle feed:
  revocations, lapses and out-of-service orders are the events worth a phone call.
- **Fast.** Every source is a keyless JSON API and every enrichment is one batched query per
  dataset (`dot_number IN (...)`), not one request per carrier. A 2,000-carrier run with CSA
  scores, authority and insurance history takes about **2 seconds**; the census pagination is
  the only real cost.
- **No API key.** The DOT open data is free; a Socrata app token is optional and only for very
  large runs.

### How it compares

| Capability | This actor | Other FMCSA scrapers on Apify |
|---|:--:|:--:|
| Census: identity, contact, officers, fleet, cargo | yes | yes |
| Filter by state / cargo / fleet size / registration date | yes | some |
| **CSA / SMS BASIC safety scores + alert flags** | **yes** | **no** |
| **Authority history (grants / revocations / reinstatements)** | **yes** | **current status only** |
| **Insurance history (insurer, coverage, lapses)** | **yes** | **current only, if any** |
| 24-month crash + inspection out-of-service detail | yes | counts only |
| Lifecycle-change monitor (revocations, lapses, OOS) | yes | new-carrier delta only |
| One row per look-up input, error rows for bad ids | yes | rare |
| Declared dataset schema + free-plan preview | yes | rare |

### Use cases

- **Freight-broker prospecting.** New interstate carriers in your lanes, with phone, email and
  officer names, the day their authority is granted.
- **Insurance underwriting.** Pull a carrier's CSA BASIC alerts, out-of-service rate, crash
  history and every past insurance cancellation before you quote.
- **Factoring / risk.** Monitor mode on `insurance_lapse` and `revocation` - a lapse is a
  carrier to call, a revocation is one to stop funding.
- **Equipment / ELD / fuel-card sales.** Filter by fleet size and cargo type, keep the officers
  and contact.
- **Compliance benchmarking.** Rank a set of carriers on OOS rate and BASIC scores.

### Quickstart

Search - new interstate reefer carriers in Texas, 5-50 trucks:

```json
{
  "mode": "search",
  "state": ["TX"],
  "operationClass": "interstate",
  "cargo": ["coldfood"],
  "minPowerUnits": 5,
  "maxPowerUnits": 50,
  "registeredAfter": "2026-06-01",
  "includeSafety": true,
  "maxItems": 500
}
```

Look up a batch:

```json
{ "mode": "lookup", "identifiers": ["76830", "MC386188", "SWIFT TRANSPORTATION"], "includeHistory": true }
```

Monitor lifecycle changes in the last week:

```json
{ "mode": "monitor", "since": "7 days", "events": ["revocation", "insurance_lapse", "oos_order"], "maxItems": 1000 }
```

Full safety profile:

```json
{ "mode": "safety", "identifiers": ["370617", "593107"] }
```

### Input reference

| Field | Applies to | Description |
|---|---|---|
| `maxItems` | all | Ceiling on rows written. |
| `mode` | all | `search`, `lookup`, `monitor` or `safety`. |
| `state` | search, monitor | Two-letter physical state code(s). |
| `operationClass` | search, monitor | `interstate`, `intrastate`, `intrastate_hazmat`. |
| `cargo` | search, monitor | Commodity types (`genfreight`, `coldfood`, `chem`, ...). |
| `hazmatOnly` | search, monitor | Only hazmat-flagged carriers. |
| `safetyRating` | search | `S`, `C` or `U`. |
| `minPowerUnits` / `maxPowerUnits` | search | Fleet-size range. |
| `registeredAfter` / `registeredBefore` | search | Registration-date window (ISO). |
| `keyword` | search | Legal or DBA name contains. |
| `activeOnly` | search, monitor | Exclude de-registered carriers (default on). |
| `identifiers` | lookup, safety | USDOT numbers, MC/MX numbers, or company names. |
| `since` | monitor | ISO date or `"7 days"` / `"2 weeks"`. |
| `events` | monitor | `new_registration`, `revocation`, `reinstatement`, `insurance_lapse`, `oos_order`. |
| `includeSafety` | search, lookup | CSA BASIC scores + inspection/crash summary. Default on. |
| `includeHistory` | search, lookup | Authority + insurance history. Billed separately. |
| `includeInspections` | search, lookup | Per-inspection + per-crash detail. Billed separately. |
| `socrataAppToken` | all | Optional free token for large runs. |

### Output reference (selected)

| Field | Description |
|---|---|
| `dot_number` / `mc_numbers` / `legal_name` / `dba_name` | Identity. |
| `status` / `entity_type` / `operation_class` / `business_type` / `hazmat` | Classification. |
| `registration_date` / `mcs150_date` | Dates. |
| `phone` / `cell_phone` / `email` / `officer_1` / `officer_2` | Contact. |
| `physical_address` / `mailing_address` / `address_undeliverable` | Addresses. |
| `power_units` / `truck_units` / `drivers_total` / `drivers_cdl` / `cargo_carried` | Fleet and cargo. |
| `safety_rating` / `safety_rating_label` / `recordable_crash_rate` / `prior_authority_revocation` | Headline safety. |
| `out_of_service` / `out_of_service_date` / `out_of_service_reason` | Current OOS order. |
| `safety_scores` | CSA BASIC measures + alerts + OOS rates (with `includeSafety`). |
| `authority_granted` / `authority_revoked` / `authority_types` / `last_authority_action` / `authority_history` | Authority lifecycle (with `includeHistory`). |
| `insurance_on_file` / `current_insurer` / `liability_coverage_thousands` / `last_cancellation_date` / `insurance_history` | Insurance (with `includeHistory`). |
| `crashes_24mo` / `fatal_crashes_24mo` / `inspections_24mo` / `oos_rate_24mo` | 24-month safety detail. |
| `change_type` | Monitor mode: `new_registration`, `revocation`, `insurance_lapse`, `oos_order`. |
| `query` / `error` | Set on an unresolved look-up id row. |
| `safer_url` | The carrier's SAFER company snapshot page. |
| `scraped_at` | ISO 8601 collection timestamp. |

### Run via API and CLI

```bash
curl -X POST "https://api.apify.com/v2/acts/USERNAME~fmcsa-carrier-scraper/run-sync-get-dataset-items?token=<TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"mode":"lookup","identifiers":["76830"],"includeHistory":true}'
```

```bash
apify call USERNAME/fmcsa-carrier-scraper --input '{"mode":"monitor","since":"7 days","events":["revocation"]}'
```

### Fetch results

```bash
curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?token=<TOKEN>&clean=true&format=csv"
```

### Billing and limits

- **Pay per result.** Billed per carrier row written. `includeSafety`, `includeHistory` and
  `includeInspections` each add a separate event, charged only when that enrichment produced data.
- **No charge on failure.** A run that produces zero rows fails with a message and is not billed.
- An unresolved look-up id still writes one `error: "not found"` row and is billed as a base row.
- **Free Apify plans** run the built-in 10-row sample only.
- The DOT open-data API caps a single query at 50,000 rows; this Actor pages the census in
  2,000-row chunks and batches enrichment lookups, so throughput is roughly **1,000 fully
  enriched carriers per second** - the census pagination is the bottleneck, not the enrichment.
- Very large runs can supply a free `data.transportation.gov` app token to raise the shared
  rate limit.

### FAQ

**Do I need an API key?** No. `data.transportation.gov` is a keyless open-data host. A Socrata
app token is optional and only helps on very large runs.

**Why is a carrier's `safety_rating` blank?** Most carriers have never had a compliance review,
so they carry no rating. That is normal, not missing data.

**What does `authority_revoked: true` mean?** There is an involuntary revocation on record with
no matching reinstatement. Carriers are routinely revoked for a lapsed insurance filing and
reinstated within days - those show `authority_revoked: false` with the cycle in
`authority_history`.

**How fresh is the data?** The census and most datasets update daily from a database that is
about 24 hours behind live. It is not real-time.

**Is this an official FMCSA tool?** No. Independent, not affiliated with FMCSA or the US DOT. It
reads only data they publish as open data.

### Local development

```bash
bun install
bun test              # offline: normalisation + input logic
bun run src/main.ts   # reads storage/key_value_stores/default/INPUT.json
bun scripts/verify-live.mjs   # hits data.transportation.gov directly, checks every mode
```

# Actor input Schema

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

Caps how many carrier rows this run writes. Starts at 10 for a quick sample; raise it for a full run.

## `mode` (type: `string`):

Search filters the census for lead lists. Look up resolves exact DOT/MC numbers or names. Monitor returns carriers with a new registration, revocation, insurance lapse or out-of-service order since a date. Safety pulls the full safety profile for the carriers you name.

## `state` (type: `array`):

Two-letter physical state code(s), e.g. TX, CA. Leave empty for all states.

## `operationClass` (type: `string`):

Restrict by operation class.

## `cargo` (type: `array`):

Only carriers that haul one of these commodity types.

## `hazmatOnly` (type: `boolean`):

Only carriers flagged to transport hazardous materials.

## `safetyRating` (type: `string`):

Restrict to carriers with this FMCSA safety rating (many carriers are unrated).

## `minPowerUnits` (type: `integer`):

Only carriers with at least this many trucks/tractors.

## `maxPowerUnits` (type: `integer`):

Only carriers with at most this many power units (e.g. 5 for owner-operators).

## `registeredAfter` (type: `string`):

ISO date (2026-01-01). Only carriers whose FMCSA registration date is on or after this - a new-authority lead filter.

## `registeredBefore` (type: `string`):

ISO date. Only carriers registered on or before this.

## `keyword` (type: `string`):

Match carriers whose legal name or DBA name contains this text.

## `activeOnly` (type: `boolean`):

Exclude inactive / de-registered carriers.

## `identifiers` (type: `array`):

US DOT numbers (e.g. 76830), MC/MX docket numbers (e.g. MC386188 or 386188), or company names. Names may match several carriers.

## `since` (type: `string`):

ISO date (2026-09-01) or a window ("7 days", "2 weeks", "1 month"). Monitor returns carriers with a matching change on or after this.

## `events` (type: `array`):

Which lifecycle changes to include. Leave empty for new registrations + revocations + insurance lapses + out-of-service orders.

## `includeSafety` (type: `boolean`):

Add the CSA BASIC measures and alert flags plus an inspection and crash summary. Billed as a separate Safety record event, only when data is found.

## `includeHistory` (type: `boolean`):

Add the full authority lifecycle (grants, revocations, reinstatements) and every insurance filing (insurer, coverage, effective and cancellation dates). Billed as a separate History record event, only when data is found.

## `includeInspections` (type: `boolean`):

Add per-inspection violation and out-of-service counts and per-crash outcomes for the last 24 months. Billed as a separate Inspections record event, only when data is found.

## `socrataAppToken` (type: `string`):

A free data.transportation.gov app token raises the shared rate limit. Only needed for very large runs.

## Actor input object example

```json
{
  "maxItems": 10,
  "mode": "search",
  "state": [
    "TX"
  ],
  "operationClass": "",
  "hazmatOnly": false,
  "safetyRating": "",
  "activeOnly": true,
  "includeSafety": true,
  "includeHistory": false,
  "includeInspections": false
}
```

# Actor output Schema

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

One dataset row per carrier (or per look-up identifier), with identity, contact, fleet, cargo, safety rating, and - when enabled - CSA BASIC scores, authority and insurance history, crashes and inspections.

# 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 = {
    "maxItems": 10,
    "mode": "search",
    "state": [
        "TX"
    ],
    "activeOnly": true,
    "includeSafety": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("normdata/fmcsa-carrier-scraper").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 = {
    "maxItems": 10,
    "mode": "search",
    "state": ["TX"],
    "activeOnly": True,
    "includeSafety": True,
}

# Run the Actor and wait for it to finish
run = client.actor("normdata/fmcsa-carrier-scraper").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 '{
  "maxItems": 10,
  "mode": "search",
  "state": [
    "TX"
  ],
  "activeOnly": true,
  "includeSafety": true
}' |
apify call normdata/fmcsa-carrier-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,normdata/fmcsa-carrier-scraper"
        }
    }
}
```

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/cnaUtvAeAV8ofGeei/builds/ccu6hufrpWSlT2drz/openapi.json
