# CA Labor Commissioner Judgments, Wage Claims, Port Drayage List (`overlookdata/ca-dlse-judgments`) Actor

California Labor Commissioner enforcement data with the dollar amounts: every judgment with its total owed, status, court and NAICS, the LC 2810.4 port drayage unsatisfied-judgment list with its history, the wage-claim index, and free debarment feeds from WA, NJ, CO, IL and OR.

- **URL**: https://apify.com/overlookdata/ca-dlse-judgments.md
- **Developed by:** [Aaron Melton](https://apify.com/overlookdata) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.03 / 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/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

## CA Labor Commissioner Judgments, Wage Claims and the Port Drayage List (plus five free multi-state wage-theft feeds)

**Who owes what.** Every California Labor Commissioner (DLSE) judgment with the
dollar amount attached: the total owed, whether it is still open, the court that
entered it, the DIR office that brought it, the industry, and the address of
every liable party named on it. Plus the Labor Code 2810.4 port drayage
unsatisfied-judgment list with its full month-by-month history, the DLSE
wage-claim index, and five free debarment and wage-theft feeds from Washington,
New Jersey, Colorado, Illinois and Oregon in the same shape.

California publishes this only through a Salesforce Lightning search portal, one
query at a time, with no export. This actor sweeps the whole corpus, verifies its
own coverage with a second independent pass, and hands you clean rows.

On the 2024 judgments alone the state names 1,939 liable parties across 1,874
judgments, and more than 99% carry a dollar amount above zero. The current port
drayage list is 54 liable parties across 52 judgments and 29 employers, totalling
$2,722,437.60 (as of 2026-08-26).

### Who this is for

Four groups have a statutory reason to check these lists, and to check them
again next month. Every citation below was read from the primary source on
2026-08-26. This is a description of public registries, not legal advice.

- **Anyone using a port drayage motor carrier.** California Labor Code 2810.4
  requires the Labor Commissioner to post the unsatisfied-judgment list and
  update it monthly by the fifth day of each month (subdivision (c)(5)). A
  customer that engages a carrier on that list "shall share with the motor
  carrier or the motor carrier's successor all civil legal responsibility and
  civil liability" owed to a port drayage driver or to the state (subdivision
  (c)(3)). Current version: Stats. 2024, ch. 739 (AB 2754), effective
  2025-01-01.
- **Anyone buying a Washington business.** RCW 49.48.086(4) makes a successor
  liable for an outstanding citation and notice of assessment when the buyer
  has "a prompt, reasonable, and effective means of accessing and verifying the
  fact and amount" of it. RCW 39.12.065(3) bars a contractor with an unpaid
  prevailing-wage penalty from bidding on public works until it is paid.
- **Anyone awarding public contracts in New Jersey or Illinois.** N.J.S.A.
  34:1A-1.16 prohibits any business on the WALL from public contracting with
  the State, its agencies, counties and local government bodies; the list is
  updated at least monthly. Illinois Prevailing Wage Act section 11a (820 ILCS
  130\) bars debarred contractors, their affiliated firms, directors, officers
  and agents from any public works contract or subcontract.
- **Compliance, credit and diligence teams generally.** Colorado publishes wage
  theft decisions with the wages ordered, the penalties and the individually
  named liable parties under its Wage Theft Transparency Act.

### What you get

One flat row per source record (default). A real judgment row:

```json
{
  "employer_name": "Brady Hoggins, an Individual",
  "address_street": "1220 Rosecrans Street #853 San Diego CA 92106",
  "naics_code": "238130",
  "naics_title": "Framing Contractors",
  "source": "judgments",
  "source_agency": "California Labor Commissioner (DLSE)",
  "source_state": "CA",
  "source_url": "https://cadir.my.site.com/s/judgmentsearchresult?searchtype=judgmentsearch",
  "record_id": "a2Acs000002Mj29EAC",
  "case_number": "J-93628",
  "status": "Open/Unpaid",
  "judgment_date": "2024-12-31",
  "amount_total": 251390.11,
  "amount_due_others": null,
  "ubi": null,
  "entity_key": "01c1de238e4a7941a043d95fae8704322f63037e",
  "scraped_at": "2026-08-26T21:00:00+00:00"
}
```

