# Prop 65 60-Day Notice Search + Settlement Benchmark (`malekh/prop-65-60-day-notice-settlement-benchmark`) Actor

Search every California Proposition 65 60-day notice by product, chemical, company or plaintiff, from the Attorney General's own register. Returns what comparable notices actually settled for - civil penalty vs attorney fees, with the sample size attached - and profiles each filer.

- **URL**: https://apify.com/malekh/prop-65-60-day-notice-settlement-benchmark.md
- **Developed by:** [Malek H](https://apify.com/malekh) (community)
- **Categories:** Automation, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

- **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

## Prop 65 60-Day Notice Monitor + Settlement Benchmark (California AG)

Search every **Proposition 65 60-day notice** filed with the California Attorney
General, and get the number a Prop 65 notice actually raises: **what notices like
this one have settled for**, and **whether the party who filed it is a serial
filer**.

Search by product, chemical, company (defendant), plaintiff or AG number. Data
comes straight from the California Attorney General's own 60-day notice register.

### The question this answers

A Prop 65 60-day notice lands on your desk. The register will tell you it exists.
It will not tell you the two things you need before you call your lawyer:

1. **What is this going to cost?** Over resolved comparables, the median Prop 65
   settlement runs about **$19,500** — of which the median civil penalty is
   **$2,000** and the median attorney fees are **$18,000**. Attorney fees are a
   median **90% of the total settlement**. (Measured per notice across 2023 H1;
   this Actor recomputes it live for *your* cohort, with the sample size
   attached.)
2. **Who is on the other side?** A handful of serial filers generate a large share
   of all notices. This Actor profiles each filer in your results: how many
   notices they filed, how often, against how many distinct companies, on which
   chemicals and products — and what their own matters have settled for.

### What you get

Three record types per search:

**`search_summary`** — notices matched, date range, the distinct noticing parties
ranked by volume, and the **settlement benchmark** for the whole matched cohort:
median / mean / min / max / p25 / p75 for total payments, civil penalty, attorney
fees and other payments, plus the attorney-fee share of the total and the share of
notices that ever acquired published economics.

**`notice`** — one record per notice: AG number, filing date, noticing party,
plaintiff attorney, alleged violators, chemicals, the product or source,
comments, every case event (Complaint / Settlement / Judgment / Withdrawal) with
its own figures, court docket numbers, type of claim, relief sought, the
injunctive-relief text, and the notice's civil penalty, attorney fees, other
payments and total.

**`filer_profile`** — per noticing party: notices filed in the window, notices per
month, first and latest filing, distinct companies targeted, plaintiff attorneys
used, top chemicals, top products, top targets, and that filer's own settlement
benchmark.

### Input

Pass one search, or a list of them in `queries`. Every search needs at least one
filter:

| Field | Matches |
|---|---|
| `defendant` | the alleged violator — any company named in the notice |
| `product` | the source/product text, e.g. `dried figs`, `vinyl gloves` |
| `chemical` | an officially listed chemical, e.g. `Lead`, `Diisononyl phthalate (DINP)` |
| `plaintiff` | the noticing party or its attorney |
| `agNumber` | one specific notice, e.g. `2026-03114` |

```json
{
  "defendant": "Whole Foods",
  "since": "2023-01-01",
  "maxFilersProfiled": 3
}
```

```json
{
  "queries": [
    { "product": "dried figs" },
    { "chemical": "Lead", "defendant": "Sprouts" },
    { "plaintiff": "Ecological Alliance" }
  ],
  "lookbackYears": 5
}
```

`since` / `until` bound the period (default: the last 3 years, via
`lookbackYears`). Pass `recordId` on a search and it is echoed onto every record
from it, so results join back onto your own list.

**Paying only for what you want.** Every part of the output can be switched off,
and anything switched off is not charged:

| Control | Effect |
|---|---|
| `maxNoticesPerQuery` | Caps the notice records returned. The benchmark is always computed over **every** matched notice, so a cap never moves the number you are quoting — it only limits the rows. |
| `includeNoticeRecords: false` | Returns just the search summary and the filer profiles. No notice records, no per-record charge. |
| `maxFilersProfiled: 0` | Skips serial-filer profiling entirely. No filer profiles, no filer-benchmark charge. |

### Who this is for

- **Companies and in-house counsel** that received a notice, or that sell into
  California and want to know what their product category attracts
- **Prop 65 defence firms** sizing exposure and checking a filer's track record
- **Compliance and product-safety teams** monitoring their category or their
  suppliers
- **Insurers and diligence teams** pricing Prop 65 exposure in a transaction

Prop 65 Clearinghouse sells subscription access to this same notice and settlement
database at **$1,150–$1,800/year**. That product is a searchable archive; this one
computes the answer.

### Source, and why the answer is trustworthy

**California Office of the Attorney General, Proposition 65 60-Day Notice
register** — the official filing register, read through the AG's own server-side
CSV export rather than by scraping an HTML page. Public, keyless, no login.

The register is not as simple as it looks, and the difference shows up as wrong
numbers rather than as errors. Every one of these was measured on 2026-07-30 and
is guarded at runtime:

- **The export returns at most 1,000 rows and has no pagination.**
  `items_per_page` and `page` are silently ignored. Worse, **truncation drops the
  newest rows**: a plain search for `Walmart` returns 1,000 rows ending in May
  2022 and silently omits the 843 notices filed since. Read literally, that says a
  company has been clear for four years. This Actor treats any response at the cap
  as a hard error and re-reads the period in bisected date windows until every
  window is provably complete.
- **The export ships one row per case event, not per notice.** A notice with a
  Complaint, a Settlement and a Judgment appears three times with the settlement
  repeated on each. Counting rows overstates a filer's volume by ~25%; averaging
  money over rows overstates the median settlement by 13%. Everything here is
  collapsed to the notice first.
- **Only ~38% of notices ever acquire published settlement economics**, because
  unresolved notices have nothing to report. So every figure is a **benchmark over
  resolved comparables, labelled with its sample size** — never an estimate
  attached to an open notice.
- **A notice can carry conflicting figures** where successive settlement records
  revise the attorney fees. A Judgment supersedes them; where nothing breaks the
  tie the notice is flagged and excluded from the benchmark rather than guessed at.
- **Chemical names contain commas** (`1,1,2,2-Tetrachloroethane`) and company
  names hide behind them (`Mindful Foods, Inc.`), so both are segmented against
  California's own 800+ listed-chemical vocabulary and a corporate-suffix rule
  rather than split on punctuation.
- **The AG's register reuses an AG number occasionally** — `2026-02912` covers two
  entirely unrelated notices. They are reported separately and flagged, not merged.
- **Freshness is checked before any search runs.** The newest notice in the whole
  register is compared to today and the run fails if the register has gone stale,
  because a stale register turns "no notices found" into a dangerous answer.

### Limits — read before you rely on it

- **This is not legal advice**, and the benchmark is **not a prediction** for any
  individual notice. It describes what comparable matters settled for.
- Settlement economics exist only for notices the AG has published outcomes for
  (~38%). Recent notices are mostly unresolved by construction.
- Company-name segmentation is a heuristic; the unmodified register text is always
  emitted alongside it as `allegedViolatorsRaw` and `chemicalsRaw`.
- Coverage is California Proposition 65 60-day notices only (Health & Safety Code
  §25249.5 et seq.). It is not a general litigation or CPSC recall search.

# Actor input Schema

## `defendant` (type: `string`):

Company name to search for among the alleged violators, e.g. 'Whole Foods' or 'Sprouts'. Partial names match, and a notice matches if the company appears anywhere in its violator list. Leave every search field empty and nothing runs — each search needs at least one filter.

## `product` (type: `string`):

The product or source the notice is about, e.g. 'dried figs', 'vinyl gloves', 'balsamic vinegar'. Partial text matches. This is usually the best field for 'what does my product category attract'.

## `chemical` (type: `string`):

An officially listed Proposition 65 chemical, spelled as California lists it — e.g. 'Lead', 'Cadmium', 'Di(2-ethylhexyl)phthalate (DEHP)', 'Diisononyl phthalate (DINP)'. The name is resolved against the Attorney General's own list of ~825 chemicals; if it is ambiguous or unlisted the run tells you so rather than searching for the wrong thing.

## `plaintiff` (type: `string`):

The party that filed the notice, or their attorney, e.g. 'Ecological Alliance' or 'Manning Law'. Use this to research a specific serial filer's whole track record.

## `agNumber` (type: `string`):

One specific notice by its Attorney General number, e.g. '2026-03114'. Use this when a notice has landed and you want that notice plus its filer's history.

## `queries` (type: `array`):

Run several searches in one go. Each entry is an object that may set any of defendant, product, chemical, chemicalId, plaintiff, agNumber, since, until and label — e.g. \[{"product":"dried figs"},{"chemical":"Lead","defendant":"Sprouts"}]. A plain string is treated as a product. Pass "recordId" on an entry and it is echoed onto every record produced from it, so the output joins back onto your own list. Overrides the single-search fields above. Maximum 10 per run.

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

Only notices filed on or after this date, as YYYY-MM-DD. Defaults to the lookback window below. Older periods cost more requests, so narrow this when you only care about recent filings.

## `until` (type: `string`):

Only notices filed on or before this date, as YYYY-MM-DD. Defaults to today.

## `lookbackYears` (type: `integer`):

How far back to search when no explicit 'since' date is given. Three years catches the current filing pattern; go longer to build a bigger settlement cohort.

## `maxFilersProfiled` (type: `integer`):

How many of the most active noticing parties in your results to profile in depth -- filing volume, targets, chemicals and their own settlement benchmark. Each profile reads that filer's full history and is charged as one filer benchmark. Set 0 to skip profiling entirely.

## `filerBenchmarkYears` (type: `integer`):

How many years of a filer's own history to read when profiling them. Longer windows give a larger settlement cohort and a more stable median.

## `includeNoticeRecords` (type: `boolean`):

On by default. Turn it off to get only the search summary and the filer profiles — useful when you want the benchmark and the filer intelligence but not the underlying rows, and it is cheaper because notice records are charged per record.

## `maxNoticesPerQuery` (type: `integer`):

A visible cap so a broad search cannot run up an unexpected bill. The most recent notices are returned first. The settlement benchmark is always computed over EVERY matched notice, not just the ones returned, so this cap never changes the figures you are quoting.

## Actor input object example

```json
{
  "defendant": "Whole Foods",
  "queries": [],
  "lookbackYears": 3,
  "maxFilersProfiled": 3,
  "filerBenchmarkYears": 5,
  "includeNoticeRecords": true,
  "maxNoticesPerQuery": 200
}
```

# 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 = {
    "defendant": "Whole Foods",
    "queries": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("malekh/prop-65-60-day-notice-settlement-benchmark").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 = {
    "defendant": "Whole Foods",
    "queries": [],
}

# Run the Actor and wait for it to finish
run = client.actor("malekh/prop-65-60-day-notice-settlement-benchmark").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 '{
  "defendant": "Whole Foods",
  "queries": []
}' |
apify call malekh/prop-65-60-day-notice-settlement-benchmark --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=malekh/prop-65-60-day-notice-settlement-benchmark",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/mAyUUS7tj5jEVcc8S/builds/0IgsFlEtCoYrMYfCE/openapi.json
