CharityJob Scraper — UK Charity Jobs, Volunteers & Leads
Pricing
from $1.00 / 1,000 job returneds
CharityJob Scraper — UK Charity Jobs, Volunteers & Leads
$1 per 1,000 jobs, $0 to start. Scrape CharityJob.co.uk paid AND volunteer roles by keyword, location, cause, salary, workplace and date posted, then add each charity's own website, LinkedIn, HQ and open-role counts. Saved-search monitor with Slack/webhook alerts. No login, no API key.
Pricing
from $1.00 / 1,000 job returneds
Rating
0.0
(0)
Developer
Scrapers Delight
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
💜 CharityJob Scraper — UK Charity Jobs, Volunteer Roles & Charity Leads
Scrape every live advert on CharityJob.co.uk — the UK's largest charity-sector job board — and get the hiring charity's own website, LinkedIn and HQ attached to each row. Paid roles and the 1,622-advert volunteer corpus, with every filter the site itself offers wired to a real input.
$1 per 1,000 jobs. $0 to start a run. No login, no API key, no cookies.
🧾 What does this Actor do?
CharityJob's search page is a two-panel UI that pre-renders the full detail of all 15 results in the same HTML response. That means one request returns 15 complete job records — full description, salary line, contract, hours, causes, tags, closing date and the charity's profile link — with no per-job fetch and no browser. This Actor walks that pagination, applies the site's own server-side filters, then optionally enriches each row twice:
enrichOrganisation(on by default) — fetches/organisation/<slug>for each charity and adds its own website URL, LinkedIn / Facebook / X / YouTube / Instagram / TikTok, HQ postcode, mission, about text, and how many paid and volunteer roles it currently has open. Each charity is fetched once per run, however many adverts it has in your result set — so you are never double-charged for the same organisation.enrichStructuredSalary(off by default) — fetches each job page for its schema.orgJobPostingblock: numericsalaryMin/salaryMax/ currency / period, ISOdatePostedandvalidThrough, theemploymentTypeenum, and every listed locality.
Add monitorMode and a schedule and it becomes a saved-search watcher that returns only adverts
that are new since the previous run, with optional Slack / webhook / email alerts.
🎯 Who buys this data
| Buyer | What they do with a row |
|---|---|
| Fundraising / charity-tech vendors (CRM, donation platforms, payroll, DBS checking) | A charity that is hiring a fundraiser is a charity with budget and a live pain. The row names the charity, its size band, its own website and its LinkedIn — a ready outbound record. |
| Charity-sector recruitment agencies | Which charities are hiring directly right now, and which roles agencies already hold (hideAgencies, applyLabel). |
| Sector researchers & funders | Salary bands, cause mix, workplace mix and hiring volume across the whole UK charity sector, refreshed daily. |
| Volunteer-management platforms | The 1,622-advert volunteer corpus that no rival CharityJob scraper covers at all. |
| Job aggregators | A clean, deduplicated feed of ~98 new paid adverts a day (measured 2026-09-05, run yrqe2Ct8glpQWnfAm: the site reported 686 paid adverts posted in the last 7 days). |
📦 What you get — measured, not estimated
Every number below comes from one run on build 0.1.9, 2026-09-05: run NI8sMc1CRWmghfm1l,
jobType: "both" with both enrichments on, 120 rows / 120 unique jobId (60 paid + 60
volunteer) in 140.7 seconds across 203 HTTP requests. Fill = the field is present and non-empty.
Always there, 100% of 120 rows — jobId · jobUrl · jobSlug · title · organisation ·
organisationSlug · organisationUrl · organisationType · partnerId · logoUrl · location ·
locationName · workplace · salaryRaw · causes · tags · closingDate ·
listedOrRefreshedOn · postedRelative · applyLabel · resultPosition · descriptionText ·
orgPaidJobCount · orgVolunteerJobCount · orgProfileId · sourceUrl · scrapedAt
| Field | Fill | Why it is not 100% |
|---|---|---|
contractType | 99% (119/120) | One advert stated no contract type |
organisationSize | 81% (97/120) | Not every charity states a staff band |
postedOn | 61% (73/120) | Refreshed adverts show "Refreshed on" instead — listedOrRefreshedOn merges the two and is 100% |
hours | 50% (60/120) | Volunteer adverts carry no hours field at all — 100% (60/60) across the paid half |
refreshedOn | 39% (47/120) | Shown only when the advert has been refreshed |
shortDescription | 26% (31/120) | A card-only field the site shows selectively |
jobReference | 22% (26/120) | Only some recruiters publish one |
closingBadge | 10% (12/120) | Shown only when a deadline is close |
Booleans are always present; these are their true rates in the same 120 rows:
isVolunteerRole 50% (the deliberate 60/60 split), hasOrganisationProfile 100%,
activelyInterviewing 66%, isTopJob 18% (the sponsored promos — see honest limit 2),
isExpiredJob 0%, isFutureJob 0%.
With enrichStructuredSalary on (same run):
| Field | Fill | Note |
|---|---|---|
datePosted, validThrough, employmentType | 100% | ISO dates + the schema.org enum |
salaryMin, salaryMax, salaryCurrency, salaryPeriod | 50% (60/120) | Volunteer roles have no salary — 100% (60/60) across the paid half |
jobRegions / jobLocalities | 72% / 71% | Multi-site adverts list several |
jobLocationType | 28% | Only set (to TELECOMMUTE) for remote roles |
With enrichOrganisation on — the lead payload (same run; all 120 rows had a charity profile
page, so nothing below is diluted by missing profiles):
| Field | Fill |
|---|---|
orgHeadquarters (postcode + country) | 78% (94/120) |
orgAboutText | 78% (94/120) |
charityWebsiteUrl | 68% (82/120) |
linkedinUrl | 58% (69/120) |
facebookUrl | 49% (59/120) |
orgMission | 48% (57/120) |
twitterUrl | 38% (46/120) |
instagramUrl / youtubeUrl / tiktokUrl | 22% / 8% / 2% |
⚠️ Ten columns are empty unless you turn enrichStructuredSalary on
enrichStructuredSalary ships off, because it costs an extra HTTP fetch and an extra
$0.0005 charge per job. With the shipped defaults every row still carries all 62 columns, but
ten of them are null on every row:
salaryMin · salaryMax · salaryCurrency · salaryPeriod · datePosted · validThrough ·
employmentType · jobLocationType · jobLocalities · jobRegions
Measured, defaults untouched: run 5fILHhLj0oYhBeyN9 (25 rows) and run g2i3Rtd3upc2DD1DJ
(25 rows) — those ten fields were null on 50 of 50 rows. Turn the flag on and they fill (100%
datePosted / validThrough / employmentType, and 100% numeric salary across paid roles, per the
table above). salaryRaw is 100% filled either way and carries whatever the charity actually wrote.
The lead output shape
Set outputShape: "lead" and you get a 23-column projection of the same record — the same field
names, never renamed, so both dataset views ("Overview" and "Charity leads") and any downstream
mapping keep working when you switch shape:
organisation · charityWebsiteUrl · linkedinUrl · organisationType · organisationSize ·
orgHeadquarters · orgPaidJobCount · orgVolunteerJobCount · title · salaryRaw ·
salaryMin · salaryMax · contractType · hours · locationName · workplace · causes ·
listedOrRefreshedOn · closingDate · jobId · jobUrl · organisationUrl · scrapedAt
Verified on run 2aP61qySUDcGNCYES (build 0.1.9, 10 rows): the "Charity leads" CSV export came back
with 12 of 12 columns populated and the "Overview" export with 10 of 10.
🔍 Every filter the site has, wired and tested
All of these are the site's own server-side parameters — each one was verified live on 2026-09-04 by confirming CharityJob's own result counter moved:
| Input | Live check on 2026-09-04 |
|---|---|
keywords | fundraising → 619 results · chief executive → 387 |
location + radius | manchester r5 → 235 · r80 → 456 |
cause (21 values, repeatable) | education + health → 501 |
contractType (repeatable) | contract + temporary → 532 |
workplace (on-site / hybrid / remote) | hybrid → 935 · remote → 179 |
minSalary / maxSalary | £40k–£60k → 609 |
postedWithinDays | Re-measured 2026-09-05 on build 0.1.9: 3 days → 351 (iRVhHbCIbbauu1d1v) · 7 days → 686 (yrqe2Ct8glpQWnfAm) · 14 days → 1,225 (2SpeTyiXZmG1JtMKe). The 1-day bucket is calendar today, so it reads low late in the UTC day — 27 at 23:00 UTC (zekT3x2hm9N41d6wB). |
sortBy | latest (newest) vs closing (soonest) — different first rows |
entryLevelOnly | → 143 |
applyNowOnly | → 525 (excludes external-ATS redirects) |
hideAgencies | → 1,454 (direct charity employers only) |
jobType | Re-measured 2026-09-05 (run NI8sMc1CRWmghfm1l): paid → 1,652 · volunteer → 1,622 · both splits your cap fairly between the two (that run returned exactly 60 paid + 60 volunteer) |
Plus client-side controls: excludeTopJobs, excludeExpired, maxItems, maxPages,
deduplicateBy, includeDescriptionHtml, outputShape, maxConcurrency, maxRequestRetries,
proxyConfiguration, and startUrls (paste any CharityJob search or single job URL — the URL's
own querystring wins, the fields above are merged in only where it is silent).
💵 Pricing
Pay per event. There is no charge to start a run, and both of Apify's auto-events are removed.
| Event | Price | When it fires |
|---|---|---|
| Job returned | $0.001 ($1 per 1,000) | Once per advert delivered to your dataset. Rows dropped by your filters, by deduplication, or by the monitor's seen-set are never charged. |
| Charity profile enriched | $0.0005 | Once per unique charity profile fetched. A charity with ten adverts costs one charge, not ten. |
| Structured salary fetched | $0.0005 | Per job page fetched for numeric salary + ISO dates. Opt-in, off by default. |
| Monitoring run | $0.01 | Once per scheduled monitor run. |
| New advert detected | $0.002 | Per advert that is new since the previous monitor run. |
What a full scrape costs you today. The site reported 1,652 live paid adverts on
2026-09-05 (run NI8sMc1CRWmghfm1l). Rival prices below were read from the Apify store API the
same day, not from memory:
| Rate | 1,652 paid adverts | |
|---|---|---|
| This Actor | $0.001/row, no start charge | $1.65 |
| memo23/charityjob-scraper | $0.0015/row + $0.05 start | $2.53 |
| getdataforme/charityjob-urls-scraper | $0.009/row + $0.05 start | $14.92 |
Charity enrichment adds $0.0005 per unique charity, not per row. Measured on the 120-row run
above: 75 unique charities behind 120 rows → +$0.0375 (charged 75, verified against 75 distinct
organisationSlug values). Over a whole-corpus scrape the worst case is one unique charity per row,
so an all-1,652 enriched scrape is $1.65 + at most $0.83.
What maxTotalChargeUsd actually does here. Before anything is written, the run prices every
row it is holding against the budget you set — the row itself plus the charity-profile and
structured-salary events that row will owe — and delivers only the rows the budget can pay for in
full. A row that cannot be paid for completely is withheld, not shipped, so you never pay an
enrichment charge for a row you did not receive, and the run total never crosses your cap. Measured
2026-09-05 on build 0.1.9: at a $0.0100 cap with both enrichments on (run JQTpnBgabykQAzAah)
the run stored 5 rows and billed 5 rows + 4 charity profiles + 5 salary fetches =
$0.0095; at a $0.0200 cap with charity enrichment on (run N1fBkYE01Ra1gkCnA) it stored
14 rows and billed 14 rows + 12 profiles = $0.0200 exactly. Rows stored equals rows billed
on both, and both numbers reproduced exactly on the shipped build (runs ia03DJsdRGwXvCd3Z and
02tgk8WO2gYcfTkDt). (On build 0.1.8 the same $0.0100 cap billed $0.0105 — over the cap — and asked to charge
17 profiles and 20 salary fetches behind 10 delivered rows; run kZrf2EPW56a8H6OcX. That is fixed.)
🧪 Reliability, measured
- Transport: plain HTTP + cheerio through an Apify datacenter proxy. The escalation ladder (direct / datacenter / residential-GB) returned byte-identical 570,104-byte responses on the 2026-09-04 transport probe, so the cheapest rung is the default. No browser, no residential, 512 MB. Every run listed on this page went through that default datacenter proxy and returned 200s with zero blocks.
- Sustained load (2026-09-04 probe, single attempt, no retry, all through an Apify proxy):
datacenter sequential 39/40 (97.5%), concurrency 5 → 10/10, concurrency 10 → 19/20.
Across 90 proxied requests CharityJob returned zero 403, zero 429, zero CAPTCHA, zero
soft-block — both failures were Apify-proxy-side
595 ECONNRESET, which the default 3 retries (each on a fresh exit IP) absorb entirely. - Speed (re-measured 2026-09-05 on build 0.1.9): 120 rows with both enrichments —
8 listing pages + 75 charity profiles + 120 job pages = 203 HTTP requests — in 140.7 seconds
(run
NI8sMc1CRWmghfm1l). Unenriched is far faster: 25 rows with charity enrichment only in 8.1 s (5fILHhLj0oYhBeyN9), and a 2-row counter probe in 6.3 s (NAUMgCJDav9hZr7nb). - Pagination is bounded and self-describing: the page reports its own total and page count, and
the crawl stops at the last page. 15 results per page is fixed by the site (
?pagesize=100is ignored).
⚠️ Honest limits — read these before you buy
- There is no apply link, and this Actor does not invent one. CharityJob's apply button is a
JavaScript-only trigger through
track.charityjob.co.uk; no destination URL exists anywhere in the page HTML. What you get instead isapplyLabel—"Apply Now"(apply on CharityJob) or"Redirect to recruiter"(external ATS) — which is honest and 100% filled. - Sponsored "Top job" promos are injected into EVERY result set, regardless of your filters.
Measured: advert 1082124, located "Remote", appeared under both
cause=educationandlocation=london. That is the site's behaviour, not a bug in the filter. SetexcludeTopJobs: trueto drop them (they were 18% — 22 of the 120 rows in runNI8sMc1CRWmghfm1l). - A salary filter silently drops adverts with no stated salary. That is how the site works.
orgHeadquartersis a postcode + country, read from the charity's own map embed — not a full street address.- Some charities have no CharityJob profile page. Their name still comes through;
hasOrganisationProfileisfalseand the enrichment fields stay null. Across the 170 rows I measured on 2026-09-05 (runsNI8sMc1CRWmghfm1l,5fILHhLj0oYhBeyN9,g2i3Rtd3upc2DD1DJ) every single row did have a profile — so checkhasOrganisationProfilerather than assuming a rate. - Ten columns are null unless you opt in. With the shipped defaults
enrichStructuredSalaryis off, andsalaryMin,salaryMax,salaryCurrency,salaryPeriod,datePosted,validThrough,employmentType,jobLocationType,jobLocalitiesandjobRegionsare null on every row (measured: 50 of 50 rows across runs5fILHhLj0oYhBeyN9andg2i3Rtd3upc2DD1DJ). They are opt-in because each one costs an extra fetch and an extra $0.0005 per job.salaryRawis 100% filled either way. - This corpus is modest and it churns. 1,652 paid + 1,622 volunteer adverts live on
2026-09-05 (run
NI8sMc1CRWmghfm1l), with 686 paid adverts posted in the previous 7 days (~98/day, runyrqe2Ct8glpQWnfAm) — so the whole live paid corpus turns over in roughly 17 days. The counter also moves while you read it: the same paid search reported 1,659 eight minutes earlier the same evening (rung2i3Rtd3upc2DD1DJ). If you want a one-off list, it is a small one; the value is in watching the flow. refreshedOnvspostedOnare mutually exclusive on the site. UselistedOrRefreshedOn, which merges them and is 100% filled (postedOnalone was 61% — 73 of 120 — andrefreshedOn39% — 47 of 120 — in runNI8sMc1CRWmghfm1l).
❓ FAQ
Do I need a CharityJob account or an API key? No. Everything this Actor reads is a public, server-rendered page.
Does it work without a proxy?
It runs, but use the default Apify proxy. Datacenter is measured sufficient — residential is not
required, though you can pin apifyProxyGroups: ["RESIDENTIAL"], countryCode: "GB" if you prefer.
How many jobs are there in total?
The site reported 1,652 paid and 1,622 volunteer adverts on 2026-09-05 (run
NI8sMc1CRWmghfm1l). The Actor reads the live figure from the page and logs it every run, so you
always know the size of your query before you commit to it.
Can I scrape the whole site?
Yes — set maxItems: 0 and jobType: "both". On 2026-09-05 that was 3,274 rows, $3.27
unenriched (1,652 + 1,622, run NI8sMc1CRWmghfm1l).
How do I get only new jobs?
monitorMode: true on a schedule. The seen-set lives in a named key-value store so it survives
between runs. Verified 2026-09-05 on build 0.1.9: round 1 (ueZLsTzyegaJsyr26) returned 10 new of 10 and
charged job-scraped: 10, new-job-detected: 10, monitor-run-completed: 1; round 2 over the
identical search a minute later (fSs1lDG9XasfEmi0p) returned 1 new of 10 — one genuinely fresh
advert had been listed in between — and charged 1 row, 1 new-job-detected and the one
monitor-run-completed. The nine already-seen adverts were suppressed and cost nothing. Pair it with
postedWithinDays: 1 to keep runs tiny.
Will I be charged twice for the same job?
No. deduplicateBy: "jobId" is the default and it collapses the sponsored promos that repeat across
pages. A/B verified 2026-09-05 with the same search URL listed twice in startUrls, maxItems
30: with the default "jobId" (run cZajAeBeLeehAXwIc, build 0.1.9) → 30 rows, 30 unique, max
repeat 1, and the crawler simply pages on to fill the cap with genuinely new adverts; with
"none" (run ead3ode2CCsmJNAJj) → 30 rows but only 15 unique, every id twice, billed 30. The control
double-charges; the shipped default does not.
Will I be charged twice for the same charity?
No. Organisation enrichment deduplicates by organisationSlug. Verified on run
NI8sMc1CRWmghfm1l: 120 rows contained 75 distinct organisationSlug values, 75 profiles were
fetched, and chargedEventCounts shows organisation-enriched: 75 — not 120.
What if my search returns nothing? The run exits cleanly with zero rows and charges nothing. The Actor distinguishes a genuinely empty search (the site's counter reads 0) from a broken parse (the counter is missing, or says >0 while no rows parsed) — the latter fails the run loudly rather than handing you a silently empty dataset.
Can I paste a URL from my browser?
Yes. Put any charityjob.co.uk/jobs?… or /volunteer-jobs?… search URL in startUrls and its
querystring becomes the filter set. A single job URL works too and returns that one advert.
What's the difference between full and lead output?
full is every field — 62 columns with the shipped defaults. Counted on every row of runs
5fILHhLj0oYhBeyN9 (25 rows), g2i3Rtd3upc2DD1DJ (25) and NI8sMc1CRWmghfm1l (120): exactly 62
keys, no row short. Two options each append one more column — includeDescriptionHtml adds
descriptionHtml, and monitorMode adds isNew (measured on run ueZLsTzyegaJsyr26: the
62-column full shape came back with 63, isNew present on all 10 rows).
lead is a 23-column projection of those same fields, under the same names — organisation,
charityWebsiteUrl, linkedinUrl, type, size, orgHeadquarters, open-role counts, title, salary,
locationName, workplace, causes, closingDate and the URLs. Because the names do not change, both
dataset views work in either shape. Note: two of those 23 — salaryMin and salaryMax — are
part of the opt-in set in honest limit 6, so with the shipped defaults they arrive empty in the
lead shape too (measured on run 2aP61qySUDcGNCYES: 23 columns, salaryMin/salaryMax 0 of 10,
every other column 4–10 of 10). Turn enrichStructuredSalary on if your CRM needs numeric pay.
Does it cover volunteer roles?
Yes — /volunteer-jobs is the site's own second tab over the same search grammar, 1,622 adverts,
parsed by the same code into the same fields. Set jobType to volunteer or both.
Why is salaryMin empty?
Most often because enrichStructuredSalary is off by default — with the shipped defaults
salaryMin and nine sibling columns are null on every row (see honest limit 6). Turn it on and it
filled 100% of paid rows (60/60) in run NI8sMc1CRWmghfm1l. It stays empty on volunteer adverts
(no salary exists) and on adverts that state pay only as free text. salaryRaw is 100% filled
either way and carries whatever the charity actually wrote.
⚖️ Legal & fair use
CharityJob's robots.txt (fetched 2026-09-04) opens with, verbatim:
User-agent: *Allow: /
and disallows only /feeds/, /Invoice/ and /attachments/ — none of which this Actor
requests. /jobs, /volunteer-jobs and /organisation are explicitly allowed and are listed in
the site's own jobsitemap.xml. The file additionally names a list of AI/SEO crawlers (Bytespider,
GPTBot, Diffbot, Amazonbot, ClaudeBot, CCBot, PerplexityBot and others) as blocked or crawl-delayed;
this Actor is none of them and does not impersonate them.
This Actor reads only ordinary public pages. It does not log in, does not solve CAPTCHAs, does not forge authentication, and does not fire the site's tracked apply endpoint.
Job adverts can contain personal information (named hiring contacts inside a description). You are the data controller for anything you collect, and you are responsible for complying with CharityJob's Terms of Service, UK GDPR, and any applicable marketing rules (PECR) before contacting anyone. Use the data for market research, lead generation and job aggregation — not for unsolicited bulk email to named individuals.
Built by ScrapersDelight. Not affiliated with, endorsed by, or connected to CharityJob or CharityJob Ltd.