# California Prop 65 60-Day Notice & Settlement Monitor (`prudent_businessman/prop65-60-day-notice-monitor`) Actor

Pull California Proposition 65 60-day notices of violation and settlements from the official CA Attorney General database. Filter by company, product, chemical or keyword, and get only new notices on a schedule.

- **URL**: https://apify.com/prudent_businessman/prop65-60-day-notice-monitor.md
- **Developed by:** [Benningfield Data](https://apify.com/prudent_businessman) (community)
- **Categories:** Lead generation, E-commerce, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$5.00 / 1,000 notices

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

## California Prop 65 60-Day Notice & Settlement Monitor

Get every **California Proposition 65 60-day notice of violation** straight from the **official California Attorney General database**, as clean JSON, CSV or Excel. Each notice comes with its company names, product, chemicals, plaintiff and law firm. Any reported **settlement, judgment, complaint or withdrawal** is attached too, with civil penalties and attorney fees.

Run it once to research a company or product category. Or schedule it daily in **monitor mode** and get only the notices filed since the last run.

> Data source: [oag.ca.gov/prop65/60-day-notice-search](https://oag.ca.gov/prop65/60-day-notice-search). This is a public government database. No login, proxy or API key is needed.

### Who uses this

- **Ecommerce brands, Amazon and Walmart sellers.** See which products and chemicals are being targeted right now, such as lead in ceramics, DEHP in cables or BPA in drinkware. Then fix labels before you get a notice.
- **Compliance consultants, testing labs and warning-label vendors.** Each new notice names a company that needs Prop 65 help this month. That makes it a ready-made, high-intent lead list.
- **Law firms.** Track filings by plaintiff, law firm, defendant or chemical. Benchmark settlement amounts and attorney fees.
- **Retailers and marketplaces.** Get alerts when your own company name, or one of your suppliers, shows up as an alleged violator.
- **Insurers and analysts.** Measure enforcement trends by chemical, product category or year. The data goes back to 1988.

### Features

- Official AG data only, nothing third-party.
- Filter by **date range**, **company (alleged violator)**, **product**, **chemicals** and **free-text keywords**.
- **Monitor mode** (`only_new`). It remembers the notice numbers it has already output, so a scheduled run returns only new notices. This is good for Slack, email or webhook alerts through Apify integrations.
- **Case filings merged per notice.** Settlements, judgments, complaints and withdrawals are grouped under the notice they belong to, with total civil penalty, attorney fees and other payments.
- **Amendment detection.** It flags amended notices and extracts the original notice number they amend.
- **Clean company list.** "Acme, Inc., Foo LLC, Amazon.com Services LLC" becomes `["Acme, Inc.", "Foo LLC", "Amazon.com Services LLC"]`. The raw string is kept too.
- **Any date range.** The AG's export caps each request at 1,000 rows. The Actor splits large ranges automatically, so a full year (more than 5,000 notices) works in one run.
- A link to each notice's official page, which has the notice PDF.

### Input

| Field | Type | Description |
|---|---|---|
| `days_back` | integer | Notices from the last N days. Default 30. Ignored if `start_date` is set. |
| `start_date` / `end_date` | `YYYY-MM-DD` | Exact date range. End defaults to today. |
| `alleged_violator` | string | Company name contains this text (filtered by the AG server), e.g. `Amazon`. |
| `product` | string | Product description contains this text (filtered by the AG server), e.g. `water bottle`. |
| `chemicals` | string\[] | Keep notices listing any of these chemicals, e.g. `["Lead", "DEHP", "BPA"]`. |
| `keywords` | string\[] | Keep notices where any keyword appears in the product, company, chemical, plaintiff, comments or case name. |
| `case_filings_only` | boolean | Only notices with a settlement, judgment, complaint or withdrawal on file. |
| `only_new` | boolean | Monitor mode. Only notices not seen in earlier runs. |
| `state_store_name` | string | Named key-value store for monitor state. Use one name per monitor. |
| `max_items` | integer | Cap on results. 0 means no limit. |

Example: daily alert for notices that name Amazon, Walmart or Target.

```json
{
  "days_back": 7,
  "keywords": ["amazon", "walmart", "target"],
  "only_new": true,
  "state_store_name": "big-box-prop65"
}
```

Example: all 2025 settlements, for benchmarking.

```json
{ "start_date": "2025-01-01", "end_date": "2025-12-31", "case_filings_only": true }
```

### Output

There is one item per notice. See `sample_output.json` and `sample_output_case_filings.json`. Below is a real record, shortened:

```json
{
  "agNumber": "2025-02214",
  "noticeDate": "2025-06-30",
  "noticingParty": "Center for Consumer Safety, LLC",
  "plaintiffAttorney": "Shannon C Wilhite, Attorney at Law",
  "allegedViolators": ["The Vanman Company, LLC", "Amazon.com, Inc."],
  "chemicals": ["Lead"],
  "product": "Miracle Tooth Cleaning Powder Toothpaste",
  "isAmendment": false,
  "amendsNoticeNumber": null,
  "hasCaseFiling": true,
  "caseFilingCount": 1,
  "caseFilings": [{
    "caseId": "Settlement 7834",
    "caseType": "Settlement",
    "caseName": "Center for Consumer Safety, LLC v The VanMan Company, LLC",
    "civilPenalty": 2500,
    "attorneyFees": 22500,
    "otherPayments": 0,
    "totalPayments": 25000,
    "injunctiveRelief": "2.1 Clear and Reasonable Warning. ..."
  }],
  "totalCivilPenalty": 2500,
  "totalAttorneyFees": 22500,
  "totalPayments": 25000,
  "noticeUrl": "https://oag.ca.gov/prop65/60-Day-Notice-2025-02214",
  "source": "California Office of the Attorney General - Proposition 65 60-Day Notice database",
  "scrapedAt": "2026-10-26T15:05:00.000Z"
}
```

You can download the dataset as JSON, CSV, Excel or HTML, or read it through the Apify API.

### Pricing

Pay per result: **$0.005 per notice ($5 per 1,000 notices)**, with no per-run fee. A typical daily monitor run returns 10–40 new notices and costs 5–20 cents. A full-year backfill of about 5,000 notices costs about $25.

### Notes and limits

- Notice dates are the dates the AG received the notice. Case filings show up whenever the parties report them, which can be months later. Re-run older ranges with `case_filings_only` to pick them up.
- Settlement amounts are as reported to the AG. Blank fields are `null`.
- Everything here is a public filing that California law requires to be published. Noticing parties and attorneys are named as they appear in those filings. The Actor collects no other personal data.
- A 60-day notice is an *allegation*, not a finding of a violation.

### FAQ

**Do I need an API key or proxy?** No. The AG database is public.

**How fresh is the data?** The AG usually posts notices within a day or two. Schedule the Actor daily with `only_new: true`.

**Can I get the notice PDF?** Yes. `noticeUrl` opens the official notice page, which links the PDF and certificate of merit.

# Actor input Schema

## `days_back` (type: `integer`):

Fetch notices filed in the last N days (ignored if Start date is set).

## `start_date` (type: `string`):

Optional. First notice date to include, YYYY-MM-DD. Data goes back to 1988.

## `end_date` (type: `string`):

Optional. Last notice date to include, YYYY-MM-DD. Defaults to today.

## `alleged_violator` (type: `string`):

Server-side filter on the company names in the notice, e.g. "Amazon", "Walmart", "Target".

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

Server-side filter on the product description, e.g. "water bottle", "cable", "chocolate".

## `chemicals` (type: `array`):

Keep notices listing any of these chemicals (case-insensitive contains), e.g. Lead, DEHP, BPA, Acrylamide, PFOA.

## `keywords` (type: `array`):

Keep notices where any keyword appears in product, company, chemical, plaintiff or comments.

## `case_filings_only` (type: `boolean`):

Only output notices that have a follow-up filing reported to the AG (settlement, judgment, complaint or withdrawal), with penalties and fees where reported.

## `only_new` (type: `boolean`):

Remember notice numbers between runs and only output notices not seen before. Use with a Schedule for daily alerts. The first run outputs everything and saves the baseline.

## `state_store_name` (type: `string`):

Named key-value store used by monitor mode. Use different names for different monitors.

## `max_items` (type: `integer`):

Stop after this many notices (0 = no limit).

## Actor input object example

```json
{
  "days_back": 30,
  "case_filings_only": false,
  "only_new": false,
  "state_store_name": "prop65-notice-monitor-state",
  "max_items": 0
}
```

# Actor output Schema

## `results` (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 = {
    "days_back": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("prudent_businessman/prop65-60-day-notice-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 = { "days_back": 30 }

# Run the Actor and wait for it to finish
run = client.actor("prudent_businessman/prop65-60-day-notice-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 '{
  "days_back": 30
}' |
apify call prudent_businessman/prop65-60-day-notice-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,prudent_businessman/prop65-60-day-notice-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/q0y6YiPjanuodhksc/builds/ruvc8yfjV24lTzgfd/openapi.json