Every row carries the same fields, so rows from different states stack in one
table. Fields a source does not publish are `null`, never missing.

**One judgment can name several liable parties, and each one is its own row.**
Judgment J-93628 above is one of three rows sharing case number J-93628, one per
defendant: an individual and two corporations. That is the point of the dataset,
so a row is identified by the judgment plus the party, and the entity rollup
counts each judgment amount once.

`record_id` is that identity: the state's judgment id and the normalized
employer name, joined. **Do not key on `judgment_party_id`.** It is included for
reference only, and the state does not hold it stable: the same party on the
same judgment comes back under different party ids from different queries, and
even between two runs. Use `record_id`, or `case_number` plus `employer_name`.

#### Which datasets carry dollar amounts

| Dataset | Amounts | What the amount is |
|---|---|---|
| `judgments` | **Yes** | Judgment total, above zero on more than 99% of records |
| `portDrayage`, `portDrayageHistory` | **Yes** | Judgment total, plus the amount due to parties other than the worker |
| `njWall` | **Yes** | Total liability owed under the final judgment or order |
| `coWageTheft` | **Yes** | Wages ordered plus penalties and fines, summed |
| `caloshaPenalties` | **Yes** | Citation initial penalty |
| `wageClaims` | No | A volume and status index reaching back to 1997. DLSE publishes no amount on the claim search |
| `waDebar` | No | Status, RCW cited, and a `Yes`, `No` or `-` flag for penalty due and wages due. No dollar figures are published |
| `ilDebar` | No | A free-text notice with the debarment period |
| `orLaborContractors` | No | A licence register, not an enforcement list |

### Input

Run it with no input to collect judgments, the current port drayage list, and
all five free feeds.

| Field | Type | Default | Description |
|---|---|---|---|
| `datasets` | array of strings | `[]` (every fast dataset) | `judgments`, `portDrayage`, `portDrayageHistory`, `wageClaims`, `waDebar`, `njWall`, `coWageTheft`, `ilDebar`, `orLaborContractors`, `caloshaPenalties`. `wageClaims` and `portDrayageHistory` run only when named. |
| `outputMode` | `records` or `entities` | `records` | One row per source record, or one row per deduplicated employer. |
| `verifyCoverage` | boolean | `true` | Second pass over judgments (by status) and wage claims (by month), compared and merged. Written to `VERIFICATION`. |
| `firstJudgmentYear` | integer | `2000` | Where year slicing starts. A fixed catch-all slice always covers everything before 2000; raising this skips the years in between. |
| `wageClaimsFirstDate` | string (date) | `2010-01-01` | Where day-by-day slicing starts. The corpus reaches back to 1997 and a fixed catch-all slice collects those earlier years whatever this is set to; raising this skips the years in between. |
| `portDrayageHistoryFrom` | string (date) | `2019-01-01` | First month of the port drayage back-fill. |
| `includeNonDefendantParties` | boolean | `false` | Keep wage-claim rows for the claimant side. Those rows name individual workers. |
| `requestDelayMs` | integer | `350` | Politeness delay per worker after each request. |
| `maxConcurrency` | integer (1 to 4) | `2` | Maximum simultaneous requests. |
| `fwuid`, `auraLoaded` | string, object | stored values | Escape hatch if Salesforce changes its framework identity. |

An unknown dataset name fails fast with a clear error instead of quietly
collecting nothing.

#### Example runs

The port drayage list, one request, finishes in seconds:

```json
{ "datasets": ["portDrayage"] }
```

Every California judgment since 2020, with amounts, verified:

```json
{ "datasets": ["judgments"], "firstJudgmentYear": 2020 }
```

One row per employer across California and the five free feeds:

```json
{ "outputMode": "entities" }
```

The full wage-claim back-fill, every claim back to 1997 (about 6,150 requests,
roughly two hours at the default pacing):

```json
{ "datasets": ["wageClaims"], "wageClaimsFirstDate": "2010-01-01" }
```

Just this month's wage claims, which is a few dozen requests. The years between
2010 and the date you give are deliberately not swept:

```json
{ "datasets": ["wageClaims"], "wageClaimsFirstDate": "2026-08-01" }
```

The whole port drayage add-and-remove history, one snapshot per month:

