# Nursing Home Directory & Ownership (CMS Form 671) Scraper (`jserle/ltc-facility-characteristics`) Actor

Nursing home directory and ownership data from CMS Form 671: all 14,696 certified US long-term care facilities with CCN, city/state/ZIP, ownership type, chain affiliation, resident census and special care unit beds. Filter by state, city, ownership, chain or census. $0.01/record.

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

## Pricing

$10.00 / 1,000 facility 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 Directory & Ownership (CMS Form 671) Scraper

Pulls every Medicare- and Medicaid-certified long-term care facility in the United States, **14,696 nursing homes** across all 50 states, DC, Puerto Rico and Guam, into clean JSON records: CCN, name, city/state/ZIP, certification date, ownership type and category, chain affiliation, resident census, dedicated special-care-unit beds, and hospital-based and CCRC flags.

CMS collects this on **Form 671** during each facility's annual survey and publishes it as a quarterly snapshot. This Actor turns that snapshot into a filterable nursing home list by state, city, ownership, chain, census size or special care unit, ready for a CRM, a territory model, or a spreadsheet.

### Who uses this data

- **LTC suppliers, pharmacies, therapy and staffing vendors sizing a territory.** Filter to a state and an ownership category and you have the addressable list, with resident census as the size signal. The special-care-unit filter is the sharp one: `ventilator` returns only the 429 facilities nationally that report dedicated ventilator beds, `dialysis` only 341.
- **Senior-care SaaS and healthcare sales teams.** Chain affiliation is the buying unit. `chainName` groups the 8,611 chain-affiliated facilities under the 3,951 organizations that actually sign contracts, so you can route enterprise and independent accounts differently.
- **Nursing home brokers, lenders and REIT analysts** who need ownership type, chain membership and census for every facility in a market.
- **Researchers and analysts** studying ownership concentration, for-profit versus non-profit mix, chain penetration, or special-care capacity by geography.

### What you get

One dataset item per facility, in CMS's own order (CCN ascending, which groups records by state because the first two digits of a CCN encode the state).

```json
{
  "ccn": "415008",
  "facilityName": "Greenwood Operations DBA Greenwood Center",
  "city": "Warwick",
  "state": "RI",
  "zipCode": "02886",
  "certificationDate": "2025-03-06",
  "programParticipation": "SNF/NF Dual Certification",
  "ownershipType": "For Profit - Corporation",
  "ownershipCategory": "For Profit",
  "hospitalBased": false,
  "multiFacilityOrganization": true,
  "chainName": "GENESIS HEALTHCARE",
  "continuingCareRetirementCommunity": false,
  "medicareCensus": 6,
  "medicaidCensus": 78,
  "otherCensus": 25,
  "totalResidents": 109,
  "censusLooksImplausible": false,
  "specialCareBeds": {
    "aids": 0, "alzheimers": 0, "dialysis": 0, "disabledChildrenYoungAdults": 0,
    "headTrauma": 0, "hospice": 0, "huntingtons": 0, "ventilator": 0,
    "otherSpecializedRehab": 0
  },
  "totalSpecialCareBeds": 0,
  "organizedResidentsGroup": true,
  "organizedFamilyMemberGroup": false,
  "conductsExperimentalResearch": false,
  "nurseAideTrainingProgram": false,
  "rnWaiver7DayDate": null,
  "rnWaiver7DayHoursPerWeek": 0,
  "licensedNursing24HrWaiverDate": null,
  "licensedNursing24HrHoursWaivedPerWeek": 0,
  "source": "https://data.cms.gov/data-api/v1/dataset/129a6503-c0f1-4132-b186-4c0232c2d894/data",
  "attribution": "Centers for Medicare & Medicaid Services (CMS)",
  "fetchedAt": "2026-08-23T11:41:55.767Z"
}
```

`ccn` is the CMS Certification Number, the facility's national identifier, and is the natural key: it is unique across all 14,696 records. Counts and censuses arrive as numbers, Yes/No columns as real booleans, and dates as ISO 8601 (`YYYY-MM-DD`). **Unreported values are `null`, never `""` and never `0`** - a facility that did not report a census is distinguishable from one that reported zero. A run summary with the filters applied, row counts and request count is written to the `OUTPUT` key.

### What this dataset does and does not contain

Read this before building on it. Form 671 is a facility characteristics survey, not a bed-inventory or address file:

