# Idealist.org Jobs, Volunteering & Nonprofit Scraper (`artsiom_k/idealist-scraper`) Actor

Scrape Idealist.org nonprofit-sector jobs, volunteer opportunities, and the organization directory, with built-in delta mode. No login required.

- **URL**: https://apify.com/artsiom\_k/idealist-scraper.md
- **Developed by:** [Artsiom Kunitsyn](https://apify.com/artsiom_k) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 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/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

## idealist-scraper

Scrapes [Idealist.org](https://www.idealist.org), the leading nonprofit/social-impact jobs and
volunteering platform — paid jobs, volunteer opportunities, and the organization/nonprofit
directory, all from the site's own public search index. No login, no API key.

### Contents

- [Key features](#key-features)
- [Output](#output)
- [Input](#input)
- [Input examples](#input-examples)
- [Incremental (delta) mode](#incremental-delta-mode)
- [How to scrape Idealist.org](#how-to-scrape-idealistorg)
- [FAQ](#faq)

### 🔑 Key features

- **Three entity types, one actor.** `jobs` covers paid nonprofit-sector postings, `volunteerOpportunities`
  covers Idealist's (much larger) volunteering board, and `organizations` covers the nonprofit/org
  directory itself — mission, focus areas, location, whether it's currently hiring or seeking
  volunteers.
- **No login, no private endpoint.** Idealist's own search runs through a public, read-only search
  index; this actor queries that directly instead of scraping rendered HTML pages.
- **Delta mode built in.** Every run classifies each result as `new`, `changed`, `unchanged`, or
  `delisted` against a persisted baseline, so a scheduled re-run only bills for what actually changed.

### 📋 Output

One dataset item per job, volunteer opportunity, or organization (see
[`.actor/dataset_schema.json`](.actor/dataset_schema.json) for the full field list) plus a
`change_type` field.

**Example — job:**

```json
{
  "source": "idealist",
  "external_id": "0584eb9326e540349dab0c670ca1ce17",
  "entity_type": "jobs",
  "url": "https://www.idealist.org/en/job/...",
  "name": "Program Manager",
  "org_name": "Smith Community Health",
  "org_type": "NONPROFIT",
  "city": "Georgetown",
  "state": "TX",
  "country": "US",
  "location_type": "ONSITE",
  "remote_ok": false,
  "areas_of_focus": ["HEALTH_MEDICINE"],
  "job_type": ["FULL_TIME"],
  "has_salary": true,
  "salary_minimum": 48000.0,
  "salary_maximum": 55000.0,
  "salary_period": "YEAR",
  "salary_currency": "USD",
  "published_at": "2026-09-01T00:00:00+00:00",
  "change_type": "new"
}
```

**Example — organization:**

```json
{
  "source": "idealist",
  "external_id": "org-4821",
  "entity_type": "organizations",
  "name": "Smith Community Health",
  "org_type": "NONPROFIT",
  "mission": "Providing free clinical care to underserved families.",
  "city": "Georgetown",
  "state": "TX",
  "country": "US",
  "areas_of_focus": ["HEALTH_MEDICINE"],
  "hiring": true,
  "seeking_volunteers": true,
  "change_type": "new"
}
```

**Known gaps:**

- Not every job posting has salary data — `has_salary: false` when Idealist itself doesn't have it,
  rather than guessing.
- `latitude`/`longitude` are only present when the listing has a specific physical location; a
  fully remote posting leaves them `null`.

### ⚙️ Input

See [`.actor/input_schema.json`](.actor/input_schema.json) for the full schema. Key parameters:

| Parameter | Type | Default | Description |
|---|---|---|---|
| `entityType` | String | `jobs` | `jobs`, `volunteerOpportunities`, or `organizations`. |
| `query` | String | *(empty)* | Optional free-text keyword search (e.g. `"nurse"`, `"climate"`). Empty returns the full scope. |
| `maxItems` | Integer | `50` | Stop after pushing this many items. Clear it (`null`) for a full run. |
| `maxPages` | Integer | *(unlimited)* | Cap on result pages walked, if you want a partial sample. |
| `mode` | String | `auto` | `auto`/`full`/`incremental` — see [Incremental mode](#incremental-delta-mode). |
| `impersonate` | String | `chrome` | curl\_cffi TLS-impersonation target. |
| `proxyConfiguration` | Object | off | Apify Proxy config. Off by default — clean without one in testing. |

### 🧪 Input examples

**Quick preview** — default 50-item cap on job postings:

```json
{
  "entityType": "jobs"
}
```

**Full volunteer-opportunity scan, filtered by keyword:**

```json
{
  "entityType": "volunteerOpportunities",
  "query": "climate",
  "maxItems": null
}
```

**Organization directory, scheduled tracking run:**

```json
{
  "entityType": "organizations",
  "mode": "incremental",
  "maxItems": null
}
```

### 🔄 Incremental (delta) mode

Every run classifies each result as `new`, `changed`, `unchanged`, or `delisted`, against a
baseline persisted per `entityType`.

- `mode: auto` (default) — first run pushes everything (`full`); later runs push only
  `new`/`changed`/`delisted`.
- A `query`-filtered or page-capped run doesn't cover the full scope, so it never updates the
  baseline or reports delistings — same rule as every other actor in this collection.

### 🚀 How to scrape Idealist.org

1. Open the actor in Apify Console and go to the **Input** tab.
2. Pick an **entityType** — `jobs`, `volunteerOpportunities`, or `organizations`.
3. `maxItems` defaults to 50 (a quick preview) — clear it for a full run.
4. Click **Start**.
5. Browse results in the **Output** tab, or download as JSON/CSV/Excel, or pull them via the API.

### ❓ FAQ

**Is it legal to scrape Idealist.org?** It's legal to collect publicly available job, volunteering,
and organization listing data. Results may contain limited personal/organizational contact
information; scrape it only with a legitimate purpose under GDPR.

**What's the difference between `jobs` and `volunteerOpportunities`?** Idealist's own platform
distinguishes paid positions from volunteer roles — this actor keeps that distinction rather than
merging them into one undifferentiated feed.

**Does this need a login or API key?** No — Idealist's own search index is publicly reachable.

### Search keywords

idealist scraper, idealist.org scraper, nonprofit jobs scraper, social impact jobs, volunteer
opportunities scraper, nonprofit organization directory, nonprofit job board data, NGO jobs feed,
social impact hiring data, nonprofit lead generation

# Actor input Schema

## `entityType` (type: `string`):

Which content type to scrape: paid Jobs, Volunteer opportunities (the platform's largest content type), or the Organization/nonprofit directory.

## `query` (type: `string`):

Optional keyword filter (e.g. "nurse", "education"). Leave empty to scrape everything of the selected data type. Narrows the run's scope, so delisted-item detection and the incremental baseline are skipped for a filtered run.

## `maxPages` (type: `integer`):

Safety cap on result pages fetched (100 items/page). Leave empty to paginate to completion. A capped run cannot detect delisted items and does not update the incremental-mode baseline.

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

Stop after pushing this many dataset items. Defaults to 50 — a fast, cheap preview. Raise it or clear it (set to null) for a full run.

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

"auto" (recommended): full scan on the first run for a given scope, incremental (new/changed only) afterwards. "full": always push every item and refresh the baseline. "incremental": always push only new/changed items.

## `impersonate` (type: `string`):

Advanced: the curl\_cffi browser fingerprint to impersonate. Leave as default unless you're diagnosing a block.

## `proxyConfiguration` (type: `object`):

Apify Proxy configuration. Not required for this site — no anti-bot layer found.

## Actor input object example

```json
{
  "entityType": "jobs",
  "query": "",
  "maxItems": 50,
  "mode": "auto",
  "impersonate": "chrome",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("artsiom_k/idealist-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("artsiom_k/idealist-scraper").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 '{}' |
apify call artsiom_k/idealist-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,artsiom_k/idealist-scraper"
        }
    }
}
```

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/AZHeh2TrZhhjbxP3P/builds/2AOfd9RAdYft2MF8E/openapi.json