```json
{ "datasets": ["portDrayageHistory"], "portDrayageHistoryFrom": "2019-01-01" }
```

### Memory and run time

- **Records mode needs 1024 MB**, the default. Rows are written to the dataset
  slice by slice as the sweep goes, and the run keeps only per-slice counts and
  record keys for verification. A full run holds about 670,000 records
  (629,776 wage claims, 31,027 judgments, the port drayage list and its history,
  and the five feeds, as measured 2026-09-29).
- **Entities mode needs 4096 MB for a full run.** The rollup can only be built
  once every record is in, so this mode holds the whole corpus in memory until
  the end. The default datasets, which leave out `wageClaims`, are far smaller.
- **Raise the run timeout for a full run.** Apify's default run timeout is
  3,600 seconds, and a full wage-claim back-fill is about 6,150 requests plus
  its verification pass, roughly two hours at the default pacing. Set a larger
  timeout in the run options (for example 14,400 seconds) when `wageClaims` is
  selected from 2010, or the platform stops the run partway through.

### Output modes

**`records`** (default): one flat row per source record, in the shape above.

**`entities`**: one row per employer, keyed on a hash of the normalized name and
address, with `name_variants`, `addresses`, `states`, `sources`, the per-source
records, and rollups: `total_judgment_amount`, `open_judgment_count`,
`on_port_drayage_list`, `wa_debarred`, `nj_wall_listed`, `record_count`.
Washington rows carry their `ubi`.

`total_judgment_amount` adds up the California judgment totals, counting each
judgment once per employer. That matters twice over: one judgment naming three
defendants arrives as three rows, and the port drayage list repeats judgments the
judgment search already returned. Penalties from the other states are not folded
into it; they stay on their own rows.

Entity matching in this version is deliberately conservative: it folds case and
punctuation but not address abbreviations, so it can leave two spellings of one
employer apart, and it will not merge an addressed record with an address-less
one. Sources that publish no address at all (Washington debarments, Illinois
debarments, California wage claims) therefore match each other on name, but do
not merge into an addressed California judgment. Under-merging is the deliberate
choice: an employer's total liability should never be overstated by a bad match.

### Data quality and the verification summary

- **The sweep verifies itself.** Judgments are collected in entry-date slices,
  then collected again by judgment status over exactly the same date windows,
  and the two sets of judgment-and-party keys are compared. Wage claims are
  collected one day at a time, then recounted one month at a time. Anything only
  the second pass saw is merged into the output.
  The comparison lands in the `VERIFICATION` record of the run's key-value
  store, with per-dataset counts, slices fetched, slices split, every failing
  slice, and the IDs each pass saw alone. Judgment statuses change between
  passes, so a handful of one-sided records is normal and the report says what
  it saw rather than promising a clean match. Two kinds of record cannot be
  reached by a status pass at all: those with no status, and those carrying a
  status the state never offers in its own picklist (`Pending/Open` is live in
  the data and missing from the picklist). Both are counted separately instead
  of being called a coverage miss.
- **A resumed run verifies what it resumed.** If the platform migrates or
  restarts a run, it resumes from its last checkpoint and skips the slices
  already written to the dataset. The checkpoint is saved every 50 slices,
  after each dataset's main sweep, and when a migration starts, and nothing more
  is written after that migration save, so a migration writes no row twice. An
  unannounced crash can repeat the rows written since the last save. The checkpoint
  keeps each slice's record count (and its judgment statuses or wage-claim
  docket months), so the second pass still covers the whole corpus: windows the
  run fetched itself are compared key by key as usual, and windows that came
  from the checkpoint are compared by count against the second pass. A count
  that no longer agrees is listed under `count_drift` with the window, the
  stored count and the recount, and fails the match; nothing is merged for it,
  because those records are already in the dataset. The per-dataset `count` and
  the totals include the resumed slices, so a resumed run reports the corpus it
  holds, not only what it fetched after the restart. Entities mode never
  resumes: it writes nothing until the end, so it starts over instead.
- **Zero date gaps, asserted.** The wage-claim check asserts that every single
  calendar day between the bounds was actually requested and did not error. A
  missing day is listed in the report.
