# Nursing Home Fines & Civil Money Penalties (CMS) Scraper (`jserle/nursing-home-penalties-fines`) Actor

Nursing home fines and civil money penalties from CMS: every fine and Medicare payment denial in the last three years, 16,166 records with CCN, date, type, dollar amount and denial window. Filter by state, CCN, facility name, date range, type or minimum fine. $0.01/record.

- **URL**: https://apify.com/jserle/nursing-home-penalties-fines.md
- **Developed by:** [JS Tech Solutions](https://apify.com/jserle) (community)
- **Categories:** Lead generation, Other
- **Stats:** 2 total users, 1 monthly users, 90.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$10.00 / 1,000 penalty records

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?

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

## Nursing Home Fines & Civil Money Penalties (CMS) Scraper

Pulls every nursing home fine (civil money penalty) and Medicare payment denial CMS has levied in the last three years into clean JSON records: facility, CCN, address, penalty date, type, fine amount in dollars, and the payment-denial window. Filter by state, CCN, facility name, date range, penalty type or minimum fine.

**16,166 penalties across 6,844 facilities in 53 states and territories** as of the July 2026 extract: 13,687 fines totalling **$464 million**, and 2,479 payment denials running from 1 to 458 days. CMS publishes this only as a browser table and a monthly CSV; this Actor turns it into records you can drop into a database, a diligence model, or an alert pipeline.

### Who uses this data

- **Elder-law and nursing home abuse attorneys** building the enforcement history of a defendant facility. One CCN, one run, every fine and payment denial with dates and dollar amounts.
- **Long-term care liability underwriters** pricing a facility or a book. Penalty frequency and severity per CCN is a loss signal you cannot get from star ratings alone.
- **Nursing home lenders, brokers, credit and bond analysts covering SNF operators.** Filter by provider name to roll a chain's penalty exposure up across every facility it runs, or by state to size regulatory pressure in a market.
- **Senior placement and referral services** screening facilities before they go on a shortlist for a family.

### What you get

One dataset item per penalty, newest penalty date first.

```json
{
  "source": "https://data.cms.gov/provider-data/dataset/g6vv-u9sr",
  "attribution": "Centers for Medicare & Medicaid Services (CMS)",
  "penaltyId": "fine:140300",
  "ccn": "375284",
  "providerName": "Arbor Village",
  "providerAddress": "310 W Taft Ave",
  "city": "Sapulpa",
  "state": "OK",
  "zipCode": "74066",
  "penaltyDate": "2026-06-11",
  "penaltyType": "Fine",
  "fineId": "140300",
  "fineAmount": 14385,
  "paymentDenialStartDate": null,
  "paymentDenialLengthDays": null,
  "paymentDenialEndDate": null,
  "processingDate": "2026-07-01",
  "fetchedAt": "2026-08-23T11:38:23.648Z"
}
```

A payment denial fills the other half: `"penaltyType": "Payment Denial"`, `fineId` and `fineAmount` `null`, and `"paymentDenialStartDate": "2026-06-28"`, `"paymentDenialLengthDays": 2`, `"paymentDenialEndDate": "2026-06-29"`.

- `penaltyDate` is CMS's own definition: **the date of the inspection that triggered the penalty**, not the date the money was collected.
- `fineAmount` and `paymentDenialLengthDays` arrive as numbers, not strings. Missing values are `null`, never `""`.
- `paymentDenialEndDate` is **derived, not published**. CMS gives a start date and a length in days, so this is start + (length - 1) days: the last day of the suspension, inclusive. Every delivered payment denial has all three denial fields populated; on a fine, all three are `null`.
- `penaltyId` is a stable key: `fine:<Fine ID>` for fines, using CMS's own identifier, and `denial:<ccn>:<start>:<days>` for payment denials, which CMS does not identify. Across the full 16,166-row extract those produce 16,166 distinct keys, so nothing collapses.
- Dates are ISO 8601 calendar dates, exactly as CMS publishes them. No time of day is invented.
- Every delivered record matches one of the two penalty shapes CMS documents: a **fine** with an identifier and a whole-dollar amount, or a **payment denial** with a start date and a whole number of days. A row that fails that check, or that carries a date or number CMS's own dictionary promises but this Actor cannot parse, is skipped and reported in the run summary rather than delivered with a `null` where the amount should be. You are not charged for it. All 16,166 rows in the current extract pass both checks.

### Input

Everything is optional. Run it with no input and you get the 100 most recent penalties nationwide.

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `state` | string | - | Two-letter postal abbreviation, exact match. 53 appear in the data, including DC, GU and PR. |
| `ccn` | string | - | Six-character CMS Certification Number, exact match. The stable federal id for one facility. |
| `providerNameContains` | string | - | Literal case-insensitive substring of the facility name, e.g. `Genesis`. Good for chains. |
| `penaltyType` | enum | `any` | `any`, `Fine`, or `Payment Denial`. |
| `penaltyDateFrom` | ISO date | - | Keeps penalties dated on or after this day. |
| `penaltyDateTo` | ISO date | - | Keeps penalties dated on or before this day. |
| `minFineAmount` | integer | - | Keeps only fines of at least this many dollars. Implies fines, since denials carry no amount. |
| `maxResults` | integer | 100 | 1 to 20000. This is your cost cap: you pay per delivered record. |
| `includeRaw` | boolean | false | Attach a `raw` object with the CMS columns under their original API names. |

Every filter except `minFineAmount` is pushed to CMS's own query API, so a narrow search reads less and finishes faster. `minFineAmount` is applied after the rows arrive, because CMS stores the amount as text and its `>=` compares it as text: asking the API for `fine_amount >= 100000` returns `5782`.

`providerNameContains` is matched literally. `%` and `_` are wildcards in the catalog's query language, so they are escaped before the query is sent and the match is re-checked locally; typing `GEN%SIS` finds facilities with that exact string, not every name from GENESIS to GENSIS.

#### Example inputs

**Every fine and payment denial for one facility** (case file, diligence):

```json
{
  "ccn": "375284",
  "maxResults": 500
}
```

**Large fines in one state this year** (underwriting, market screening):

```json
{
  "state": "TX",
  "penaltyType": "Fine",
  "minFineAmount": 50000,
  "penaltyDateFrom": "2026-01-01",
  "maxResults": 1000
}
```

**A chain's penalty exposure across every facility it operates**:

```json
{
  "providerNameContains": "Genesis",
  "maxResults": 2000
}
```

### Pricing

**$0.01 per record; you pay only for records delivered.** One charge per dataset item, nothing else. `maxResults` is your ceiling, not a quota: at 100 it can cost at most $1.00, and a filter matching fewer penalties costs proportionally less. Filters are applied before delivery, so a narrow search costs less than a broad one. Nothing else is billable, and a run that fails delivers and charges nothing.

### Data source, refresh and licence

Records come from the **Centers for Medicare & Medicaid Services (CMS)** Provider Data Catalog, read through the catalog's own datastore query API:

- Dataset: [Penalties](https://data.cms.gov/provider-data/dataset/g6vv-u9sr) (`g6vv-u9sr`), described by CMS as "A list of the fines and payment denials received by nursing homes in the last three years."
- API: `https://data.cms.gov/provider-data/api/1/datastore/query/5b9088ff-626e-5038-bab8-fc3d4c476be4`
- Field definitions: [Nursing Home Data Dictionary](https://data.cms.gov/provider-data/sites/default/files/data_dictionaries/nursing_home/NH_Data_Dictionary.pdf) (PDF), Table 14.

**Refresh:** CMS refreshes this table monthly; its data dictionary names the file `NH_Penalties_MonYYYY.csv`, and the current one is `NH_Penalties_Jul2026.csv`. The catalog metadata for that extract reads `modified: 2026-07-01`, `released: 2026-07-29`, `nextUpdateDate: 2026-08-26`; every record carries CMS's own `processingDate` so you can see which extract you have. A monthly schedule tracks the source; running it daily will return the same extract until CMS posts the next one.

**Licence:** The Provider Data Catalog's own metadata declares no licence for this dataset. CMS's sibling catalog at data.cms.gov declares `https://www.usa.gov/government-works` on each of its datasets; that page states a "government work is something created by a U.S. government officer or employee as part of their official duties" and that such works are not copyright-protected, while cautioning that you "cannot use government materials in a way that implies endorsement by a government agency, official, or employee."

**Attribution:** Centers for Medicare & Medicaid Services (CMS), carried on every record in the `attribution` field. **This Actor is not affiliated with or endorsed by CMS.** No login, API key, or account is involved. Buyers are responsible for their own use of the data.

data.cms.gov publishes `crawl-delay: 10` in its robots.txt and does not disallow `/provider-data/api/*`. This Actor honours that delay between requests, including between retries, and waits longer still when CMS sends a `Retry-After` header. It sends a descriptive User-Agent, opens no parallel connections, and caches nothing between runs. A default 100-record run is a single request.

### Limitations

- **Three years only.** CMS publishes a rolling three-year window. The current extract spans 2023-07-17 to 2026-06-11. Older penalties are not available here, and this Actor does not archive them for you.
- **Penalties, not deficiencies.** A facility can be cited without being penalized. This table is the enforcement outcome, not the inspection record; for the underlying citations see the [Nursing Home Deficiency Citations](https://apify.com/jserle/nursing-home-deficiency-citations) Actor or CMS's [Health Deficiencies](https://data.cms.gov/provider-data/dataset/r5ix-sfxw) dataset.
- **No appeal or payment status.** The table has fourteen columns and none of them says whether a penalty was appealed, reduced, waived, or actually collected. Treat `fineAmount` as the amount CMS published, not as money known to have changed hands.
- **No payment-denial end date at the source.** CMS publishes a start date and a length in days; `paymentDenialEndDate` is computed from those two rather than published, so check it against the source if it is load-bearing for you.
- **Monthly, not live.** A penalty imposed today appears in the next monthly extract, not immediately.
- **Federally certified nursing homes only.** Facilities without a Medicare or Medicaid certification are outside CMS's enforcement data entirely.

### FAQ

#### How do I find out if a nursing home has been fined?

Run with the facility's `ccn` (the six-character CMS Certification Number shown on its Care Compare page) or with `providerNameContains`. Every fine and payment denial CMS has published for that facility in the last three years comes back with the penalty date and the dollar amount.

#### What is a civil money penalty (CMP) for a nursing home?

A fine CMS imposes after a survey finds noncompliance serious enough to penalise. In this dataset it appears as `penaltyType: "Fine"` with `fineAmount` in whole dollars and CMS's own `fineId`.

#### What is a denial of payment for new admissions?

The other enforcement remedy in this dataset: Medicare and Medicaid stop paying for new admissions to the facility for a set number of days. It appears as `penaltyType: "Payment Denial"` with a start date, a length in days and a derived end date.

#### How often is the CMS nursing home penalties data updated?

Monthly. The current extract is `NH_Penalties_Jul2026.csv`, and every record carries the `processingDate` of the extract it came from.

#### Can I get nursing home fines by state?

Yes. Set `state` to a two-letter code; the filter runs on the CMS API. Combine it with `minFineAmount` and a date range to keep only the large, recent fines.

#### Does the fine amount show what was actually paid?

No. CMS publishes the amount imposed. Appeals, reductions, waivers and collection status are not in this dataset.

### Related datasets

Other datasets by the same author, all pay-per-record with source, refresh cadence and licence stated on each listing:

**Nursing home and long-term care data**

- [Nursing Home Deficiency Citations (CMS) Scraper](https://apify.com/jserle/nursing-home-deficiency-citations)
- [Nursing Home Directory & Ownership (CMS Form 671) Scraper](https://apify.com/jserle/ltc-facility-characteristics)
- [Nursing Home Daily Nurse Staffing (CMS PBJ) Scraper](https://apify.com/jserle/cms-nursing-home-staffing-daily)
- [Nursing Home Change of Ownership (CMS SNF CHOW) Scraper](https://apify.com/jserle/snf-change-of-ownership-tracker)
- [New York Nursing Home Bed Availability (NYSDOH) Scraper](https://apify.com/jserle/ny-nursing-home-bed-census)

**Medicare provider enrollment data**

- [Medicare Revoked Providers List (CMS Revocations) Scraper](https://apify.com/jserle/medicare-revoked-providers)
- [Medicare Opt-Out Providers List (CMS Affidavits) Scraper](https://apify.com/jserle/medicare-opt-out-physicians)
- [Medicare Revalidation Due Date List (CMS) Scraper](https://apify.com/jserle/medicare-revalidation-due-leads)

**Public procurement and RFP feeds**

- [E-Rate Form 470 RFP Scraper (USAC School & Library Bids)](https://apify.com/jserle/erate-form-470-rfp-feed)
- [NYC PASSPort Procurement Scraper (RFPs, Bids & Contracts)](https://apify.com/jserle/nyc-passport-procurement)

**Developer and AI test data**

- [Synthetic Invoice OCR Ground Truth Dataset Generator](https://apify.com/jserle/ocr-ground-truth-document-factory)

# Actor input Schema

## `state` (type: `string`):

Two-letter postal abbreviation, matched exactly. 53 values appear in the data, including DC, GU and PR. Example: NY

## `ccn` (type: `string`):

Six-character CCN of one facility, matched exactly. This is the stable federal id for a nursing home. Example: 335003

## `providerNameContains` (type: `string`):

Case-insensitive substring of the facility name, matched by CMS's API. Useful for tracking an operator or chain across facilities. Example: Genesis

## `penaltyType` (type: `string`):

Fines are civil money penalties in dollars. Payment denials suspend Medicare/Medicaid payment for new admissions for a number of days.

## `penaltyDateFrom` (type: `string`):

ISO date, for example 2025-01-01. Keeps penalties dated on or after this day. The penalty date is the date of the inspection that triggered the penalty.

## `penaltyDateTo` (type: `string`):

ISO date, for example 2026-06-30. Keeps penalties dated on or before this day.

## `minFineAmount` (type: `integer`):

Keeps only fines of at least this many dollars. Setting it restricts the run to fines, because payment denials carry no dollar amount. Example: 100000

## `maxResults` (type: `integer`):

How many records to deliver, newest penalty date first. You are charged per delivered record, so this is also your cost cap.

## `includeRaw` (type: `boolean`):

Attach a `raw` object with the CMS columns under their original API names, whitespace-trimmed. Useful for auditing the normalization.

## Actor input object example

```json
{
  "penaltyType": "any",
  "maxResults": 100,
  "includeRaw": false
}
```

# Actor output Schema

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

One item per penalty delivered by this run, newest penalty date first.

## `summary` (type: `string`):

Source URLs, filters applied, rows read, requests made, delivered records and whether the charge limit stopped the run.

# 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 = {
    "penaltyType": "any",
    "maxResults": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("jserle/nursing-home-penalties-fines").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 = {
    "penaltyType": "any",
    "maxResults": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("jserle/nursing-home-penalties-fines").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 '{
  "penaltyType": "any",
  "maxResults": 100
}' |
apify call jserle/nursing-home-penalties-fines --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jserle/nursing-home-penalties-fines"
        }
    }
}

```

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/BjHnG3qdyOreHnA02/builds/1Wciynrjrf3O2fYM8/openapi.json
