AcademicPositions Job Scraper — EU Academic Jobs
Pricing
from $6.50 / 1,000 job results
AcademicPositions Job Scraper — EU Academic Jobs
Scrape postdoc jobs, PhD positions & faculty jobs from academicpositions.com (EU, UK & Switzerland). A real browser via residential proxy passes Cloudflare. Returns title, institution, location, field, salary, posted date & apply URL — with delta mode for new-only scheduled runs.
Fetch postdoc, PhD, faculty and early-career-researcher openings from academicpositions.com, covering institutions across the EU, UK and Switzerland.
How it works
academicpositions.com sits behind Cloudflare's bot protection, so this Actor
drives a real headless browser (Playwright/Chromium) through an Apify
Residential proxy to load pages the same way a person's browser would.
Each posting is parsed from the page's structured JobPosting data
(schema.org JSON-LD), with a plain-HTML fallback for the rare page that omits
it — so results stay accurate even as the site's front-end layout changes.
What data does this Actor extract?
Each result is one flat JSON record per job posting:
| Field | Type | Description |
|---|---|---|
title | string | Job title as posted |
company | string | null | Hiring institution name |
location | string | null | Posting location (city/region/country, or "remote" wording for remote roles) |
field | string | null | Research area / discipline the posting itself labels (e.g. "Physics", "Life sciences"), read verbatim from JSON-LD occupationalCategory/industry or a discipline chip — never inferred from the title |
url | string | Direct link to the posting |
postedAt | string | null | Posting date (ISO 8601, e.g. "2026-06-20"), when the source provides one |
snippet | string | null | Plain-text excerpt of the job description |
salary | string | null | Human-readable pay summary (e.g. "3000-4200 EUR MONTH"), only when the posting discloses baseSalary — most academic postings don't, so usually null |
salaryMin / salaryMax | number | null | Structured pay range endpoints from JSON-LD baseSalary, when present |
salaryCurrency | string | null | Currency code for the salary range (e.g. "EUR"), when present |
globalId | string | null | Stable cross-run id (academicpositions:<detail-path>) — the dedup key for delta mode |
isNew | boolean | null | Only present in delta mode (onlyNewSinceLastRun) — always true (already-seen postings are dropped, never emitted with isNew: false) |
source | string | Always "academicpositions" |
Fields come back as null (never an empty string) on the rare posting where
the source doesn't provide that piece of data.
How to scrape academicpositions.com with this Actor
- Click Try for free / Run — the default input needs no changes.
- Optionally set a
keyword,countryFilterorpostedSinceto narrow results, and adjustmaxItems. - Run it and export the dataset as JSON, CSV or Excel, or read it over the API.
Run it from your own code:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("nomad-agent/academicpositions-scraper").call(run_input={"maxItems": 30, "keyword": "machine learning postdoc"})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item["title"], "—", item["company"], item["url"])
Or a single HTTP call that runs the Actor and returns items in one response:
curl -X POST \"https://api.apify.com/v2/acts/nomad-agent~academicpositions-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \-H "Content-Type: application/json" \-d '{"maxItems": 30}'
Input
| Field | Type | Default | Notes |
|---|---|---|---|
keyword | string | (empty) | Free-text query appended to the listing URL (e.g. "postdoc", "computer science"). Leave empty to scrape the default listing. |
countryFilter | string | (empty) | Case-insensitive substring match on the extracted location field (e.g. "Germany"). Applied client-side, after extraction. Leave empty to keep every location. |
postedSince | string | (empty) | Only return postings dated on or after this date (YYYY-MM-DD). Postings without a parseable date are kept, not dropped. Leave empty to disable. |
maxItems | integer | 30 | Maximum number of postings to return. Each returned posting is billed as one dataset result — capped at 500 per run. |
onlyNewSinceLastRun | boolean | false | Delta / monitoring mode: only return postings not already seen on a previous run made with this flag on. Already-seen postings are dropped before push, so you are never billed for them (see "Delta mode / monitoring"). |
proxyConfiguration | object | Apify Residential proxy | Proxy used to load the site. Keep the Residential group selected — academicpositions.com blocks non-residential IPs. |
startUrl (Advanced) | string | https://academicpositions.com/find-jobs | The listing page the Actor starts from and harvests job links from. Change only to start from a specific saved-search URL instead of the default listing. |
detailUrlContains (Advanced) | string | /ad/ | Only links whose URL contains this text are treated as job-detail pages. Change only if the site's URL structure changes and the Actor stops finding postings. |
useResidentialProxy (Advanced, deprecated) | boolean | true | Superseded by proxyConfiguration above. Still honored when proxyConfiguration is left unset, for older integrations. |
Output example
{"title": "Postdoctoral Researcher in Quantum Computing","company": "TU Delft","location": "Delft, Netherlands","field": "Physics","url": "https://academicpositions.com/ad/tu-delft/2026/postdoctoral-researcher-in-quantum-computing/12345","postedAt": "2026-06-20","snippet": "Join our lab working on superconducting qubits and scalable quantum error correction...","salary": null,"salaryMin": null,"salaryMax": null,"salaryCurrency": null,"globalId": "academicpositions:ad/tu-delft/2026/postdoctoral-researcher-in-quantum-computing/12345","source": "academicpositions"}
Delta mode / monitoring
Set onlyNewSinceLastRun: true to turn this Actor into a "what's new" monitor.
Postings already delivered on a previous run made with this flag on are dropped
before the billed push step — you are not charged for them — so pairing this
with an Apify schedule (cron) means every run only returns, and only bills
for, academic jobs that appeared since the last flagged run. Each emitted
record is stamped isNew: true.
How it works: seen postings are tracked in a dedicated key-value store keyed by
each posting's globalId (a stable id derived from its canonical detail-page
URL), capped at ~50,000 entries with the oldest evicted first. The first run
made with the flag on has nothing to compare against, so it emits everything.
There is no isNew: false in the output — unseen-yet postings simply aren't
included.
Pricing
Pay per event: $0.02 per Actor start and $0.008 per posting returned ($8 / 1,000 postings, less on higher Apify plans — down to $6.50 / 1,000). 100 postings ≈ $0.82. No subscription, no rental — you pay only for what you fetch. The price covers the real headed browser + residential proxy each run needs to pass Cloudflare.
This Actor also routes every request through Apify's Residential proxy group (required to get past academicpositions.com's bot protection), which is billed separately by Apify against your account's residential proxy GB allowance in addition to the per-event charges above.
Integrations
Export results as JSON, CSV or Excel, pull them via the
Apify API or run-sync-get-dataset-items,
wire this Actor into Make, Zapier or n8n, or call it from AI agents through
the Apify MCP server.
Use cases
- Academic job boards and alert bots for postdocs, PhD candidates and faculty
- University career-services aggregation
- Research on hiring trends across EU/UK/CH institutions
- Building a searchable database of research openings
FAQ
Is it legal to scrape academicpositions.com? This Actor reads only publicly available job postings — data any visitor can see without logging in. Review the target site's terms and your local regulations for your specific use case.
Do I need an account on academicpositions.com? No. Postings are fetched from public pages — no login, cookies or session tokens required.
Why does this Actor need a residential proxy? academicpositions.com fronts its pages with Cloudflare Bot Fight Mode, which blocks datacenter IPs outright. A residential exit IP plus a real browser is what reliably gets through the challenge.
How fresh is the data? Every run fetches live listings directly from the site — there's no cache.
Something broken or missing? Open an issue on the Actor's Issues tab — it is monitored and reliability fixes ship fast.