- **No county and no street address.** CMS publishes city, state and ZIP only. Use `city`, or join on `ccn` against a CMS file that carries addresses.
- **No certified or licensed bed count.** The only capacity figures are the **resident census** (`totalResidents`, plus its Medicare / Medicaid / other split) and the **dedicated special-care-unit beds** in `specialCareBeds`. Census is occupancy on the survey date, which is a good size signal but is not the same as licensed capacity. `minResidents` / `maxResidents` filter on census, and `specialCareUnit` filters on the bed counts that do exist.
- **No special focus facility status.** SFF designation is published by CMS separately, not on Form 671.
- **19 facilities report an impossible census.** In most of them the facility keyed its own CCN into a census column, giving values such as `1,811,702,000`. They are delivered exactly as CMS publishes them rather than silently corrected, and flagged with `censusLooksImplausible: true` (set when `totalResidents` exceeds 2,000; the 99th percentile is 276). Set `maxResidents` to exclude them. The run summary counts them.

### Input

Everything is optional. Run it with no input and you get the first 100 facilities.

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `state` | string | - | Two-letter code, e.g. `TX`. Applied by the CMS API itself, so a state run is one request. |
| `city` | string | - | Case-insensitive substring on the city or town. |
| `ownershipCategory` | enum | - | `For Profit`, `Non-Profit` or `Government`. Exact match. |
| `ownershipType` | string | - | Case-insensitive substring on the detailed type, e.g. `LLC`, `Church Related`. |
| `facilityName` | string | - | Case-insensitive substring on the facility name. |
| `chainName` | string | - | Case-insensitive substring on the chain / affiliated entity, e.g. `Genesis`. |
| `minResidents` / `maxResidents` | integer | - | Inclusive bounds on total resident census. Facilities with no reported census are excluded. |
| `specialCareUnit` | enum | - | Keep only facilities with at least one dedicated bed of this type: `alzheimers`, `ventilator`, `hospice`, `dialysis`, `headTrauma`, `aids`, `huntingtons`, `disabledChildrenYoungAdults`, `otherSpecializedRehab`. |
| `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 row exactly as the API served it. |

Filters combine with AND. Text filters are case-insensitive substring matches.

#### Example inputs

**Every nursing home in one state, for a territory list**:

```json
{
  "state": "FL",
  "maxResults": 1000
}
```

**Large for-profit facilities with a ventilator unit** (specialty vendor prospecting):

```json
{
  "ownershipCategory": "For Profit",
  "specialCareUnit": "ventilator",
  "minResidents": 100,
  "maxResults": 500
}
```

**Every facility in one chain** (enterprise account mapping):

```json
{
  "chainName": "Genesis",
  "maxResults": 500
}
```

### Pricing

**$0.01 per record; you pay only for records delivered.** One charge per dataset item, nothing else. Set `maxResults` and you have set your bill: 100 records is $1.00. Filters are applied before delivery, so a narrow search costs less than a broad one, and a filter that matches nothing costs nothing.

### Data source, refresh and licence

Data comes from the **Centers for Medicare & Medicaid Services (CMS)**, from the same public API the agency's own data viewer uses:

- Dataset: [Long-Term Care Facility Characteristics](https://data.cms.gov/quality-of-care/long-term-care-facility-characteristics)
- API: `https://data.cms.gov/data-api/v1/dataset/129a6503-c0f1-4132-b186-4c0232c2d894/data`
- [Data dictionary](https://data.cms.gov/resources/long-term-care-facility-characteristics-data-dictionary) and [methodology](https://data.cms.gov/resources/long-term-care-facility-characteristics-methodology)

**Refresh:** CMS publishes this dataset **quarterly** (`accrualPeriodicity: R/P3M` in the agency's catalog). The snapshot live on 2026-08-23 covers the period beginning 2026-04-01 and was last modified 2026-07-29. A quarterly or monthly schedule tracks the source; running it daily will mostly re-deliver identical records.

**Licence:** CMS declares the licence for this dataset in its own [data.json](https://data.cms.gov/data.json) catalog as **<https://www.usa.gov/government-works>**, and its access level as `public`. `data.cms.gov/robots.txt` places no restriction on `/data-api/v1/dataset/*` and publishes `Crawl-delay: 10`, which this Actor honors.

**Attribution:** Centers for Medicare & Medicaid Services (CMS). This string ships on every record in the `attribution` field. **This Actor is not affiliated with or endorsed by the Centers for Medicare & Medicaid Services.** No login, API key or account is involved in reading this data.

The Actor sends a descriptive User-Agent (`jserle-apify-actor/ltc-facility-characteristics`), makes its requests sequentially with a ten second gap, never opens parallel connections, and caches nothing between runs. A default run is a single HTTP request.

### Limitations

- **A quarterly snapshot, not a live feed.** Values are as of each facility's most recent annual survey as compiled at the snapshot date, so a certification date or ownership change can be up to a quarter behind reality.
- **Certified long-term care facilities only.** Facilities outside Medicare and Medicaid certification do not appear, and neither do assisted living or independent living communities that are not certified nursing facilities.
- **Fields are as reported by the facility.** CMS publishes Form 671 as submitted. Beyond the 19 flagged census rows, one record reports no ownership type or participation code at all; those arrive as `null`.
- **Ordering is CCN ascending**, the source's own order. There is no "newest first" mode, because the dataset is a registry rather than a feed.
- **No historical quarters.** This Actor reads the current snapshot. CMS keeps prior quarters under separate dataset IDs.

### FAQ

#### How do I get a list of all nursing homes in a state?

Set `state` to the two-letter code and `maxResults` high enough to cover the state. The state filter runs on the CMS API itself, so the run is a single request. Every facility comes back with its CCN, name, city, ZIP, ownership and census.

#### Does this include nursing home ownership data?

Yes: `ownershipCategory` (For Profit, Non-Profit, Government), the detailed `ownershipType` (for example `For Profit - Corporation`, `Church Related`), the `multiFacilityOrganization` flag and the `chainName`. It does not list the individual people or parent entities behind a facility; those are not on Form 671.

#### Does it include the number of beds?

Not certified or licensed beds. Form 671 reports the resident census on the survey date (`totalResidents` with its Medicare, Medicaid and other split) and the dedicated special-care-unit beds (`specialCareBeds`). Use census as the size signal.

#### Can I filter for facilities with a ventilator, dialysis or memory care unit?

Yes. `specialCareUnit` keeps only facilities reporting at least one dedicated bed of that type: `alzheimers`, `ventilator`, `hospice`, `dialysis`, `headTrauma`, `aids`, `huntingtons`, `disabledChildrenYoungAdults` or `otherSpecializedRehab`.

#### Does it include assisted living facilities?

No. Only facilities certified by Medicare or Medicaid as nursing facilities appear in CMS Form 671 data.

#### How current is the data?

CMS publishes the snapshot quarterly. The copy read on 2026-08-23 was last modified 2026-07-29.

### 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 Fines & Civil Money Penalties (CMS) Scraper](https://apify.com/jserle/nursing-home-penalties-fines)
- [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 state or territory code, applied by the CMS API itself so the run stays fast. Examples: TX, CA, NY, PR, GU.

## `city` (type: `string`):

Case-insensitive substring matched against the city or town. Example: BROOKLYN. Note: this dataset publishes city, state and ZIP, but no county and no street address.

## `ownershipCategory` (type: `string`):

The broad ownership class, matched exactly. Derived from the CMS ownership type: 'For Profit - LLC' has the category 'For Profit'.

## `ownershipType` (type: `string`):

Case-insensitive substring matched against the detailed CMS ownership type. Examples: LLC, Corporation, Church Related, Government - County, Individual, Partnership.

## `facilityName` (type: `string`):

Case-insensitive substring matched against the facility name. Example: rehabilitation

## `chainName` (type: `string`):

Case-insensitive substring matched against the multi-facility organization name, which is the chain or affiliated entity a facility belongs to. Examples: Genesis, Life Care Centers, PACS, Trilogy.

## `minResidents` (type: `integer`):

Keep facilities whose total resident census is at least this. This dataset reports resident census, not licensed or certified bed count; see the README. Facilities with no reported census are excluded.

## `maxResidents` (type: `integer`):

Keep facilities whose total resident census is at most this. Useful for excluding the handful of rows where a facility mis-keyed its census (see censusLooksImplausible).

## `specialCareUnit` (type: `string`):

Keep only facilities reporting at least one dedicated bed of this type. This is the bed-count dimension the dataset actually publishes.

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

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

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

Attach a `raw` object holding the CMS row exactly as the API served it, under its original column names. Useful for auditing the normalization; roughly doubles item size.

## Actor input object example

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

# Actor output Schema

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

One item per certified long-term care facility delivered by this run.

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

Source URLs, filters applied, row counts, 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 = {
    "state": "",
    "maxResults": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("jserle/ltc-facility-characteristics").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 = {
    "state": "",
    "maxResults": 100,
}

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jserle/ltc-facility-characteristics"
        }
    }
}

```

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/pqFoxhut6kFyUdRxv/builds/aDRuMHmwLJf6OZop9/openapi.json
