# FMCSA New Carriers Scraper - Trucking Companies, USDOT Lookup (`neverempty/fmcsa-new-carriers-monitor`) Actor

For trucking sales leads and carrier research: new trucking companies from the FMCSA Company Census File API, with USDOT number, legal name, state, power units, drivers, registration date, phone and email. About 15,000 register in 30 days (2026-10-05). Monitoring returns only new carriers.

- **URL**: https://apify.com/neverempty/fmcsa-new-carriers-monitor.md
- **Developed by:** [NeverEmpty](https://apify.com/neverempty) (community)
- **Categories:** Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 carrier returneds

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

## FMCSA New Carriers Scraper - Trucking Companies, USDOT Lookup

Newly registered US trucking companies and other motor carriers from the **FMCSA Company Census File**, one row per carrier: USDOT number, legal and DBA name, registration date, state and address, power units, drivers, carrier operation, classifications, cargo, MC/docket numbers, and the phone, email and company officers the carrier filed.

- **Search** by state, registration date, power units, carrier operation, classification and USDOT status. Newest registrations first.
- **Monitoring mode** returns only the carriers that were not there at the last run. A run that finds nothing new sends one light request and is charged one check instead of rows.
- **USDOT lookup**: give USDOT numbers and get those carriers.
- No login, no API key, no proxy. The Actor reads the public open-data API of the U.S. Department of Transportation (data.transportation.gov), one request at a time and at most one per second.

This Actor is an independent tool. It is not affiliated with or endorsed by FMCSA or the U.S. Department of Transportation.

### How fresh the data is

The Company Census File is published by FMCSA on the DOT open-data portal with a stated update frequency of **daily**. Measured on 2026-10-05: the file had last been updated on 2026-10-04 at 10:19 UTC, and the newest registration date in it was 2026-10-03.

Registrations for a given date keep arriving for a few days. In that same reading, 2026-10-03 held 7 carriers and 2026-10-02 held 405, while ordinary weekdays in the weeks before held 450 to 790. So:

- a search for "registered yesterday" returns only part of that day; ask for the last few days instead;
- monitoring mode does not use a date watermark. It compares USDOT numbers over the last 30 days of registration dates, so a carrier that shows up late under an older date is still returned as new;
- running more often than once a day mostly returns "nothing new".

Every row carries `registryUpdatedAt`, the time the portal says the file was last changed.

### What you get

| Column | Meaning |
|---|---|
| `usdotNumber` | The carrier's USDOT number |
| `legalName`, `dbaName` | Legal name and "doing business as" name |
| `registeredDate` | The date the USDOT record was added (`YYYY-MM-DD`) |
| `usdotStatus`, `usdotStatusCode` | `Active`, `Inactive` or `Pending`, and the code in the file (`A`, `I`, `P`) |
| `carrierOperation`, `carrierOperationCode` | `Interstate`, `Intrastate Hazmat` or `Intrastate Non-Hazmat`, and the code in the file (`A`, `B`, `C`) |
| `classifications` | The carrier's operation classifications as written in the file, for example `AUTHORIZED FOR HIRE`, `PRIVATE PROPERTY`. A carrier can hold several |
| `businessType` | Form of business when the file gives it |
| `powerUnits`, `truckUnits`, `busUnits` | Vehicle counts the carrier reported |
| `totalDrivers`, `cdlDrivers` | Driver counts the carrier reported |
| `fleetSizeCode` | The file's fleet size band, as a letter. It is not translated |
| `hazmat` | `true` / `false` from the file's hazardous-materials flag |
| `cargo`, `cargoOtherDescription` | Cargo types the carrier ticked on its registration form, and its own wording for "Other" |
| `docketNumbers` | MC / MX / FF docket numbers in the census record, each with the status code the file gives. Many new carriers have none |
| `physicalAddress`, `mailingAddress` | `street`, `city`, `state`, `zip`, `country` |
| `phone`, `cellPhone`, `fax`, `email` | As filed by the carrier. Empty when `includeContacts` is off |
| `companyOfficers` | Up to two names filed as company officers. Empty when `includeContacts` is off |
| `mcs150Date`, `mcs150Mileage`, `mcs150MileageYear` | Date of the latest MCS-150 filing and the mileage reported on it. A mileage of 0 in the file means "not reported" and is returned as `null` |
| `safetyRating`, `safetyRatingCode`, `safetyRatingDate` | `Satisfactory`, `Conditional` or `Unsatisfactory` when the carrier has been rated. Most carriers, and nearly all new ones, have no rating |
| `saferUrl` | The address of the carrier's Company Snapshot on FMCSA's SAFER site |
| `searchedWhere` | Search runs: the exact query condition that was sent, so you can see what was searched |
| `registryUpdatedAt`, `scrapedAt` | When the file was last changed according to the portal; when the row was read |
| `change`, `previousCheckedAt` | Monitoring runs: `new-carrier`, and when this search was last compared |
| `status` | `ok` for a carrier row |

A value the file does not hold is `null`, never 0 or an empty string.

**About the numbers.** Power units, drivers and mileage are what each carrier wrote on its form. FMCSA does not correct them, and a few records hold implausible values (for example hundreds of thousands of power units for a one-truck company). Filter and sort with that in mind.

**About the codes.** The names for the status, operation and safety-rating codes follow FMCSA's published definitions for this file. The raw code is always in the row next to the name. A code this Actor does not know is returned as the raw code with the name left `null`.

**About contact details.** Phone numbers, email addresses and officer names come from a public federal registration record. Many new carriers are one-person businesses, so these can be personal contact details. You are responsible for using them in line with the laws that apply to you (for example the U.S. TCPA and CAN-SPAM rules, and state telemarketing laws). Turn `includeContacts` off if you do not need them.

### Input

- **`states`** - two-letter codes of the physical-address state (`TX`, `CA`). Empty means every state.
- **`registeredInLastDays`**, **`registeredFrom`**, **`registeredTo`** - registration date range. Not used in monitoring mode.
- **`minPowerUnits`**, **`maxPowerUnits`** - range of reported power units. Carriers with no number are left out when either is set.
- **`carrierOperations`** - `interstate`, `intrastate-hazmat`, `intrastate-non-hazmat`.
- **`classifications`** - any of `authorized-for-hire`, `exempt-for-hire`, `private-property`, `private-passenger-business`, `private-passenger-non-business`, `migrant`, `federal-government`, `state-government`, `local-government`. A carrier matches when it holds at least one.
- **`statuses`** - `active`, `inactive`, `pending`.
- **`maxCarriers`** - with monitoring off, at most this many rows, newest registration first (default 200, at most 20,000).
- **`dotNumbers`** - look up these USDOT numbers instead of searching (up to 5,000).
- **`includeContacts`** - phone, email and officer names on or off (default on).
- **`monitoringMode`**, **`resetMonitoringState`** - see below.

All filters that are set must match. No filter has a hidden default: an empty filter is not applied. The filters are sent to the portal as the query, so carriers that do not match are never read and never charged.

The search queries this Actor sends were checked against the portal on 2026-10-05: all 2,223 carriers registered from 2026-09-26 to 2026-10-01 were downloaded without filters, the expected matches were counted locally for nine filter combinations, and each query returned exactly that set of USDOT numbers (`test/live-query-check.mjs` repeats the check).

### Monitoring mode

Turn **monitoringMode** on and schedule the Actor (daily is enough) with the same input.

- The **first run** with a set of filters only remembers the matching carriers registered in the last 30 days. Nothing is returned and nothing is charged (a free `baseline-saved` row). To get the carriers that are listed now, run once with monitoring off.
- Each **later run** sends one light request for the USDOT numbers of matching carriers registered in the last 30 days and compares them with what it remembers.
  - Nothing new: one free `no-new-carriers` row, and one `search-checked` charge.
  - Something new: the full records of the new carriers only are fetched and returned with `change: "new-carrier"`. No `search-checked` is charged on such a run.
- "New" means new to your search: a USDOT number that matches the filters now and was not among the remembered ones. A carrier registered within the last 30 days that did not match before and matches now (for example after it updated its power units) is returned once.
- `maxCarriers` and the date inputs are not applied.
- A carrier that could not be delivered because of a charge limit, or because the portal could not be read, is not remembered and still counts as new at the next run - as long as its registration date is within the last 30 days. If the portal cannot be read at all, nothing is charged and nothing is remembered.
- If a search matches 50,000 or more carriers in 30 days, the run stops with a free `search-too-broad` row. The whole country without filters is about 15,000 in 30 days (measured 2026-10-05), so this is not expected.

Carriers are remembered per set of filters, so schedules with different filters do not affect each other. Do not run two schedules with the same filters at the same moment: both would return the same new carriers.

### What is charged

- **`carrier-returned`** - one per carrier row.
- **`search-checked`** - monitoring mode only: one per run that compared the registry with the remembered carriers and found no new carrier. The first run (which only remembers) is not charged, and a run that returns new carriers does not charge it.

Rows that explain something (`baseline-saved`, `no-new-carriers`, `no-carriers`, `usdot-not-found`, `limit-reached`, `budget-reached`, `not-read`, `search-too-broad`, `invalid-input`, `source-unreadable`, `source-blocked`) are never charged; each ends with "This row is not charged." There is no start fee.

If you set a maximum total charge for a run, the Actor delivers the rows that fit and says in a `budget-reached` row how many did not.

### When a run returns no carrier

A run always says why:

| `status` | Meaning |
|---|---|
| `no-carriers` | The registry answered and holds no carrier for the search. The row repeats the query that was sent |
| `no-new-carriers` | Monitoring: the registry was read and nothing is new since the last run |
| `baseline-saved` | Monitoring: first run with these filters; the current carriers were remembered |
| `usdot-not-found` | Lookup: the listed USDOT numbers are not in the file |
| `source-unreadable`, `source-blocked` | The portal did not answer, answered with an error, or refused the request (HTTP 403 / 429). Nothing was charged for what could not be read. A failed request is retried once after a pause when the portal did not answer or returned a 5xx error; a 403 or 429 is not retried |
| `invalid-input` | An input value could not be read (for example a state not written as two letters). Nothing was read |
| `not-read` | The maximum total charge leaves no room for one carrier row |

### Limits

- The Actor reads one dataset: the Company Census File. It does not read operating-authority history, insurance filings, inspections or crashes.
- The census record's docket numbers are returned as they are; authority status changes are not tracked.
- The portal allows anonymous access with shared rate limits. The Actor does not use an app token. If the portal answers 429, the run stops reading and says so.
- The state filter uses the physical address. The mailing address can be in another state.
- Monitoring looks back 30 days by registration date. A record that appears in the file more than 30 days after its registration date is not returned by monitoring.

### Thanks for using this Actor

We build these tools for people who run them every day, and we improve them from what users tell us.

- **Missing a field, or need another filter?** Tell us in the **Issues** tab. If the data is there, we add it.
- **Found a bug or a wrong value?** Post the run ID in the **Issues** tab. Wrong data is the thing we fix first.

If this Actor saved you time, a short review helps other people find it.

# Actor input Schema

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

Two-letter codes of the state of the carrier physical address (TX, CA, FL ...). Canadian provinces and Mexican states in the file use their own two-letter codes. Leave empty for every state. One per line.

## `registeredInLastDays` (type: `integer`):

Keep carriers whose registration date (the date the USDOT record was added) is within this many days before today (UTC). The file is refreshed about once a day and the newest one or two dates are still filling in, so 1 returns few carriers. Leave empty for no lower date. Not used in monitoring mode.

## `registeredFrom` (type: `string`):

Keep carriers registered on or after this date (YYYY-MM-DD). If "Registered in the last N days" is also set, the later of the two dates is used. Not used in monitoring mode.

## `registeredTo` (type: `string`):

Keep carriers registered on or before this date (YYYY-MM-DD). Not used in monitoring mode.

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

Keep carriers that report at least this many power units (trucks, tractors, buses and other powered vehicles). The number is what the carrier wrote on its registration form; a few records hold implausible values. Carriers with no number are left out when this is set.

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

Keep carriers that report at most this many power units. Carriers with no number are left out when this is set.

## `carrierOperations` (type: `array`):

Keep carriers with one of these operation codes. Leave empty for all, including records with no code.

## `classifications` (type: `array`):

Keep carriers whose classification list contains at least one of these. A carrier can hold several classifications; the row lists all of them. Leave empty for all.

## `statuses` (type: `array`):

Keep carriers with one of these USDOT status codes. Leave empty for all. Nearly every newly registered carrier is active.

## `maxCarriers` (type: `integer`):

With monitoring off, at most this many carrier rows are returned, newest registration first. The registry is read 1,000 carriers per request, one request at a time, at most one per second. Not applied in monitoring mode (every new carrier is returned) or to a USDOT lookup.

## `dotNumbers` (type: `array`):

Look up these USDOT numbers instead of searching (digits; "USDOT 1234567" is also read). One row per number found; numbers that are not in the file are listed in one row that is not charged. The search filters are not used for a lookup. Up to 5,000 numbers per run. Cannot be combined with monitoring mode.

## `includeContacts` (type: `boolean`):

On: the phone, cellPhone, fax, email and companyOfficers columns hold what the carrier filed with FMCSA. Off: those columns are empty. Addresses are always included.

## `monitoringMode` (type: `boolean`):

Remembers carriers between runs, per set of filters. The first run with a set of filters only remembers the matching carriers registered in the last 30 days: nothing is returned and nothing is charged. Each later run reads the USDOT numbers of matching carriers registered in the last 30 days in one light request, compares them with what it remembers and returns only the carriers that were not there before (carrier-returned). A run that finds no new carrier is charged one check (search-checked) instead. Carriers are compared by USDOT number, not by date, because registrations for a given date keep arriving for a few days. The file is refreshed about once a day, so a daily schedule is enough. The date inputs are not used. Do not run two schedules with the same filters at the same moment.

## `resetMonitoringState` (type: `boolean`):

With monitoring on, clears what is remembered for this set of filters before the run, so the run is a first run again: matching carriers are remembered and nothing is returned. Use it for one run and turn it off again.

## Actor input object example

```json
{
  "states": [
    "TX"
  ],
  "registeredInLastDays": 30,
  "maxCarriers": 200,
  "includeContacts": true,
  "monitoringMode": false,
  "resetMonitoringState": false
}
```

# Actor output Schema

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

One row per motor carrier from the FMCSA Company Census File: USDOT number, legal and DBA name, registration date, USDOT status, carrier operation, classifications, power units, drivers, cargo, docket (MC) numbers, physical and mailing address, phone, email, company officers and safety rating. Runs that could not read the registry, found no carrier or no new carrier, or hit a limit return a row that says so and is not charged.

# 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": [
        "TX"
    ],
    "registeredInLastDays": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/fmcsa-new-carriers-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": ["TX"],
    "registeredInLastDays": 30,
}

# Run the Actor and wait for it to finish
run = client.actor("neverempty/fmcsa-new-carriers-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": [
    "TX"
  ],
  "registeredInLastDays": 30
}' |
apify call neverempty/fmcsa-new-carriers-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,neverempty/fmcsa-new-carriers-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/4fkzqK2mscu3AJ02v/builds/hqJYKgIIh7bK25Ov4/openapi.json