- **The wage-claim corpus starts in 1997, not 2010.** Day slicing starts at
  2010-01-01 because that is where the claim volume is, and one catch-all slice
  collects everything earlier: about 31,000 records back to 1997, in roughly 37
  requests rather than the 4,750 that day-slicing them would take. The month
  recount follows the data, so those earlier records are verified the same way
  the rest are.
- **A slice that hits the cap splits itself.** The state caps any response at
  5,000 rows, so exactly 5,000 rows is never a count. Such a slice is halved and
  re-fetched down to a single day; a single day that still returns 5,000 is
  recorded as an error rather than silently truncated.
- **Data-entry typos are kept, not dropped.** DLSE holds judgment entry dates in
  2029 and 2205. A far-future slice catches them and the verification record
  counts them as out of window.
- **Some judgments carry a zero total.** About 27 in 5,000 come back as
  `0.0` rather than a figure. The zero is passed through as the state published
  it, and the verification record counts those rows under
  `records_without_positive_amount` rather than hiding them.
- **Judgment liability is joint and several.** A judgment naming three
  defendants is three rows, each carrying the full judgment total, because each
  party can be pursued for the whole amount. In `entities` mode each of those
  three employers therefore shows the full amount in
  `total_judgment_amount`. Adding `total_judgment_amount` across entities
  overstates the true total owed; to total real liability, sum by
  `case_number` in `records` mode instead.
- **Dates are ISO.** Every date in the output is `YYYY-MM-DD`, converted from
  whatever the source used.
- **Statuses are the source's own raw values,** not normalized.
- **`judgment_party_id` is not stable and must not be used as a key.** The state
  issues a different party id for the same party on the same judgment depending
  on which query returned the row. The actor collapses those twins itself, which
  is why the same employer never appears twice on one judgment in the output.
  The field is published only because it is what the state returned.
- **A feed that fails does not fail the run.** Each of the five free feeds is
  fetched independently, and its row count, `Content-Length` and `Last-Modified`
  are recorded. Illinois genuinely lists only one debarred company today, so
  zero rows there is a warning, not an error.

### Freshness

DIR's own HTML page describing the port drayage list is stamped March 2021 and
still describes the 2018 version of the statute. The endpoint behind the search
portal is current, and this actor reads the endpoint.

### Personal data

These are public enforcement registers, and the state publishes them so that the
parties with a duty to check them can. Sole proprietors and individually named
liable parties therefore appear under personal names, and the address on a
judgment can be a home address. Colorado names individual liable parties in its
own spreadsheet column.

Wage-claim rows exist for both sides of a case. **This actor keeps only the
defendant side by default**, because the other side is the worker who filed the
claim. `includeNonDefendantParties` turns that filter off; leave it off unless
you have a specific reason.

Do not treat any of this as a consumer marketing list.

The actor republishes these registers as the state publishes them, adds no
information about any person beyond what the state releases, and does not edit
records. A correction or removal happens at the source and flows through on the
next run.

**This dataset is not a consumer report, and the publisher is not a consumer
reporting agency as defined by the Fair Credit Reporting Act (15 U.S.C. § 1681
et seq.).** Do not use it as a factor in establishing any consumer's
eligibility for credit, insurance, employment, tenancy, or any other purpose
covered by the Act. It is published for statutory compliance screening of
businesses (such as the customer duty in Labor Code section 2810.4), journalism
and research.

### Politeness

Two concurrent requests by default, a 350 ms delay per worker after each request,
three attempts with exponential backoff on server errors and timeouts, and a
User-Agent that identifies the actor. There is no CAPTCHA and no login on any of
these sources; the state serves this data to an anonymous visitor.

### Sources

