# CharityJob Scraper (`boncross/charityjob-jobs`) Actor

Scrape UK charity and non-profit jobs from CharityJob. Search by keyword, location and radius, filter by cause, contract type, workplace and salary, and get the employer, salary range, cause categories, posting and closing dates and the full advert. Export to CSV, JSON or Excel.

- **URL**: https://apify.com/boncross/charityjob-jobs.md
- **Developed by:** [BonCross API](https://apify.com/boncross) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 job-details

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

## CharityJob Scraper

### What is CharityJob Scraper?

CharityJob is where UK charities advertise, and CharityJob Scraper gets you those vacancies as data you can filter by cause. You pick from the site's 21 causes, from Animal and Environment to Mental Health and Youth and Children, add a keyword and a town or postcode, and each job arrives with its full advert, its salary as numbers and its closing date.

If you're building a sector job board, a salary benchmark for non-profit roles or a daily alert for candidates, this is the data underneath it.

Why this scraper:

- **The salary is parsed.** You get a from figure, a to figure, the period and the currency, with the charity's own wording kept beside them. That was filled on all 40 rows of our administrator test run.
- **Closing dates are in the row**, so a role can leave your board on the day it shuts.
- **It's fast for the size of the site.** 1,000 jobs with full adverts took 54 to 68 seconds on 2 October 2026.
- **Overlapping searches don't double your bill.** A job that several of your searches return is written and charged once.
- **$1.00 per 1,000 jobs with the advert** on the Free plan, or $0.25 per 1,000 if the listing fields are enough.

**BonCross Verified** means we tested this actor against the live site before release and kept the record:

- 32 of 32 live checks on its inputs and filters passed on 6 October 2026
- 6 searches run on 7 October 2026 across Manchester, Glasgow, Bristol, Cardiff and London: 72 jobs, none empty
- 8 of 8 sampled adverts matched CharityJob's own pages, text and link
- 87 charges checked, none mismatched

More that it does:

- Search any job title or keyword in any UK town, city or postcode, with a radius up to 100 miles
- Filter by contract type and by on-site, hybrid or remote working
- Set a salary floor and ceiling in pounds a year
- Keep only jobs whose title matches, or leave out employers you don't want
- Return only the jobs you haven't seen before on a scheduled run
- Run several searches together and tell them apart afterwards

### What data can you extract from CharityJob?

| Field | Field |
|---|---|
| 💼 Job title | 🏢 Charity or employer |
| 📍 Location as advertised | City, region and postcode |
| 🏠 On-site, hybrid or remote | Country code |
| 💷 Salary from and salary to | Salary period and currency |
| Salary as advertised | Contract types |
| 🎗 Cause categories | Featured listing flag |
| 📅 Posted date | ⏳ Closing date |
| 📄 Full advert text | Advert HTML, optional |
| 🔗 Advert link | Job id |
| Employer's own reference | Charity logo |
| When the row was collected | |

### How to scrape CharityJob

1. [Create a free Apify account](https://console.apify.com/sign-up) and open [CharityJob Scraper](https://apify.com/boncross/charityjob-jobs).
2. Enter a job title or keyword and a location. One of the two is enough.
3. Set the radius and tick the causes, contract types or workplace you care about.
4. Choose how many jobs you want per search and for the run.
5. Press Start, then download the jobs as Excel, CSV or JSON.

A search for administrator roles within 10 miles of London finished in about 2 seconds.

### ⬇️ Input

Give it a keyword, a location, or both. To run more than one search, fill in "Searches". If you've already filtered a search on charityjob.co.uk, paste its URL into Start URLs and the filters in the URL are kept.

Two limits apply. "Max jobs per search" (default 200) caps each search, and "Max jobs for the whole run" (default 0, no cap) sits above them all.

**Administrator jobs within 10 miles of London**

```json
{
  "keyword": "administrator",
  "location": "London",
  "distance": 10,
  "maxItemsPerSearch": 200
}
```

**Remote fundraising roles paying £40,000 or more**

```json
{
  "keyword": "fundraising manager",
  "workplaces": ["remote"],
  "minSalary": 40000,
  "contractTypes": ["permanent", "full-time"],
  "maxItems": 500
}
```

**Several searches, mental health and youth causes, posted in the last week**

```json
{
  "searches": [
    { "keyword": "project manager", "location": "Manchester" },
    { "keyword": "support worker", "location": "Birmingham" }
  ],
  "causes": ["mental-health", "youth-and-children"],
  "maxDaysOld": 7,
  "fetchDetails": true
}
```

**A scheduled run that skips what you've already had**

```json
{
  "keyword": "communications",
  "location": "London",
  "onlyNew": true,
  "dedupStoreName": "charityjob-seen",
  "sortBy": "newest"
}
```

The optional settings, by group:

- **Filters.** "Minimum salary" and "Maximum salary" are in GBP per year, and 0 means no limit. "Quick apply only" keeps jobs that take CharityJob's quick-apply form. Then there's the radius, contract types, workplace, causes, sort order (newest or closing soonest) and "Posted within (days)".
- **Title and employer filters.** "Title must contain" keeps a job when its title has at least one of your words. "Title must not contain" drops it when the title has any of them. "Exclude employers" does the same on the employer name. None of them is case-sensitive.
- **What each row includes.** "Fetch full job details" is on by default and opens each advert. "Include description" adds the advert as plain text. "Include description HTML" also adds the original HTML, which makes rows considerably larger.

#### For developers

- Keys: `keyword`, `location`, `searches`, `startUrls`, `maxItemsPerSearch`, `maxItems`, `distance`, `contractTypes`, `workplaces`, `causes`, `quickApplyOnly`, `minSalary`, `maxSalary`, `sortBy`, `maxDaysOld`, `titleIncludes`, `titleExcludes`, `companyExcludes`, `fetchDetails`, `includeDescription`, `includeDescriptionHtml`, `onlyNew`, `dedupStoreName`, `maxConcurrency`, `delayMs`.
- Each `searches` entry is a keyword string or an object with `keyword` and `location`. An entry without a location uses `location`.
- CharityJob returns 15 jobs a page. A search pages until its limit is reached or the results run out.
- `onlyNew` skips jobs returned by an earlier run that used the same `dedupStoreName`.
- `maxDaysOld` and the description need `fetchDetails` on, because the posting date and advert text live on the advert page. An advert opened and then dropped by `maxDaysOld` is still billed `job-detail`.
- `maxConcurrency` (default 16, from 1 to 32) and `delayMs` (default 0, up to 2,000) control pacing.
- If Apify moves a run to another server part-way through, it carries on where it stopped. No job is returned or charged twice.

### ⬆️ Output

One row per job. The Overview view shows title, charity, location, salary range, contract, causes and dates. The full record adds the advert text and the structured address.

```json
{
  "id": "1084171",
  "title": "Foundations Manager",
  "company": "The UK Committee for UNICEF (UNICEF UK)",
  "url": "https://www.charityjob.co.uk/jobs/…/foundations-manager/1084171",
  "location": "E20, London (Hybrid)",
  "city": "London",
  "region": "England",
  "postcode": "E20",
  "countryCode": "GB",
  "workplaceType": "Hybrid",
  "isRemote": false,
  "salaryMin": 46000,
  "salaryMax": 46000,
  "salaryCurrency": "GBP",
  "salaryPeriod": "YEAR",
  "salaryText": "Circa £46,000 per annum",
  "employmentTypes": ["CONTRACTOR", "FULL_TIME"],
  "categories": ["Campaigns", "Communications", "Fundraising"],
  "postedAt": "2026-09-17",
  "closingAt": "2026-10-04",
  "description": "About the role…",
  "scrapedAt": "2026-09-17T11:58:02.114Z"
}
```

Each row also has `search` (the query that found it, which keeps a multi-search run separable), `postedText` and `isTopJob` in CharityJob's wording, `isQuickApply` (true when the job takes CharityJob's quick-apply form), `employerRef` where the employer publishes a reference of its own, and `companyLogo`.

### How much does it cost to scrape CharityJob?

| Event | Free plan | Starter | Scale | Business |
|---|---|---|---|---|
| `actor-start`, per run | $0.002 | $0.002 | $0.002 | $0.002 |
| `search-run`, per search (recorded, not charged) | $0 | $0 | $0 | $0 |
| `job-scanned`, per search result read | $0.00005 | $0.00005 | $0.00005 | $0.00005 |
| `job-detail`, per advert opened (charged even if **Posted within (days)** then drops the job) | $0.001 | $0.0009 | $0.0008 | $0.0007 |
| `job-listed`, per job returned without an advert | $0.0002 | $0.00018 | $0.00016 | $0.00014 |

Enterprise plans pay the Business price.

**$1.00 per 1,000 jobs** on the Free plan and $0.70 on Business, adverts included. CharityJob needs no proxy, so there are no proxy charges, and platform usage is in the price too.

- 200 jobs with full adverts: $0.002 + 200 × ($0.00005 + $0.001) = **$0.212** ($0.152 on Business).
- The same 200 as a listing-only run, with "Fetch full job details" off: $0.002 + 200 × $0.00025 = **$0.052** ($0.040 on Business).

A job is charged one of `job-detail` or `job-listed`, never both, and once per run however many of your searches found it.

The first example is a typical run. Apify's Free plan gives you $5 of credits a month, which covers about 23 of them, or about 4,700 jobs with adverts.

### How many jobs, and how fast?

Whole runs with full adverts fetched, measured on Apify on 2 October 2026:

| Run | Jobs returned | Time |
|---|---:|---:|
| Administrator roles within 10 miles of London | 15 | about 2 seconds |
| Manager roles in London | 200 | about 5 seconds |
| Three searches (London, Manchester, Bristol), 60 each | 180 | about 8-9 seconds |
| Three searches in London ("administrator", "fundraising", "finance"), 100 each | 300 | 7-10 seconds |
| Three searches in London ("fundraising", "finance", "communications"), 200 each | 600 | 15-29 seconds |
| Five searches in London, 200 each | 1,000 | 54-68 seconds |

That's about 1,000 jobs a minute, which is more than CharityJob lists for most searches. Searches that share many jobs take longer per row, because a shared job is returned once and the search reads further to fill its quota.

On the 40-row administrator run, salary, contract types, causes, posting date, closing date and the advert text were filled on **every row**. City, region and postcode come from the advert's own address block and are present on roughly two rows in three, because not all charities fill them in. Rows averaged 4.7 KB, with 3,660 characters of advert text.

### FAQ

#### How do I get only the jobs posted since my last run?

Turn on "Only jobs not seen before", give "Store name for seen jobs" a name, and schedule the run in Apify Console. Each run then returns what has appeared since the one before.

#### My keyword ignored the location and filters. What happened?

CharityJob treats some keywords (fundraising, finance, marketing) as sector categories and opens a sector page in place of a search. Those pages ignore location and filters, and the run says so in its log when it happens. Use a more specific keyword, or filter the search on the site and paste the link into Start URLs.

#### Why is the salary a single number on some jobs?

The charity advertised one figure. The from and to values are then both that figure, and the advertised wording stays in the salary text field. Where an advert gives no salary, both are empty.

#### Which causes can I filter by?

All 21 that CharityJob uses: Animal, Arts, Culture and Heritage, Charity Support, Community Development, Disability, Diversity and Inclusion, Education, Elderly, Environment, Faith-based, Health, Housing and Homelessness, Human Rights, International Development, Justice, Membership Organisations, Mental Health, Research, Social Welfare, Sport, and Youth and Children. Leave the field empty for all of them.

#### How do I find remote charity jobs?

Set "Workplace" to Remote. Each row also says whether the role is on-site, hybrid or remote, so you can leave the filter off and sort afterwards.

#### Do I need a proxy or a CharityJob account?

There's nothing to configure. The adverts are public, and no account or login is used.

#### What are the limits?

- CharityJob only lists UK charity and non-profit roles.
- City, region and postcode are missing where the charity left them blank. The advertised location text is always present.
- Some charities attach the real advert as a PDF and write one line in the body. You get that one line.
- If an advert can't be opened, the job is still returned with its listing fields and billed as `job-listed`. If a whole search fails, the run writes a row with the search and an `error` message, uncharged, and carries on.
- You can't submit applications through this actor.

#### Is scraping CharityJob legal?

The actor reads job adverts CharityJob publishes openly. Collecting public data is generally lawful in the UK and EU. What you do with it is your responsibility, including under UK GDPR where a record identifies a person.

### Feeding a board, a CRM or a newsletter

For a job board or a weekly sector newsletter, schedule a daily only-new run and let a webhook push the new roles into your system. The Zapier, Make, Slack, Google Sheets and Airbyte integrations do the same without code.

Developers can run the actor and get the rows in one call with Apify's run-sync-get-dataset-items endpoint. There are `apify-client` libraries for Python and JavaScript, and the actor's API tab shows the reference with your token filled in.

AI agents can use it as a tool through the Apify MCP server at `https://mcp.apify.com`: ask for hybrid fundraising roles in Leeds above £35,000 and the agent reads the answer as structured data.

### More from BonCross

- [Glassdoor Job Scraper](https://apify.com/boncross/glassdoor-jobs): Glassdoor job listings for a role and location.
- [Greenhouse Jobs Scraper](https://apify.com/boncross/greenhouse-jobs): Every open job from a Greenhouse careers board.
- [hiring.cafe Job Scraper](https://apify.com/boncross/hiring-cafe-jobs): Every job hiring.cafe lists for your filters.
- [Indeed Job Scraper](https://apify.com/boncross/indeed-jobs): Indeed job listings for a role and location.
- [Lever Jobs Scraper](https://apify.com/boncross/lever-jobs): A Lever careers board for every open job.
- [LinkedIn Jobs Scraper](https://apify.com/boncross/linkedin-jobs-scraper): LinkedIn jobs from keywords and locations or search URLs, no login needed.

### Your feedback

If a salary was parsed wrongly or a cause is missing from a job, we want to know. Raise it on the Issues tab in Apify Console with the advert link. We read every report and fix what we can reproduce.

# Changelog

This Actor's version history is a separate document: https://apify.com/boncross/charityjob-jobs/changelog.md

# Actor input Schema

## `keyword` (type: `string`):

What to search for, for example "fundraising manager" or "administrator". Leave empty to take everything the other filters allow.

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

A town, city or postcode, for example "London" or "M1". Combined with the search radius below.

## `searches` (type: `array`):

Several searches in one run. Each entry is either a keyword string, or an object with "keyword" and "location". Entries without a location use the Location field above.

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

Paste CharityJob search URLs, or point at a file or Google Sheet holding many. Used as-is, so any filters already in the URL are kept.

## `maxItemsPerSearch` (type: `integer`):

Row limit for each individual search. 0 means no limit.

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

Row ceiling across every search in the run, on top of the per-search limit. 0 means no limit.

## `distance` (type: `integer`):

How far from the location to search. CharityJob offers 10 to 100 miles.

## `contractTypes` (type: `array`):

Keep only these contract types. Leave empty for all.

## `workplaces` (type: `array`):

Keep only jobs with these working arrangements. Leave empty for all.

## `causes` (type: `array`):

Keep only jobs in these charitable causes. Leave empty for all.

## `quickApplyOnly` (type: `boolean`):

Keep only jobs you can apply for on CharityJob itself with the quick-apply form (shown as isQuickApply on each row).

## `minSalary` (type: `integer`):

Lowest advertised salary to accept, in GBP per year. 0 means no minimum.

## `maxSalary` (type: `integer`):

Highest advertised salary to accept, in GBP per year. 0 means no maximum.

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

Order CharityJob returns results in.

## `maxDaysOld` (type: `integer`):

Keep only jobs posted in the last N days, using the posting date on each advert. 0 keeps everything. Needs "Fetch full job details" on, because the posting date comes from the advert.

## `titleIncludes` (type: `array`):

Keep a job only if its title contains at least one of these words. Case-insensitive.

## `titleExcludes` (type: `array`):

Drop a job if its title contains any of these words. Case-insensitive.

## `companyExcludes` (type: `array`):

Drop a job if the employer name contains any of these words. Case-insensitive.

## `fetchDetails` (type: `boolean`):

Open each advert for the description, salary range, cause categories, employment types and closing date. Turn off for a fast, cheap listing-only scan.

## `includeDescription` (type: `boolean`):

Include the advert text as plain text. Needs "Fetch full job details".

## `includeDescriptionHtml` (type: `boolean`):

Also include the advert's original HTML. Makes rows considerably larger.

## `onlyNew` (type: `boolean`):

Skip jobs returned by an earlier run that used the same store name below.

## `dedupStoreName` (type: `string`):

Named key-value store that remembers job ids between runs. Leave empty to remember nothing.

## `maxConcurrency` (type: `integer`):

How many requests run at once across the whole run. The default is the fastest level measured clean; lower it only if a run reports refusals or errors.

## `delayMs` (type: `integer`):

Optional pause before each call, in milliseconds, up to 2,000. 0 (the default) runs as fast as the parallel limit allows.

## Actor input object example

```json
{
  "keyword": "administrator",
  "location": "London",
  "searches": [],
  "startUrls": [],
  "maxItemsPerSearch": 200,
  "maxItems": 0,
  "distance": 10,
  "contractTypes": [],
  "workplaces": [],
  "causes": [],
  "quickApplyOnly": false,
  "minSalary": 0,
  "maxSalary": 0,
  "sortBy": "newest",
  "maxDaysOld": 0,
  "titleIncludes": [],
  "titleExcludes": [],
  "companyExcludes": [],
  "fetchDetails": true,
  "includeDescription": true,
  "includeDescriptionHtml": false,
  "onlyNew": false,
  "dedupStoreName": "",
  "maxConcurrency": 16,
  "delayMs": 0
}
```

# Actor output Schema

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

CharityJob jobs — every row the run returned.

## `stats` (type: `string`):

Counts for the run: what was searched, fetched, filtered and returned.

# 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 = {
    "keyword": "administrator",
    "location": "London"
};

// Run the Actor and wait for it to finish
const run = await client.actor("boncross/charityjob-jobs").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 = {
    "keyword": "administrator",
    "location": "London",
}

# Run the Actor and wait for it to finish
run = client.actor("boncross/charityjob-jobs").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 '{
  "keyword": "administrator",
  "location": "London"
}' |
apify call boncross/charityjob-jobs --silent --output-dataset

```

## MCP server setup

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

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/RvAJrIqs5b9w2rh2E/builds/3aueKLkSmtUtOqrhh/openapi.json
