Big Four Careers Scraper - Deloitte, PwC, EY, KPMG & More
Pricing
from $1.20 / 1,000 result scrapeds
Big Four Careers Scraper - Deloitte, PwC, EY, KPMG & More
Pull every open role at the Big Four and adjacent professional-services firms across Europe, verified from their own career pages, not a job board index. Covers Deloitte, PwC, EY, KPMG and more, with real location, language and ATS platform per role. Diff mode reports new/removed roles.
Pricing
from $1.20 / 1,000 result scrapeds
Rating
0.0
(0)
Developer
Studio Amba
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
Big Four Careers Scraper — Verified Live Roles from Deloitte, PwC, EY, KPMG & More
Every open role at the Big Four and adjacent professional-services firms across Europe, verified from their own career pages, with a daily appeared/disappeared diff. Covers Deloitte, PwC, EY, KPMG, BDO, Forvis Mazars, Grant Thornton, RSM and a supporting roster of banks, insurers and asset managers across the EU/EEA, UK and Switzerland.
What you get
- ~2,500 live roles per run, pulled fresh from each employer's own careers system, not re-indexed from a job board.
- 18 firms, 24 European countries, 6 ATS platforms in a single run. Deloitte, PwC, EY, KPMG, BDO, Forvis Mazars, Grant Thornton, RSM and more.
- Verified live. Every role is confirmed open on the employer's own page at run time, with the real location, real posting language, and the ATS platform it came from.
- Daily diff mode. Put it on a schedule and get only the roles that appeared or disappeared since your last run. A hiring-signal feed by employer.
- ~90 seconds per full run. Pay per result, no subscription. Narrow by country or employer to pay for only what you need.
Why use this actor?
Job boards re-index what a firm posts, on their own schedule, with their own taxonomy. This actor reads each employer's Applicant Tracking System (ATS) directly, so every row carries what a board can't reliably give you: the real location (parsed from the ATS, not a board's regional feed), the real posting language, confirmation the role is live on the employer's own site right now, and which ATS platform the employer runs (Workday, SuccessFactors, Avature, Radancy, SmartRecruiters, Greenhouse and others).
A companion diff mode turns the same pull into a hiring-signal feed: run it on a schedule and it reports only which roles newly appeared or disappeared since the last run, instead of re-exporting the whole list every time.
Built on a proven ATS-detection mechanism (see docs/strategy/eu-employer-jobs-poc-findings-2026-08-16.md in the source repo), then widened in two stages: first to a ~32-employer BE/LU/CH/NL/FR finance/tax roster, then rescoped on 2026-08-16 to the Big Four and adjacent professional-services firms across all of Europe — see docs/strategy/big-four-adjacent-board-map-2026-08-16.md for the full board-mapping research behind this roster (which firms run a single pan-European ATS tenant vs a separate board per country, and why).
How to scrape Big Four careers data from Deloitte, PwC, EY and KPMG
- Leave the input empty (
{}) to run the full built-in roster — Deloitte, PwC, EY, KPMG, BDO, Forvis Mazars and more across Europe. - Narrow it with
countries(e.g. onlyDE) oremployerNames(e.g.["Deloitte", "PwC"]) to focus a run. The country filter works at the ROLE level: pan-European boards are pulled and filtered down, so acountries: ["IE"]run returns Deloitte Ireland plus PwC's and EY's Irish roles, not PwC's whole pan-EU board. - Add your own employers with
customEmployers— just a name, country and careers-page URL. The same ATS-detection pipeline runs against them automatically; no per-employer scraper code needed. - Switch
modetodiffand put the actor on a schedule (daily is plenty — corporate careers pages don't churn roles faster than that) to get an appeared/disappeared feed instead of a full re-export every run. - Read
locationCountry,locationCity,employerAtsPlatformandverifiedLiveAton every row — that's the ATS-sourced data a job board can't give you.
Single-tenant multipliers — one board, many countries
Several firms in this roster run ONE shared ATS tenant across multiple countries rather than a separate board per market — the highest-leverage entries in the roster:
- PwC — one shared Workday tenant (
pwc.wd3.myworkdayjobs.com) serves Ireland, Netherlands, Belgium, Luxembourg, Austria, France, Spain, Switzerland, Denmark and Poland from a single board (confirmed live: 1,000+ roles across 8+ European countries in one fetch). - EY —
careers.ey.comis genuinely global: one SAP SuccessFactors tenant, country is a facet, not a separate URL (confirmed live: ~7,300 roles worldwide, most European markets represented). - Deloitte Central Europe — one white-label Avature board (
apply.deloittece.com) covers Poland, Czech Republic, Slovakia, Romania and Hungary. - Deloitte Central Mediterranean — one Avature board (
deloittecm.avature.net) covers Italy and Greece. - Deloitte Nordic — one SmartRecruiters board (
careers.smartrecruiters.com/DeloitteNordic) covers Sweden, Norway, Denmark and Finland.
Firms with genuinely SEPARATE per-country boards (Deloitte UK/Belgium/Switzerland/Germany/Luxembourg/Portugal/Austria, KPMG, most of the adjacent tier) each get their own roster row.
How ATS detection works
For each employer, the actor fetches the careers-page URL, fingerprints which ATS it runs by looking for that platform's own domain or markup in structural locations only — a script tag, a link href, an iframe src, a canonical URL, a genuine <a href> to the ATS's own domain, or a literal URL string inside an inline <script> JSON hydration payload (common on Next.js/React career sites). It never trusts loose body text, which matters: both KPMG's and PwC's marketing pages mention "Workday" in a nav link because they're Workday implementation partners, not because that's how they run their own hiring — a naive keyword search would misfire on that; this actor doesn't. It also excludes known non-jobs Avature tenants (talent-community/newsletter signup portals some firms link from their real, differently-hosted jobs page) from counting as evidence.
Once the platform is known, a dedicated fetcher pulls the live roster directly:
| Platform | Method | Notes |
|---|---|---|
| Workday | Official CXS JSON API | Paginated 20 rows/request. Locale-prefixed site paths (e.g. /en-GB/) are handled. |
| SuccessFactors Career Site Builder | Server-rendered HTML, paginated via ?startrow=N | Two link shapes recognized: performancemanagerN.successfactors.* and career5.../career?company=X. |
| Avature | Server-rendered HTML, paginated via ?jobOffset=N | Both the standard tenant.avature.net theme and white-label deployments on the employer's own domain (detected via an Avature portal meta tag) are supported, across two different card-markup themes. |
| Radancy ("TMP Worldwide") | AJAX results endpoint, paginated via CurrentPage | Three markup themes seen and handled. |
| SmartRecruiters | Official public JSON API | Board tokens resolved from jobs.smartrecruiters.com job-detail permalinks (the only structural evidence these career pages actually render). |
| Greenhouse | Official public JSON API | Recognizes both the legacy boards.greenhouse.io and the newer region-prefixed job-boards.<region>.greenhouse.io domains. |
| Ashby, Lever | Official public JSON APIs | Not yet matched to an employer in the current roster — kept ready for the next one that uses them. |
Detection is cached per employer (14-day TTL, a named key-value store) so a tenant that already resolved once doesn't re-run the full multi-candidate probe on every single run. If a cached detection stops working, the actor transparently re-detects.
Vertical scoping: a single-country entry point sometimes turns out to be a genuinely GLOBAL tenant once pulled — confirmed live: PwC's Workday board and EY's SuccessFactors board both list offices worldwide. Every role's parsed locationCountry is checked against the full EU/EEA + UK + CH country set; a role resolved to a different country is dropped, one with an unresolved location is kept (better to keep an ambiguous in-scope role than drop real coverage over a city our lookup table doesn't have yet).
Parked platforms
Two employers are detected but deliberately never fetched, because the block is at the network edge, not an ATS-detection gap:
- BNP Paribas Group (
group.bnpparibas) — Akamai edge block, HTTP 403 to both a plain request and a real headless browser. - Zurich Insurance (
zurich.com/careers) — Imperva Incapsula JS-challenge wall, an empty iframe shell to a plain fetch.
Both need Bright Data's Web Unlocker (currently blocked by a rejected BD KYC application) or a captured real-user network trace. They're excluded with a documented reason rather than silently failing the run.
Several other firms/boards researched are behind similar bot-mitigation (McKinsey/Akamai, Bain/Cloudflare Turnstile, RSM Netherlands/Cloudflare) and are simply not in the active roster yet rather than being fetched and failing every run.
Phenom People, Talentsoft, Cornerstone OnDemand, Oracle Recruiting Cloud, Yello, Pinpoint, Teamtailor, Recruitee and eRecruiter are real platforms confirmed live across multiple firms in this vertical (see the board-mapping doc) but not fingerprinted yet — several of those employers are kept in the roster reporting unknown honestly, as the next platform worth adding.
Input
| Field | Type | Required | Description |
|---|---|---|---|
mode | String | No | full (default) returns every verified-live role this run. diff returns only roles that newly appeared or disappeared since the last run. |
countries | Array | No | Return only roles located in these countries (ISO 3166-1 alpha-2, any EU/EEA + UK + CH code, e.g. DE, FR, PL). Pan-European boards (PwC's shared Workday tenant, EY's global board) are included automatically and filtered down to your countries — you never lose a firm's roles in a country just because its board is registered elsewhere. A role whose location text could not be resolved to a country is kept only when the whole board's coverage sits inside your filter. |
employerNames | Array | No | Filter the built-in roster to employers whose name contains one of these strings. |
customEmployers | Array | No | Add your own {name, country, careersUrl} employers, run through the same detection pipeline. |
maxRolesPerEmployer | Integer | No | Cap on roles pulled per employer per run. Default 150. |
resetState | Boolean | No | Testing only — clears diff-mode tracking history before the run. |
proxyConfiguration | Object | No | Every targeted ATS is a public JSON API or plain HTML page with no anti-bot (confirmed live, zero blocks) — automatic/no-groups is correct by default. |
Output
One row per verified-live role in full mode, one row per appeared/disappeared event in diff mode, plus an occasional run_status housekeeping row (first-run seeding, or a genuinely quiet diff run — never an empty dataset).
| Field | Type | Example |
|---|---|---|
eventType | String or null | "appeared", "disappeared", or null for a straight live listing |
jobTitle | String | "Senior Associate - Legal Transformation & Managed Services" |
employer | String | "PwC (Workday network — IE/NL/BE/LU/AT/FR/ES/CH/DK/PL)" |
employerBrand | String | "PwC" — clean grouping key per firm, without the board naming |
employerAtsPlatform | String | "workday" |
locationCity | String or null | "Amsterdam" — null when the ATS text didn't resolve |
locationCountry | String or null | "NL" (ISO 3166-1 alpha-2) — null when unresolved |
locationRaw | String | "Amsterdam" — untouched location text as returned by the ATS |
language | String or null | "en" |
employmentType | String or null | "Full time" |
url | String | Direct application URL on the employer's own ATS |
reqId | String or null | "1396234733" |
postedAt | String or null | Best-effort ISO date; null when the ATS only gives a vague relative label |
verifiedLiveAt | String or null | ISO timestamp this run confirmed the role live; null for a disappeared row |
lastSeenAt | String | ISO timestamp of the last run that saw this role live |
source | String | Always "employer-ats" |
Example output
{"eventType": null,"jobTitle": "Gestionnaire de paie - H/F - Bayonne","employer": "Forvis Mazars France","employerAtsPlatform": "smartrecruiters","locationCity": "Bayonne","locationCountry": "FR","locationRaw": "Bayonne, fr","language": null,"employmentType": "Full-time","url": "https://jobs.smartrecruiters.com/MAZARS/744000143639529","reqId": "744000143639529","postedAt": "2026-08-15T07:28:57.976Z","verifiedLiveAt": "2026-08-16T16:19:45.662Z","lastSeenAt": "2026-08-16T16:19:45.662Z","detectedAt": "2026-08-16T16:19:55.546Z","source": "employer-ats","recordType": "live_role"}
Scheduling for diff mode
Diff mode's entire value is in the delta, not the snapshot — put it on a schedule, not a one-off run.
- Apify Console → your run → Schedules → Create new schedule.
- Daily is a reasonable cadence — corporate careers pages don't churn roles faster than that.
- Leave
resetStateoff between scheduled runs — enabling it wipes tracking history and turns every run back into a first-run seed. 3b. Keep the samecountries/employerNamesfilters on every run of a schedule. The diff baseline only contains what past runs actually pulled, so changing filters mid-schedule reports the newly-included scope as one big batch of appeared roles. 3c.disappearedevents for an employer only fire when the run pulled that employer's full in-scope list. A capped (partial) pull can't prove a role left the ATS, so it reports appearances only — raisemaxRolesPerEmployerabove the employer's live-role count if disappearances matter to you. - The first scheduled run always seeds (one
run_statusrow per employer, no delta events yet — there's nothing to diff against). Every later run reports real appeared/disappeared events.
Cost estimate
Workday, SmartRecruiters and Greenhouse cost roughly one HTTP request per 20–100 roles (each platform's own JSON API page-size ceiling). The HTML-tier platforms (SuccessFactors, Avature, Radancy) cost one request per 15–25 roles. Per-result compute is minimal — no browser rendering, no proxy spend on any currently-supported platform. Actor usage is billed per result and per run start; your Apify usage dashboard is the source of truth. Usage cost for a run only settles after it reports SUCCEEDED — reading the dataset mid-run will undercount what you'll actually be billed.
Limitations
- Detection coverage is honest, not exhaustive. Roughly half the built-in roster resolves to a known, currently-supported ATS today (see the
unknown/parked notes in the run log for the rest) — employers on platforms this actor doesn't fingerprint yet (Phenom People, Talentsoft, Cornerstone OnDemand, and several bespoke in-house systems) reportunknownrather than being silently skipped or faked. postedAtis best-effort. Several ATSs only expose a relative label ("Posted Today", "30+ Days Ago") with no exact timestamp; a vague label yieldsnullrather than a fabricated date.employmentTypeis exactly as labeled by the ATS, not normalized across employers ("Full time"vs"Tijdelijk"vs"Permanent"all appear verbatim).- A country filter on a non-Workday pan-European board is applied after pulling. Workday tenants are filtered server-side (the query itself is scoped to your countries), but EY's global SuccessFactors board can only be pulled in its own ordering and filtered afterwards, bounded by
maxRolesPerEmployer. RaisemaxRolesPerEmployerwhen you filter to a single country and want deep EY coverage there — the run log reports exactly how many fetched roles the filter dropped per employer. - Location resolution favors coverage over strict precision on huge global tenants. A role whose ATS text has no country name or code at all can't be resolved to a country and is kept rather than dropped — the alternative would also drop genuine in-scope roles whose city just isn't in the curated lookup table yet. A role with a RECOGNIZED non-European country is always dropped.
- Data is scraped from each employer's own public careers page and may change without notice.
Need this data on a schedule, or a custom version?
We run this scraper as a managed service for businesses: scheduled runs, deduplication, delta detection, and delivery to your inbox, Google Sheets, or API — maintenance included. We can also widen the employer roster to your specific target list or combine it with other sources into one feed.
See studioamba.dev/services or email hello@studioamba.dev for a free data sample. We maintain 300+ European web scrapers and answer within one business day.