- [California Labor Commissioner judgment search and port drayage list](https://cadir.my.site.com/s/)
- [California Labor Commissioner wage claim search](https://cadir.my.site.com/wcsearch/s/)
- [Washington L\&I debarred contractors](https://secure.lni.wa.gov/debarandstrike/ContractorDebarList.aspx)
- [New Jersey WALL](https://www.nj.gov/labor/ea/osec/wall.shtml)
- [Colorado wage theft transparency decisions](https://cdle.colorado.gov/dlss/decisions-and-appeals-information)
- [Illinois debarred public works contractors](https://labor.illinois.gov/laws-rules/conmed/debarred-contractors.html)
- [Oregon BOLI labor contractor licensing](https://www.oregon.gov/boli/employers/Pages/labor-contractor-licensing.aspx)
- [Cal/OSHA penalties over $100,000](https://www.dir.ca.gov/dosh/statistics/Penalties-100K.html)

This actor is not affiliated with or endorsed by any of these agencies. Data
accuracy is the agencies' own. Every record carries the timestamp it was
scraped.

# Changelog

This Actor's version history is a separate document: https://apify.com/overlookdata/ca-dlse-judgments/changelog.md

# Actor input Schema

## `datasets` (type: `array`):

Leave empty to collect every fast dataset: judgments, the current port drayage list, and the five free multi-state feeds. The wage-claim sweep and the port drayage history are excluded from that default because they are long runs, so name them explicitly when you want them.

## `outputMode` (type: `string`):

One flat row per source record, or one row per deduplicated employer across every collected source with the amounts and compliance flags rolled up. Records mode streams rows to the dataset as it goes and fits a full run in the default 1024 MB. Entities mode holds the whole corpus in memory until the end to build the rollup, so give a full entities run 4096 MB; it also starts over rather than resuming after a platform migration, because nothing is written until the end.

## `verifyCoverage` (type: `boolean`):

Re-enumerate judgments by judgment status and wage claims by calendar month over the same date windows the sweep covered, compare the two passes, merge anything only the second pass found, and write the comparison to the VERIFICATION record in the default key-value store. The judgment check runs one query per status per window, so it costs several times the primary sweep. The wage-claim recount runs one query per month of data it actually saw, about 356 on a full run back to 1997, roughly a minute at the default pacing.

## `firstJudgmentYear` (type: `integer`):

Year slicing starts here. The judgment corpus starts on 2000-04-07, and a separate catch-all slice always covers everything before 2000 so data-entry typos still surface. Raising this skips the years in between.

## `wageClaimsFirstDate` (type: `string`):

Where day-by-day slicing starts. The corpus itself reaches back to 1997, and those earlier records are collected by one fixed catch-all slice that splits itself as needed, about 37 requests for roughly 31,000 records instead of the 4,750 that day slicing them would cost. Raising this skips the years in between: setting 2026-08-01 sweeps that day onward plus the catch-all, and does not sweep 2010 to July 2026. That is what makes a narrowed run fast.

## `portDrayageHistoryFrom` (type: `string`):

First month of the port drayage back-fill. The endpoint replays the list as of any past date, one request per month.

## `includeNonDefendantParties` (type: `boolean`):

Off by default. Wage-claim rows also exist for the claimant side of a case, and those rows name individual workers rather than businesses. Turn this on only if you have a reason to hold personal data.

## `requestDelayMs` (type: `integer`):

Politeness delay each worker waits after a request.

## `maxConcurrency` (type: `integer`):

Maximum number of simultaneous requests.

## `fwuid` (type: `string`):

Escape hatch. Leave empty to use the stored value. The actor already self-heals from the framework id every response reports, so you only need this if Salesforce changes something deeper.

## `auraLoaded` (type: `object`):

Escape hatch, paired with the framework id. Leave empty to use the stored value.

## Actor input object example

```json
{
  "datasets": [
    "portDrayage"
  ],
  "outputMode": "records",
  "verifyCoverage": true,
  "firstJudgmentYear": 2000,
  "wageClaimsFirstDate": "2010-01-01",
  "portDrayageHistoryFrom": "2019-01-01",
  "includeNonDefendantParties": false,
  "requestDelayMs": 350,
  "maxConcurrency": 2
}
```

# Actor output Schema

## `records` (type: `string`):

No description

## `verification` (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 = {
    "datasets": [
        "portDrayage"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("overlookdata/ca-dlse-judgments").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 = { "datasets": ["portDrayage"] }

# Run the Actor and wait for it to finish
run = client.actor("overlookdata/ca-dlse-judgments").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 '{
  "datasets": [
    "portDrayage"
  ]
}' |
apify call overlookdata/ca-dlse-judgments --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,overlookdata/ca-dlse-judgments"
        }
    }
}
```

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/mCxAWNmBS0krvFSgv/builds/cZjS4aHZEGUVwQe6d/openapi.json
