# PracticeLink Scraper (`crawlerbros/practicelink-scraper`) Actor

Scrape PracticeLink - 27K+ physician, NP/PA and healthcare jobs in the US. Search by keyword, location, state and specialty, or fetch full job details (description, employer, education requirements, visa commitments) by ID or URL.

- **URL**: https://apify.com/crawlerbros/practicelink-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## PracticeLink Scraper

Scrape **PracticeLink** — the leading US physician-recruitment job board with 27K+ active physician, NP/PA and healthcare jobs. Search by keyword, location, state and specialty, or fetch full job details (employer, description, education requirements, visa commitments, direct-apply status) by job ID or URL. HTTP-only via the public jobs.practicelink.com site. No auth, no proxy.

### What this actor does

- **Three modes:** `search`, `byId`, `byUrl`
- **Rich filters:** keyword, location, state, specialty, profession, practice type, employment type, recruitment type, loan assistance, immigration assistance, telemedicine, sort order
- **Search cards:** facility, parent organization, location, specialty, employment type, recruitment type
- **Full detail records:** JSON-LD structured data with employer, address, education requirements, visa commitments
- **Empty fields are omitted**

### Output per job (mode = `search`)

- `jobId`, `title`
- `facility`, `parentOrganization`, `location` (e.g. `Page, AZ`)
- `categories[]`, `specialty`, `employmentType`
- `recruitmentType` — `Employer Direct`, `Recruiter` or `Search Firm`
- `url`, `sourceUrl`

### Output per job (mode = `byId` / `byUrl`)

- `jobId`, `title`
- `description` — full job description (HTML stripped to text)
- `datePosted`, `validThrough`
- `employmentType` (FULL\_TIME / PART\_TIME / ...), `employmentTypePage`
- `telemedicine` — true/false when the page states it
- `city`, `state`, `postalCode`, `country`
- `hiringOrganization`, `hiringOrganizationUrl`, `hiringOrgLogoUrl`
- `educationRequirements[]`, `occupationalCategory`
- `specialCommitments` — e.g. `Accepts U.S. J1 & H1B Visas`
- `directApply` — whether the employer accepts direct applications
- `industry[]`, `postedBy`
- `practicelinkUrl`, `sourceUrl`, `recordType: "job"`, `scrapedAt`

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `search` | `search` / `byId` / `byUrl` |
| `searchQuery` | string | `family medicine` | Free-text keyword (mode=search) |
| `location` | string | – | City/region, e.g. `Chicago`, `Texas` (mode=search) |
| `state` | enum | – | US state/territory (e.g. `TX`) |
| `specialty` | enum | – | Full 204-value specialty taxonomy (e.g. `Family Medicine`, `Hospitalist`) |
| `sortBy` | enum | `relevance` | `relevance` / `verified_date_asc` / `verified_date_desc` |
| `employmentType` | enum | – | `Not Specified` / `Full-Time` / `Part-Time` / `Contract` / `Internship` / `Temporary` / `Locum Tenens` / `Other` / `Seasonal` |
| `recruitmentType` | enum | – | `Employer Direct` / `Recruiter` / `Search Firm` |
| `profession` | enum | – | Full profession taxonomy (e.g. `Physician`, `CRNA`, `Nurse Practitioner`) |
| `practiceType` | enum | – | Practice setting (e.g. `Group Practice`, `Hospital Employee`, `Locum Tenens`) |
| `loanAssistance` | enum | – | `Yes` / `No` / `Negotiable` |
| `immigrationAssistance` | enum | – | Visa support (e.g. `Accepts U.S. J1 & H1B Visas`) |
| `telemedicine` | enum | – | `Yes` / `No` |
| `jobIds` | array | – | Job IDs (mode=byId) |
| `startUrls` | array | – | Job detail URLs (mode=byUrl) |
| `postedWithinDays` | int | – | Only jobs posted within N days (detail records) |
| `containsKeyword` | string | – | Substring filter on title/organization/city/state |
| `maxItems` | int | `50` | Hard cap (1–1000) |

#### Example: family medicine jobs in Texas

```json
{
  "mode": "search",
  "searchQuery": "family medicine",
  "location": "Texas",
  "maxItems": 50
}
```

#### Example: hospitalist jobs in a state, newest first

```json
{
  "mode": "search",
  "specialty": "Hospitalist",
  "state": "TX",
  "sortBy": "verified_date_desc",
  "maxItems": 100
}
```

#### Example: full details for specific jobs

```json
{
  "mode": "byId",
  "jobIds": ["1481516", "1597926"]
}
```

#### Example: lookup by URL

```json
{
  "mode": "byUrl",
  "startUrls": [
    {"url": "https://jobs.practicelink.com/jobs/1481516/urgent-care/nurse-practitioner/illinois/ocuc-bradford/"}
  ]
}
```

### Use cases

