# 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
- **Features:** Limited permissions
- **Stats:** 2 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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.org Jobs, Volunteering & Nonprofit 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)
- [Strengths and limits](#strengths-and-limits)
- [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.

### ⚖️ Strengths and limits

Read this before you run a big job, so you know exactly what you get.

**Strengths**

- **Three datasets from one actor:** paid nonprofit jobs, volunteer opportunities and the organization directory.
- **Salary and location fields as structured data** where Idealist has them, plus the listing description.
- **Fast and light.** Idealist's own search index, no login, no proxy; a default run takes about 5 seconds.

**Limits**

- **Big selections need your go-ahead.** A selection of up to 5,000 results comes back complete, which covers all paid
  jobs (about 2,500). Volunteer opportunities (about 108,000, about $540 at $5 per 1,000 on the free plan) and organizations
  (about 235,000, about $1,175) are much bigger, so a run stops at the newest 1,000 and says so, unless you set Max results to 5,000 or
  less or turn on `fullExport`. Set a spending limit for a full export.
- **We haven't run a whole big data type end to end.** Our tests stopped at about 18,000 rows (our own spending cap) at
  about 500 rows per second. A date-by-date count matched the totals above, and every sampled date range came back exact.
- **Result counts are rough on big selections.** Idealist's search can be far off in either direction (it reported about
  286,000 volunteer opportunities and 43,000 organizations), so the count in the log is only a rough figure.
- **Incremental mode needs a complete run.** `change_type` and delistings only work for a selection the run covers
  completely: all jobs, or a big data type with `fullExport`. A run stopped at the newest 1,000 doesn't update the memory.
- **Mostly the US.** About 94% of jobs and most volunteer opportunities are in the US. Idealist also has far fewer paid
  jobs than volunteer listings.
- **Salary isn't always there.** `has_salary: false` when Idealist doesn't have it.
- **Keyword only.** There are no input filters for location, focus area or job type; filter the output yourself.
- **It depends on Idealist's search index.** If Idealist changes it, the actor stops working until it's updated. Not
  affiliated with Idealist.

### 📋 Output

One dataset item per job, volunteer opportunity, or organization (see
the **Output** tab 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

Key parameters (the **Input** tab lists every option):

| Parameter | Type | Default | Description |
|---|---|---|---|
| `entityType` | String | `jobs` | `jobs`, `volunteerOpportunities`, or `organizations`. |
| `query` | String | *(empty)* | Optional free-text keyword search (e.g. `"nurse"`, `"climate"`). Empty = the whole data type. |
| `maxItems` | Integer | `50` | Stop after pushing this many items. Clear it (`null`) for everything; see `fullExport`. |
| `maxPages` | Integer | *(unlimited)* | Cap on result pages walked, if you want a partial sample. |
| `fullExport` | Boolean | `false` | Needed for an uncapped run of more than 5,000 results. Billed per row, so this can cost $500–$1,200. Without it, such a run returns the newest 1,000. |
| `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"
}
```

**Volunteer opportunities for a keyword:**

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

**The whole organization directory (about 235,000 rows, about $1,175), scheduled tracking run:**

```json
{
  "entityType": "organizations",
  "mode": "incremental",
  "fullExport": true,
  "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) — with `maxItems` cleared, the first run pushes everything (`full`); later runs push
  only `new`/`changed`/`delisted`. A capped run is a preview and always returns rows.
- A `query`-filtered, capped or page-capped run doesn't cover the full scope, so it never updates the
  baseline or reports delistings. Neither does a run stopped at the newest 1,000.

### 🚀 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 everything (big data types also need `fullExport`).
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.

### Feedback and reviews

Missing a field or hit a problem? Open an issue on the **Issues** tab: issues are answered promptly.

If this Actor is useful to you, please leave a short review on this page. Reviews help other people find it and
help decide what to improve next. Thank you!

### Related jobs data scrapers

- [Career Site Jobs Scraper](https://apify.com/artsiom_k/career-site-jobs-scraper) — 190,000+ jobs from company career sites (Greenhouse, Ashby, Lever, Workable), filtered by title, country, remote and salary.
- [USAJobs Scraper](https://apify.com/artsiom_k/usajobs-scraper) — US federal government jobs with agency, grade, salary and hiring path.
- [GovernmentJobs Scraper](https://apify.com/artsiom_k/governmentjobs-scraper) — US state, county and city government jobs from GovernmentJobs.com.
- [US Teaching Jobs Scraper](https://apify.com/artsiom_k/us-teaching-jobs-scraper) — K-12 school jobs from SchoolSpring and EdJoin with salary, district and contacts.

### 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.

## `fullExport` (type: `boolean`):

Allow a run to return everything when your selection has more than 5,000 results (about 108,000 volunteer opportunities and 235,000 organizations; at the per-row price that can cost $500 to $1,200, so set a spending limit). Without it, such a run returns the newest 1,000 unless Max results is 5,000 or less.

## `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,
  "fullExport": false,
  "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/qpisRBYPfJzOKbnAC/openapi.json
