# Idealist Search Scraper (`jobsapi/idealist-jobs-search-scraper`) Actor

Scrape job listings from Idealist.org, the leading job board for nonprofit and social impact careers. Extract job titles, organizations, locations, cause areas, and descriptions for social impact recruitment.

- **URL**: https://apify.com/jobsapi/idealist-jobs-search-scraper.md
- **Developed by:** [Jobs API](https://apify.com/jobsapi) (community)
- **Categories:** Jobs, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.99 / 1,000 idealist job records

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

### What does Idealist Search Scraper do?

This Apify Actor collects publicly listed nonprofit and social-impact jobs from [Idealist.org](https://www.idealist.org/en/jobs). It follows a bounded set of official detail pages and emits one enriched dataset record per complete job. It uses ordinary direct access only; it does not access candidate accounts, submit applications, fetch application destinations, or bypass access controls.

### Why use Idealist Search Scraper?

Use it to collect a bounded set of public job facts in one dataset, including organization, location, employment details, dates, descriptions, and public application links when Idealist exposes them. Search pages and detail candidates are capped, and browser requests are processed sequentially. The public input has no proxy setting: schema-valid runs use direct access to Idealist pages.

### What data can Idealist Search Scraper extract?

The dataset schema describes more than 20 useful fields that may be populated from the public listing, detail page, or embedded JobPosting data. Job facts come from those public surfaces; the table marks normalized and Actor-generated metadata separately. Optional source-dependent fields are omitted when Idealist does not publish them. This field inventory is not a promise that every Idealist posting publishes every value.

| Field | Type | Meaning |
|---|---|---|
| `jobId` | string | Idealist identifier, or the canonical job URL when no identifier is available. |
| `resultIndex` | integer | Search-candidate order assigned by the Actor. |
| `title` | string | Public job title. |
| `organization` | string or null | Organization name. |
| `organizationUrl` | URL or null | Public Idealist organization page, when present. |
| `organizationLogo` | URL or null | Published organization logo URL, when present. |
| `listingType` | string | Listing category inferred from the official Idealist job URL path. |
| `contractType` | string or null | Public employment-type label. |
| `employmentTypes` | string array | Employment-type values retained from public JobPosting data. |
| `experienceLevel` | string or null | Published experience-level text. |
| `education` | string or null | Published education requirement. |
| `compensation` | string or null | Public salary or compensation text. |
| `listingCompensation` | string | Compensation text specifically from the listing card. |
| `detailCompensation` | string | Compensation text specifically from the labeled job detail. |
| `salary` | object, string, or number | Public salary data retained in the form supplied by JobPosting content. |
| `salaryMin` | number | Minimum salary value parsed from published salary data. |
| `salaryMax` | number | Maximum salary value parsed from published salary data. |
| `salaryCurrency` | string | Published currency when available. |
| `salaryUnit` | string | Published salary period normalized to `year`, `month`, or `hour`. |
| `location` | string, object, or null | Public location text or structured address. |
| `fullAddress` | string or null | Readable address normalized from public location fields. |
| `locationCity` | string | City/locality from public location data. |
| `locationRegion` | string | State, province, or region from public location data. |
| `locationCountry` | string | Country from public structured location data. |
| `postalCode` | string | Postal code from public structured location data. |
| `locationMode` | string or null | Public remote, hybrid, or on-site wording when available. |
| `locationSentence` | string or null | Location sentence supplied by the page extractor. |
| `isRemote` | boolean | Derived only when public location mode explicitly indicates remote or on-site work; omitted when ambiguous (for example, hybrid). |
| `causeAreas` | string array | Public cause-area labels, when available. |
| `postedDate` | string or null | Public posted date or label. |
| `startDate` | string | Published job start date from the detail page or JobPosting data. |
| `publishedDate` | string or null | Date portion normalized from the posted-date value. |
| `publishedSince` | string or null | Relative posting-age label from the listing card. |
| `closingDate` | string or null | Published application deadline or JobPosting valid-through date. |
| `description` | string | Readable public job description. |
| `descriptionHtml` | string or null | HTML for the public description section. |
| `descriptionFields` | object | Public description headings and labeled facts extracted from the page. |
| `sections` | object | Relevant public detail-page sections keyed by normalized heading; related-job/footer content is excluded. |
| `benefits` | string | Visible benefits text when published. |
| `responsibilities` | string | Visible responsibilities text when published. |
| `qualifications` | string | Visible qualifications text when published. |
| `educationRequirements` | string | Published education requirement text. |
| `experienceRequirements` | string | Published experience requirement text. |
| `languageRequirements` | string | Published language requirements or preferences. |
| `programAreas` | string array | Program/project areas explicitly named in the public description. |
| `scheduleRequirements` | string | Published schedule or evening/weekend requirements. |
| `transportRequirements` | string | Published travel or transportation requirements. |
| `programScope` | string | Visible program-scope section, when present. |
| `leadership` | string | Visible leadership section, when present. |
| `educationExpertise` | string | Visible education-expertise section, when present. |
| `applicationInstructions` | string | Visible How to Apply instructions. |
| `industry` | string | Industry from public JobPosting data, when present. |
| `occupationalCategory` | string | Occupational category from public JobPosting data, when present. |
| `jobCategory` | string | Public detail-page or JobPosting category, when present. |
| `workHours` | string | Published work-hours value, when present. |
| `skills` | string array | Skill labels when supplied by the page extractor. |
| `application` | object | Public application metadata such as a visible external application link and label. |
| `directApply` | boolean | Included only when Idealist or JobPosting data publishes an explicit boolean. |
| `applyUrl` | URL or null | Public application URL when found; the destination is not fetched. |
| `applicationHost` | string | Hostname parsed from the public application URL. |
| `jobUrl` | URL | Canonical public Idealist job-detail page. |
| `listingUrl` | URL | Public search/listing page from which the card was collected. |
| `source` | string | Fixed source label, `idealist.org`. |
| `searchData` | object | Listing-card text and visible labels retained for context. |
| `sourceData` | object | Public JobPosting data and labeled detail fields retained by the mapper. |
| `scrapedAt` | date-time | Actor-generated record timestamp. |

Most job facts come directly from Idealist's public page content. `isRemote` and `publishedDate` are normalized from public values; `resultIndex` and `scrapedAt` are Actor metadata. Listing and detail compensation are kept separately when both are published. A location phrase is passed to Idealist, but the Actor does not independently filter geographic results; the site may return a broader or differently ranked result set than a separate browser view. The raw description is kept separately from the structured `sections` and `sourceData` fields.

### How to scrape Idealist jobs

1. Open the Actor's Input tab.
2. Enter a required job query. Optionally set a location phrase, result cap, search-page cap, timeout, or an official Idealist `/en/jobs` URL override.
3. Start the run and review the dataset. `OUTPUT` contains counts, diagnostics, and bounded direct-request receipts; `RUN_HEALTH` contains the compact run status.

### How much will it cost to scrape Idealist?

Apify charges depend on the account plan and the resources used during a run; this Actor does not set a fixed price. Browser navigation, the number of search pages, and opening detail pages affect runtime. Raising `maxItems` can inspect up to five extra detail candidates beyond the requested record count when a public detail is incomplete. Requests are sequential and have no retries; a transport failure stops further navigation and records `DEFERRED`.

### Inputs

See the Input tab for the complete configuration. `query` is required; `startUrl`, when supplied, replaces the search URL generated from `query` and `location`.

- `query`: required search terms, 1–200 characters, default `program manager`
- `location`: optional location phrase, default `United States`, at most 200 characters; passed to Idealist when `startUrl` is omitted, but not independently enforced by the Actor
- `maxItems`: maximum enriched records, 1–100, default 3
- `maxDetailPages`: maximum official search pages, 1–5, default 2
- `timeoutSecs`: navigation timeout, 20–120 seconds, default 60; the handler timeout is derived from this value
- `startUrl`: optional HTTPS `https://www.idealist.org/en/jobs` or `https://idealist.org/en/jobs` URL override; it replaces the generated search URL

The public schema does not expose `proxyConfiguration`. Search and detail pages are accessed directly.

Quick search:

```json
{
  "query": "program manager",
  "location": "United States",
  "maxItems": 3,
  "maxDetailPages": 2,
  "timeoutSecs": 60
}
```

Search with a public Idealist URL override:

```json
{
  "query": "program manager",
  "location": "United States",
  "startUrl": "https://www.idealist.org/en/jobs?q=program+manager&l=United+States",
  "maxItems": 5,
  "maxDetailPages": 3,
  "timeoutSecs": 60
}
```

### Output

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

Each dataset record contains the job ID, title, organization, official job URL, location, contract and compensation fields where available, description, structured sections, application information, source data, and scrape timestamp. Required fields are `jobId`, `title`, `description`, `jobUrl`, `source`, and `scrapedAt`.

Representative abbreviated record emitted by the Actor (description shortened; optional source fields omitted). The run's `United States` location phrase did not match its India-based result cards, so this example demonstrates the record shape only; location relevance remains unqualified.

```json
{
  "jobId": "ffc768cc03b84f5dbe277cb3f921f2ae",
  "title": "ET Admin Manager + Secretary",
  "organization": "Empower Tamizhagam",
  "contractType": "Full Time",
  "employmentTypes": ["FULL_TIME"],
  "location": {
    "@type": "PostalAddress",
    "addressLocality": "Chennai",
    "addressRegion": "TN",
    "addressCountry": "IN"
  },
  "locationMode": "On-site",
  "isRemote": false,
  "experienceRequirements": "2-7 years of experience",
  "programAreas": ["Small Business & Startups", "Public Policy", "CSR Funding", "Project Mgmt"],
  "description": "ONLY CANDIDATES CURRENTLY BASED IN CHENNAI, INDIA ...",
  "jobUrl": "https://www.idealist.org/en/nonprofit-job/ffc768cc03b84f5dbe277cb3f921f2ae-et-admin-manager-secretary-empower-tamizhagam-chennai",
  "listingUrl": "https://www.idealist.org/en/jobs?q=program+manager&l=United+States",
  "source": "idealist.org",
  "scrapedAt": "2026-09-23T04:57:28.523Z"
}
```

The following abbreviated `OUTPUT` excerpt illustrates the current status contract; it is not a rewrite of the preserved 2026-09-23 run summary, which predates `resultStatus`:

```json
{
  "status": "SUCCEEDED",
  "resultStatus": "COMPLETE",
  "requestedItems": 3,
  "items": 3,
  "searchCandidates": 8,
  "searchPagesProcessed": 1,
  "queuedDetails": 3,
  "detailAttempts": 3,
  "detailSuccesses": 3,
  "detailFailures": 0,
  "requestFailures": 0,
  "searchesRequested": 1,
  "emptySearchesConfirmed": 0,
  "blocked": false,
  "accessMode": "direct",
  "proxyUsed": false,
  "diagnostics": []
}
```

The default key-value store exposes `OUTPUT` (platform `status`, separate `resultStatus`, requested and emitted counts, search/detail counters, `accessMode: "direct"`, `proxyUsed: false`, bounded diagnostics, and request receipts) and `RUN_HEALTH` (the same status split plus compact health fields). Platform `status` is only `SUCCEEDED` or `FAILED`; `resultStatus` is `COMPLETE`, `LIMITED`, `SKIPPED`, `DEFERRED`, `NO_DATA`, or `FAILED`. An access boundary is `SKIPPED` only when its final response/page is confirmed on the official Idealist origin; requests stop and buffered records are discarded. A denial or challenge after an off-origin redirect is `DEFERRED`, not attributed to Idealist. Generic transport, ambiguous empty-page, and unverified parse outcomes are `SUCCEEDED` / `DEFERRED` when no records were stored. Genuine rows stored before a later error or access boundary remain `SUCCEEDED` / `LIMITED`. `NO_DATA` requires affirmative official empty-result text and zero visible job cards for every requested search, recorded in the search receipts and the `searchesRequested` / `emptySearchesConfirmed` counters. A fatal zero-row failure is `FAILED` / `FAILED` and uses the Actor failure lifecycle. Diagnostics and request receipts are written only to the key-value store, never as dataset rows.

### Tips and advanced options

- Increase `maxDetailPages` to inspect more search pages, or increase `maxItems` to request more enriched records. Both settings increase browser work.
- `maxDetailPages` caps search pagination; detail requests are separately bounded by the requested item count plus a small candidate allowance.
- Use `startUrl` when you already have a public Idealist search URL. The URL must use HTTPS and the `/en/jobs` path.
- The Actor's public input supports direct access only and has no proxy option. Do not change routes, identities, cookies, or browser fingerprints to continue after an access barrier.
- Records omit optional values that Idealist does not publish. Missing values are not inferred as facts about the job.

### FAQ, support, and responsible use

**What if the result has no jobs?** `NO_DATA` is used only when every requested search explicitly reports an empty result on the successful official Idealist page. Missing cards, unrecognized empty pages, and incomplete detail parsing are `DEFERRED`; check the search evidence, counters, and diagnostics in `OUTPUT`.

**What if Idealist displays a CAPTCHA, human check, or access-denial page?** The Actor stops requests, discards buffered rows, and records the run as `SKIPPED` with an access-boundary diagnostic. Do not try another identity, proxy, cookie set, or route to get around it.

**What if a request times out or the browser cannot load a page?** The Actor stops further requests and records `DEFERRED` with a request receipt; it does not retry or switch routes/browsers.

**Where can I report an issue?** Use the Actor's Issues tab and include the run ID and a short description of the behavior. The API tab provides programmatic access to the Actor and its stored output.

This Actor is not affiliated with Idealist. Collect only public job information. Respect Idealist.org terms, robots directives, rate limits, and applicable law. Do not collect candidate data, access authenticated pages, solve CAPTCHAs, or bypass paywalls and access controls. Public job pages can still contain personal information; use a lawful basis and consult qualified counsel if unsure.

### Local run

For a local run from PowerShell, start in the repository root and use a new actor-relative storage directory. The command below checks that the path does not already exist, uses `--resurrect`, and avoids purging or reusing a prior dataset:

```powershell
Set-Location .\idealist-jobs-search-scraper
$storagePath = 'storage-idealist-local-run'
if (Test-Path -LiteralPath $storagePath) {
  throw "Choose a new storage path; $storagePath already exists."
}
$env:APIFY_LOCAL_STORAGE_DIR = $storagePath
try {
  apify run --resurrect --input-file .actor/input.json
} finally {
  Remove-Item Env:APIFY_LOCAL_STORAGE_DIR -ErrorAction SilentlyContinue
}
```

# Changelog

This Actor's version history is a separate document: https://apify.com/jobsapi/idealist-jobs-search-scraper/changelog.md

# Actor input Schema

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

Job title or keywords used to build an Idealist public jobs search URL unless startUrl is supplied.

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

Optional city, region, or country phrase passed to Idealist when building the search URL. The Actor does not independently filter geography, and Idealist may return a broader or differently ranked result set. Ignored when startUrl is supplied.

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

Maximum number of job records to emit after opening public Idealist detail pages.

## `maxDetailPages` (type: `integer`):

Maximum number of public Idealist search result pages to inspect (not the number of detail pages).

## `timeoutSecs` (type: `integer`):

Maximum navigation timeout in seconds. The request handler timeout is derived from this value.

## `startUrl` (type: `string`):

Optional HTTPS Idealist /en/jobs search URL. When supplied, this URL replaces the URL generated from query and location.

## Actor input object example

```json
{
  "query": "program manager",
  "location": "United States",
  "maxItems": 3,
  "maxDetailPages": 2,
  "timeoutSecs": 60
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

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

No description

## `health` (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("jobsapi/idealist-jobs-search-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("jobsapi/idealist-jobs-search-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 jobsapi/idealist-jobs-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jobsapi/idealist-jobs-search-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/F323j248hVIRvmk3n/builds/yaZGhFCzuPQNtHbSO/openapi.json
