# Jobs.ac.uk Academic Jobs Scraper (`crawlerbros/jobs-ac-uk-scraper`) Actor

Scrape jobs.ac.uk - the UK's leading academic & higher-education job board. Search by keyword/location, browse by discipline, filter by contract type, hours, salary band, workplace and sector, or fetch specific job URLs.

- **URL**: https://apify.com/crawlerbros/jobs-ac-uk-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Jobs.ac.uk Academic Jobs Scraper

Scrape [jobs.ac.uk](https://www.jobs.ac.uk) — the UK's leading job board for academic, research, and higher-education careers. Search by keyword and location, browse by 20 academic and 19 professional-services disciplines, filter by contract type, hours, salary band, workplace and employer sector, or fetch specific job posting URLs directly. HTTP-only against public `jobs.ac.uk` pages. No auth, no proxy, no cookies.

### What this actor does

- **Two modes:** `search` (keyword / location / discipline / filter browsing) and `byUrls` (fetch specific job posting URLs)
- **Full discipline coverage:** 20 academic subject areas (Biological Sciences, Engineering, Law, Psychology, etc.), 89 narrower academic sub-disciplines (e.g. Cyber Security, Software Engineering), and 19 professional-services job families (IT Services, HR, Estates & Facilities, etc.)
- **Postgraduate study listings:** filter to Masters/PhD opportunities by qualification type and funding eligibility
- **Rich filters:** hours (full/part-time), contract type, workplace (remote/hybrid/on-site), 13 salary bands, employer sector, search radius
- **Full job descriptions:** optionally visits each job's detail page for the complete description, structured salary, employment type and closing date
- **Empty fields are omitted**

### Output per job

- `title`, `jobUrl`, `jobReference` (jobs.ac.uk advert code, e.g. `DSI921`)
- `employer`, `employerLogoUrl`, `employerWebsite`
- `department` (when advertised)
- `location`, `locationCity`, `locationRegion`, `locationCountry`
- `salaryRaw` (as advertised), `salaryAmount`, `salaryCurrency`, `salaryPeriod`
- `employmentTypes[]` (e.g. `Full Time`, `Fixed-Term/Contract`)
- `description` (full plain-text job description)
- `datePosted`, `closingDate` — ISO 8601
- `recordType: "job"`, `scrapedAt`

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `search` | `search` / `byUrls` |
| `keywords` | string | `research` | Free-text search terms |
| `location` | string | – | UK town/city/postcode/country (advisory text match against each job's advertised location; jobs.ac.uk ignores this server-side without a browser-resolved place, see FAQ) |
| `distanceMiles` | select | `0` | Search radius around `location` (advisory only, see FAQ) |
| `locationFacet` | string | – | A single real, working jobs.ac.uk location filter — continent/country/UK nation/UK county (e.g. `Scotland`, `Greater London`, `Oxfordshire`); auto-slugified from free text |
| `sortOrder` | select | `relevance` | `relevance` / `datePlaced` / `closingDate` |
| `academicDisciplines` | array (enum) | – | 20 academic subject areas |
| `academicSubDisciplines` | array (enum) | – | 89 narrower academic sub-fields (e.g. Cyber Security, Software Engineering) — independent of `academicDisciplines`, can combine or be used alone |
| `nonAcademicDisciplines` | array (enum) | – | 19 professional-services job families |
| `jobTypes` | array (enum) | – | `masters` / `phds` — restrict to postgraduate study |
| `hoursTypes` | array (enum) | – | `full-time` / `part-time` |
| `contractTypes` | array (enum) | – | `permanent` / `fixed-term-contract` / `temporary` |
| `workplaceTypes` | array (enum) | – | `hybrid` / `remote` / `on-site` |
| `salaryBands` | array (enum) | – | 13 GBP salary bands |
| `employerSectors` | array (enum) | – | 6 employer types |
| `qualificationTypes` | array (enum) | – | PhD qualification type (postgrad listings) |
| `fundingTypes` | array (enum) | – | PhD funding eligibility (postgrad listings) |
| `jobUrls` | array | – | Direct job URLs (mode=byUrls) |
| `fetchFullDescription` | bool | `true` | Visit detail page for full description/salary/dates |
| `maxItems` | int | `25` | Hard cap (1–1000) |

#### Example: computer science jobs in London, full-time & permanent

```json
{
  "mode": "search",
  "keywords": "lecturer",
  "location": "London",
  "distanceMiles": 20,
  "academicDisciplines": ["computer-sciences"],
  "hoursTypes": ["full-time"],
  "contractTypes": ["permanent"],
  "maxItems": 50
}
```

#### Example: funded PhD studentships for UK students

```json
{
  "mode": "search",
  "jobTypes": ["phds"],
  "fundingTypes": ["uk-students"],
  "maxItems": 50
}
```

#### Example: fetch specific job postings

```json
{
  "mode": "byUrls",
  "jobUrls": ["https://www.jobs.ac.uk/job/DSI921/senior-statistical-analyst"]
}
```

### Use cases

- **HE recruitment intelligence** — track hiring trends across UK universities and research institutes
- **Academic job alerts** — build a custom feed filtered by discipline/salary/contract type
- **PhD/Masters discovery** — surface funded postgraduate opportunities by subject and funding type
- **Salary benchmarking** — aggregate advertised salary bands by discipline or sector
- **Employer research** — enumerate all current openings at a specific university or research body

### FAQ

**Does this require a jobs.ac.uk account?** No — all listings and job detail pages scraped are publicly accessible without login.

**Why are some fields (like `department`) missing on some jobs?** Not every advertiser fills in every field (e.g. department is often left blank for external/company employers). Empty fields are omitted rather than returned as null.

**What's the difference between `academicDisciplines` and `nonAcademicDisciplines`?** jobs.ac.uk splits its taxonomy into academic subject areas (used for lecturer/researcher roles) and professional-services job families (used for university administration, IT, HR, estates, etc. roles).

**How do I get funded PhD listings only?** Set `jobTypes: ["phds"]` and optionally `fundingTypes` to restrict by student eligibility (UK/EU/international/self-funded).

**Can I combine multiple filters?** Yes — all filters combine with AND logic, matching jobs.ac.uk's own faceted search.

**Why doesn't `location`/`distanceMiles` actually restrict results?** jobs.ac.uk's own `location`/`distance` query parameters only take effect when `location` is resolved through a browser-side Google Places autocomplete widget (not available to a server-side scraper) — verified live: the site's own result count is identical with and without them. This actor applies `location` as an advisory case-insensitive text match against each job's advertised location instead. For a filter that actually changes which jobs the server returns, use `locationFacet` (e.g. `Scotland`, `Greater London`) — a genuine jobs.ac.uk facet, confirmed live to change the result count. Only pass one `locationFacet` value per run: jobs.ac.uk ANDs multiple location facets together, and since a job only has one location, combining two different regions always yields 0 results.

**How fresh is the data?** jobs.ac.uk lists new roles daily; the `datePosted` and `closingDate` fields (from each job's detail page) reflect the advertiser's own dates.

# Actor input Schema

## `mode` (type: `string`):

What to fetch.

## `keywords` (type: `string`):

Free-text search terms (job title, skill, employer name). Leave empty to browse by discipline/filters only.

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

UK town/city, region, or country text to filter jobs by (e.g. `London`, `Manchester`, `Scotland`). Matched as a case-insensitive substring against each job's advertised location - jobs.ac.uk's own distance-radius search requires a browser-only autocomplete widget with no free server-side equivalent, so this is a text match rather than a precise mile radius.

## `locationFacet` (type: `string`):

A single jobs.ac.uk location facet, as a real working server-side filter (unlike `location`/`distanceMiles` above). Use a continent (`Europe`), country (`United Kingdom`, `Ireland`, `United States`), UK nation (`England`, `Scotland`, `Wales`, `Northern Ireland`) or UK county/city-region (`Greater London`, `Oxfordshire`, `Greater Manchester`, `Cambridgeshire`, etc.) - free text is auto-slugified (e.g. `Greater London` -> `greater-london`). Only ONE value is honored meaningfully: jobs.ac.uk ANDs multiple location facets together, and since a job only has one location, combining two different regions always yields 0 results - so pass a single region per run. An unrecognized value simply yields 0 results rather than erroring.

## `distanceMiles` (type: `integer`):

Sent to jobs.ac.uk alongside `location`, but the site only honors a mile-radius when `location` was resolved through its browser-side autocomplete widget (not available to a server-side scraper), so this has no effect on which jobs are returned. Kept for forward-compatibility only; use a broader/narrower `location` string to widen or narrow results instead.

## `sortOrder` (type: `string`):

Result ordering.

## `academicDisciplines` (type: `array`):

Filter to one or more academic subject areas.

## `academicSubDisciplines` (type: `array`):

Filter to one or more narrower academic sub-fields (e.g. Cyber Security within Computer Sciences). Independent of `academicDisciplines` -- can be used alone or combined.

## `nonAcademicDisciplines` (type: `array`):

Filter to one or more professional-services job families (HE administration, IT, HR, etc.).

## `jobTypes` (type: `array`):

Restrict to Masters or PhD study opportunities instead of staff jobs.

## `hoursTypes` (type: `array`):

Filter by working hours.

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

Filter by contract type.

## `workplaceTypes` (type: `array`):

Filter by remote/hybrid/on-site working arrangement.

## `salaryBands` (type: `array`):

Filter by advertised annual salary band (GBP).

## `employerSectors` (type: `array`):

Filter by type of hiring organisation.

## `qualificationTypes` (type: `array`):

For postgraduate study listings: restrict by qualification type.

## `fundingTypes` (type: `array`):

For postgraduate study listings: restrict by funding eligibility.

## `jobUrls` (type: `array`):

Direct jobs.ac.uk job posting URLs to fetch, e.g. `https://www.jobs.ac.uk/job/DSI921/senior-statistical-analyst`.

## `fetchFullDescription` (type: `boolean`):

Visit each job's detail page to include the full description, structured salary, employment type and closing date. Slower but much richer output. Always on for mode=byUrls.

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

Hard cap on emitted records.

## Actor input object example

```json
{
  "mode": "search",
  "keywords": "research",
  "distanceMiles": 0,
  "sortOrder": "relevance",
  "academicDisciplines": [],
  "academicSubDisciplines": [],
  "nonAcademicDisciplines": [],
  "jobTypes": [],
  "hoursTypes": [],
  "contractTypes": [],
  "workplaceTypes": [],
  "salaryBands": [],
  "employerSectors": [],
  "qualificationTypes": [],
  "fundingTypes": [],
  "jobUrls": [],
  "fetchFullDescription": true,
  "maxItems": 25
}
```

# Actor output Schema

## `jobs` (type: `string`):

Dataset containing all scraped job postings.

# 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 = {
    "mode": "search",
    "keywords": "research",
    "distanceMiles": 0,
    "sortOrder": "relevance",
    "academicDisciplines": [],
    "academicSubDisciplines": [],
    "nonAcademicDisciplines": [],
    "jobTypes": [],
    "hoursTypes": [],
    "contractTypes": [],
    "workplaceTypes": [],
    "salaryBands": [],
    "employerSectors": [],
    "qualificationTypes": [],
    "fundingTypes": [],
    "jobUrls": [],
    "fetchFullDescription": true,
    "maxItems": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/jobs-ac-uk-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 = {
    "mode": "search",
    "keywords": "research",
    "distanceMiles": 0,
    "sortOrder": "relevance",
    "academicDisciplines": [],
    "academicSubDisciplines": [],
    "nonAcademicDisciplines": [],
    "jobTypes": [],
    "hoursTypes": [],
    "contractTypes": [],
    "workplaceTypes": [],
    "salaryBands": [],
    "employerSectors": [],
    "qualificationTypes": [],
    "fundingTypes": [],
    "jobUrls": [],
    "fetchFullDescription": True,
    "maxItems": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/jobs-ac-uk-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 '{
  "mode": "search",
  "keywords": "research",
  "distanceMiles": 0,
  "sortOrder": "relevance",
  "academicDisciplines": [],
  "academicSubDisciplines": [],
  "nonAcademicDisciplines": [],
  "jobTypes": [],
  "hoursTypes": [],
  "contractTypes": [],
  "workplaceTypes": [],
  "salaryBands": [],
  "employerSectors": [],
  "qualificationTypes": [],
  "fundingTypes": [],
  "jobUrls": [],
  "fetchFullDescription": true,
  "maxItems": 25
}' |
apify call crawlerbros/jobs-ac-uk-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,crawlerbros/jobs-ac-uk-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/Ab3vdTXUGWtwR1V65/builds/NieeLKIlw8lcRHgAu/openapi.json