- **Physician recruiters** — monitor competitor postings by specialty, state and facility
- **Healthcare staffing** — pipeline of open NP/PA and physician roles with direct-apply status
- **Job seekers** — track verified-date-sorted postings in target states and specialties
- **Provider compensation research** — collect `specialCommitments`, requirements and employment types
- **Hospital systems** — benchmark recruiting mix (Employer Direct vs agency)

### FAQ

**What is PracticeLink?**  A US physician-recruitment job board listing 27K+ active jobs across all 50 states, covering physicians, NPs, PAs and allied healthcare roles.

**Are there rate limits?**  No documented hard cap. The actor uses small polite delays and retries on 429/5xx.

**What is `recruitmentType`?**  Whether the job was posted directly by the employer (`Employer Direct`), by a recruiter (`Recruiter`) or by a search firm/agency (`Search Firm`).

**What does `specialCommitments` mean?**  PracticeLink's shorthand for visa support — e.g. `Accepts U.S. J1 & H1B Visas`.

**Why do search-mode records have fewer fields than detail records?**  Search results are listing cards; the rich fields (description, employer, requirements) live on the detail page. Use `byId`/`byUrl` (or `containsKeyword` + a follow-up pass) for full records.

**How fresh is the data?**  Live — every run queries PracticeLink in real time.

**Is this affiliated with PracticeLink?**  No. This is an independent third-party actor using the public website.

# Actor input Schema

## `mode` (type: `string`):

What to fetch.

## `searchQuery` (type: `string`):

Free-text keyword, e.g. `family medicine`, `nurse practitioner` (mode=search).

## `location` (type: `string`):

City, region or keyword-based location, e.g. `Chicago`, `Texas` (mode=search).

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

Restrict results to a US state or territory (mode=search).

## `specialty` (type: `string`):

PracticeLink specialty filter - full site taxonomy (mode=search).

## `profession` (type: `string`):

PracticeLink profession filter, e.g. Physician, CRNA, Nurse Practitioner (mode=search).

## `practiceType` (type: `string`):

Practice setting filter, e.g. Group Practice, Hospital Employee, Locum Tenens (mode=search).

## `sortBy` (type: `string`):

Sort order for search results (mode=search).

## `employmentType` (type: `string`):

Employment type filter (mode=search).

## `recruitmentType` (type: `string`):

Only emit jobs posted directly by the employer vs. by a recruiter vs. by a search firm.

## `loanAssistance` (type: `string`):

Only emit jobs with this loan-assistance flag (mode=search).

## `immigrationAssistance` (type: `string`):

Only emit jobs accepting these visa types (mode=search).

## `telemedicine` (type: `string`):

Only emit jobs offering telemedicine (mode=search).

## `jobIds` (type: `array`):

PracticeLink job IDs, e.g. `1481516`.

## `startUrls` (type: `array`):

Job detail URLs, e.g. `https://jobs.practicelink.com/jobs/1481516/...`.

## `postedWithinDays` (type: `integer`):

Only emit jobs posted within this many days (applies to detail records).

## `containsKeyword` (type: `string`):

Only emit jobs whose title, organization, city or state contains this text (case-insensitive).

## `maxItems` (type: `integer`):

Hard cap on emitted records.

## Actor input object example

```json
{
  "mode": "search",
  "searchQuery": "family medicine",
  "state": "",
  "specialty": "",
  "profession": "",
  "practiceType": "",
  "sortBy": "relevance",
  "employmentType": "",
  "recruitmentType": "",
  "loanAssistance": "",
  "immigrationAssistance": "",
  "telemedicine": "",
  "jobIds": [],
  "maxItems": 50
}
```

# Actor output Schema

## `jobs` (type: `string`):

Dataset containing all scraped PracticeLink jobs.

# 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 = {
    "mode": "search",
    "searchQuery": "family medicine",
    "state": "",
    "specialty": "",
    "profession": "",
    "practiceType": "",
    "sortBy": "relevance",
    "employmentType": "",
    "recruitmentType": "",
    "loanAssistance": "",
    "immigrationAssistance": "",
    "telemedicine": "",
    "jobIds": [],
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/practicelink-scraper").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 = {
    "mode": "search",
    "searchQuery": "family medicine",
    "state": "",
    "specialty": "",
    "profession": "",
    "practiceType": "",
    "sortBy": "relevance",
    "employmentType": "",
    "recruitmentType": "",
    "loanAssistance": "",
    "immigrationAssistance": "",
    "telemedicine": "",
    "jobIds": [],
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/practicelink-scraper").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 '{
  "mode": "search",
  "searchQuery": "family medicine",
  "state": "",
  "specialty": "",
  "profession": "",
  "practiceType": "",
  "sortBy": "relevance",
  "employmentType": "",
  "recruitmentType": "",
  "loanAssistance": "",
  "immigrationAssistance": "",
  "telemedicine": "",
  "jobIds": [],
  "maxItems": 50
}' |
apify call crawlerbros/practicelink-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=crawlerbros/practicelink-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/rQOPDjOqM1OheVE5m/builds/dFxDYBgqkb3fHk2b2/openapi.json
