# Reed Scraper — UK Jobs, Salaries & Recruiters (`tortuga/reed-scraper`) Actor

Scrape Reed.co.uk jobs by keyword, location, salary, contract type, remote/hybrid or URL: title, employer, salary text with parsed GBP min/max, dates; optional full description.

- **URL**: https://apify.com/tortuga/reed-scraper.md
- **Developed by:** [Trevor Ortega](https://apify.com/tortuga) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.30 / 1,000 job scrapeds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Reed Scraper — UK Jobs, Salaries & Recruiters

Scrape job ads from **Reed.co.uk**, one of the UK's largest job boards, by keyword and location with Reed's own
filters (distance, salary range, permanent / contract / temporary, full-time / part-time, date posted, remote /
hybrid / on-site, agency or employer, graduate, Easy Apply, visa sponsorship), or from any Reed search URL or
company jobs page. For every job you get the title, the employer or recruitment agency with its Reed profile link and
logo, location and county, the **salary line exactly as Reed shows it** ("£650 - £750 per day", "£45,000 per annum,
OTE", "Competitive salary") **plus parsed min / max / period / currency**, contract type, working hours, remote /
hybrid / on-site, posted, updated and expiry dates, Easy Apply and badges, Reed's job category and the description
snippet. Optionally it adds the **full description**, sector, town / region / postcode, the annual pay equivalent,
the advertiser's job reference and whether the job is still live.

No Reed account, no API key, no browser. Fast: 100 jobs per request, about 1,000 jobs in 6 seconds. Export to JSON,
CSV, Excel or use the API.

### What data does the Reed Scraper return?

| Field | Example | Notes |
|---|---|---|
| `jobId`, `url` | `57377207`, `https://www.reed.co.uk/jobs/python-developer/57377207` | |
| `title` | `Python Developer` | |
| `employer`, `postedBy` | `Hays Specialist Recruitment Limited`, `agency` | `agency` (recruitment consultancy) or `employer` (direct) |
| `employerProfileUrl`, `employerLogoUrl` | `https://www.reed.co.uk/jobs/hays-specialist-recruitment-limited/p36210` | Reed's "all jobs from this advertiser" page |
| `location`, `county` | `Watford, Hertfordshire`, `Hertfordshire` | as on the job card |
| `salaryText` | `£550 - £617.55 per day` | Reed's salary line, also `Competitive salary`, `Salary negotiable`, `Training Course`... |
| `salaryMin`, `salaryMax`, `salaryPeriod`, `salaryCurrency` | `550`, `617.55`, `day`, `GBP` | period: hour, day, week, month, year; null when the employer hides the figures |
| `salaryNotes` | `["OTE", "inc benefits"]` | OTE, inc benefits, pro-rata, negotiable |
| `contractType`, `workingHours` | `Contract`, `full-time` | Permanent / Contract / Temporary; full-time, part-time or "full-time or part-time" |
| `workplaceType`, `isRemote` | `remote`, `true` | remote, hybrid, on-site (null when the ad does not say) |
| `postedAt`, `createdAt`, `updatedAt`, `expiresAt` | `2026-09-22T08:38:10.017` | UK time; `postedAt` is the date Reed shows on the card |
| `easyApply`, `isFeatured`, `isPromoted`, `isEarlyBird` | `true`, `false`, `false`, `true` | Reed's badges on the job card ("Easy Apply", "Featured", "Promoted", "Early bird") |
| `ukApplicantsOnly`, `isTrainingCourse` | `false`, `false` | |
| `category`, `occupation` | `Developer`, `Python Developer` | Reed's job taxonomy |
| `descriptionSnippet` | `Your new company You will be supporting a major ...` | first ~150 characters |
| `searchKeyword`, `searchLocation`, `searchUrl`, `scrapedAt`, `detailsFetched` | | where and when the job was found |
| `description`, `descriptionHtml` | `Your new company\nYou will be supporting ...` | with **Include full job description** |
| `sector`, `specialism` | `Web Developer`, `IT & Telecoms` | with details |
| `town`, `region`, `country`, `countryCode`, `postcode` | `York`, `Yorkshire and Humberside`, `United Kingdom`, `GB`, `YO32` | with details; postcode when the advertiser gave one |
| `salaryPerAnnumMin`, `salaryPerAnnumMax` | `143000`, `160563` | with details: Reed's annual equivalent of day / hourly rates |
| `jobReference`, `recruiterType` | `4830766`, `Recruitment consultancy` | with details: the advertiser's own reference |
| `skills` | `["Registered Nurse", "Care Planning", "NMC Registration"]` | with details: the advertiser's skill tags (about 30% of ads) |
| `isGraduate`, `applyOnExternalSite` | `false`, `false` | with details |
| `status`, `isExpired` | `Live`, `false` | with details: `Expired` for closed ads (job URLs) |

Reed does not publish how many people applied to a job, so there is no applicant count; `isEarlyBird` is Reed's
"Early bird" badge exactly as the job card shows it.

### How to scrape Reed jobs by keyword and location

1. Enter one or more **Keywords** (job title, skill or company) and a **Location** such as `London`, `Manchester`,
   `Kent` or a postcode like `SW1A 1AA`. Leave the location empty for the whole UK, or type `Remote` for remote jobs.
2. Optionally set filters: distance, salary from / to (GBP per year), contract type, full-time / part-time, remote /
   hybrid / on-site, date posted, agency or employer, graduate, Easy Apply, visa sponsorship, and sort by date.
3. Set **Max jobs** and run.

```json
{
  "keywords": ["accountant", "finance manager"],
  "location": "Leeds",
  "distance": 20,
  "salaryMin": 35000,
  "contractTypes": ["permanent"],
  "workplaceType": "hybrid",
  "postedWithin": "lastweek",
  "maxItems": 500
}
```

**Skip training-course ads** is on by default: Reed mixes paid training courses ("Trainee Cyber Security Analyst -
job guarantee", shown with "Training Course" instead of a salary) into job results, sometimes half of a search.
Turn it off to get exactly what Reed lists.

You can also paste Reed URLs into **Start URLs**: search pages with any filters you set on the site, a company's
jobs page, and single job pages (returned with full details):

```json
{
  "startUrls": [
    { "url": "https://www.reed.co.uk/jobs/accountant-jobs-in-leeds?proximity=20&salaryFrom=30000&perm=True" },
    { "url": "https://www.reed.co.uk/jobs/hays-specialist-recruitment-limited/p36210" },
    { "url": "https://www.reed.co.uk/jobs/python-developer/57377207" }
  ],
  "maxItems": 300
}
```

#### Output example

```json
{
  "jobId": 57418395,
  "url": "https://www.reed.co.uk/jobs/python-developers/57418395",
  "title": "Python Developers",
  "employer": "INTEC SELECT LIMITED",
  "employerProfileUrl": "https://www.reed.co.uk/jobs/intec-select-limited/p41618",
  "employerLogoUrl": "https://resources.reed.co.uk/profileimages/logos/thumbs/Logo_41618.png",
  "postedBy": "agency",
  "location": "London",
  "county": "London",
  "salaryText": "£650 - £750 per day",
  "salaryMin": 650,
  "salaryMax": 750,
  "salaryPeriod": "day",
  "salaryCurrency": "GBP",
  "salaryNotes": [],
  "contractType": "Contract",
  "workingHours": "full-time",
  "workplaceType": "hybrid",
  "isRemote": false,
  "postedAt": "2026-10-02T16:58:06.81",
  "expiresAt": "2026-11-13T23:55:00",
  "descriptionSnippet": "Software Developer - Python (Contract) Location: London - Hybrid, 2 days/week on-site Contract: Initial 6 months ...",
  "easyApply": true,
  "isEarlyBird": false,
  "category": "Developer",
  "occupation": "Python Developer",
  "searchKeyword": "python developer",
  "searchLocation": "London",
  "detailsFetched": false
}
```

### How many jobs can I get per search?

Reed serves at most **10,000 jobs for any one search** (deeper pages repeat the last ones). With **Get more than
Reed's 10,000 results per search** (on by default) the actor splits a bigger search into narrower ones that together
cover it exactly: by Reed's 37 specialisms, then permanent / contract / temporary, then agency / employer; a slice
that is still too big is read in both sort orders. Duplicates are removed. In tests, every job in London (Reed:
22,844) came back complete, **22,844 of 22,844**, from 251 requests in 53 seconds, and every job in the UK (start URL
`https://www.reed.co.uk/jobs`, Reed: 97,944) gave **97,975 distinct jobs** (new ads appeared during the run) from
1,002 requests in about 3 minutes.

### Can I get the full job description?

Yes. Turn on **Include full job description**. For each job the actor reads the job's page data and adds the full
description (plain text and HTML), sector and specialism, town, region, country and postcode, the annual pay
equivalent of day and hourly rates, the graduate flag, the advertiser's job reference, the advertiser type
(recruitment consultancy / direct employer) and whether the ad is still live. It is one extra small request per job
(about 4 KB). Single job URLs in Start URLs always come with details. Apply e-mails and recruiter contact details are
not collected.

### Does it work without login? Is a proxy needed?

It works without any login, cookies or Reed API key: it reads the same public data the Reed website loads in your
browser. Reed blocks Apify's datacenter IPs, so the actor uses Apify's **residential proxy with UK IPs** by default
(and switches to it automatically if another proxy gets blocked). Residential traffic is small because the actor
reads compact JSON instead of web pages; see the proxy note below.

### Monitor changes on a schedule

Turn on **Only new or changed items** to watch a search: each run remembers what earlier runs returned and outputs
only jobs that are new or whose title or salary changed. Unchanged jobs are dropped before any details are read, so
they are not charged. **Max jobs** then sets how many jobs are checked per run; sort by date so the newest jobs land in
that window. Save the input as a task and add a Schedule in Apify (for example daily); give each watch its own
**Monitoring key** if several schedules use the same search. Every output item has `changeType` (`new` or
`changed`), and changed jobs have `previousValues` with the old values, e.g. `{"salaryText": "£650 - £750 per day"}`.

### Pricing

Pay per job: **$0.0003 per job** ($0.30 per 1,000). With **Include full job description** (or for a job URL) each job
adds a **$0.0001 detail** event, so $0.40 per 1,000 jobs with full descriptions. No start fee, no subscription and no
extra charge for monitoring.

### Proxy note and cost

The default proxy is Apify RESIDENTIAL with UK IPs, which Apify bills by traffic on your account. The actor reads
Reed's compact JSON: about 21 KB per 100 jobs and about 4 KB per job description. Measured total platform usage on
top of the per-job price (proxy traffic, compute, storage): about **$0.007 per 1,000 jobs** without details and about
**$0.04 per 1,000 jobs** with details. Requests that fail or come back blocked are retried automatically on a new IP.

### Is it legal to scrape Reed?

The actor reads only public job ads that anyone can open on Reed.co.uk without an account: what employers and agencies
publish, their names and pay information. It does not log in and does not collect job seekers' data, apply e-mails
or recruiter contact details. Salary figures that the employer chose to hide ("Competitive salary", "Salary
negotiable") are not exported. You are responsible for using the data in line with Reed's terms and the data
protection laws that apply to you (for example UK GDPR).

# Actor input Schema

## `keywords` (type: `array`):

One search per keyword, e.g. "python developer", "nurse", "accountant". Leave empty to list every job matching the location and filters.

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

Where, as you would type it on Reed: a town or city ("Manchester"), a county ("Kent") or a postcode ("SW1A 1AA"). Leave empty for the whole UK. "Remote" = remote jobs only.

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

Radius around the location. Reed offers 0, 1, 3, 5, 10, 15, 20, 30 and 50 miles (other values are rounded to the nearest); Reed's default is 10.

## `salaryMin` (type: `integer`):

Reed's salary filter "From", in GBP per year, e.g. 30000.

## `salaryMax` (type: `integer`):

Reed's salary filter "To", in GBP per year, e.g. 60000.

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

Only permanent, contract or temporary jobs. Several = any of them.

## `workingHours` (type: `string`):

Only full-time or only part-time jobs.

## `workplaceType` (type: `string`):

Only remote, hybrid or on-site jobs.

## `postedWithin` (type: `string`):

Only jobs posted within this period.

## `postedBy` (type: `string`):

Only jobs posted by recruitment agencies or only jobs posted directly by employers.

## `graduateOnly` (type: `boolean`):

Reed's "Graduate" experience-level filter.

## `easyApplyOnly` (type: `boolean`):

Only jobs you can apply to on Reed with Easy Apply.

## `visaSponsorshipOnly` (type: `boolean`):

Only jobs that Reed marks as offering visa sponsorship (few jobs have this).

## `excludeTrainingCourses` (type: `boolean`):

Reed mixes paid training courses ("Trainee ... with job guarantee", shown with "Training Course" instead of a salary) into job results, sometimes half of a search. On = only real job ads, for keyword searches and search URLs. Off = exactly what Reed lists.

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

Relevance (Reed's default for keyword searches) or newest first (Reed's default without keywords).

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

Optional: Reed search URLs with any filters set on the site, e.g. https://www.reed.co.uk/jobs/accountant-jobs-in-leeds?salaryFrom=30000\&perm=True, company job pages (https://www.reed.co.uk/jobs/<company>/p<id>), or single job URLs (https://www.reed.co.uk/jobs/<title>/<id>), which are returned with full details.

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

Stop after this many jobs in total (you pay per job saved).

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

Optional cap for each keyword / start URL, so one search does not use the whole Max jobs budget.

## `splitLargeSearches` (type: `boolean`):

Reed shows at most 10,000 jobs for any search. With this on, a bigger search is split by specialism, contract type and agency/employer (and read in both sort orders when a slice is still too big), so you get all or nearly all of its jobs. Each extra page is one small request.

## `includeDetails` (type: `boolean`):

Read each job's page data for the full description (text and HTML), sector and specialism, town, region, country and postcode, annual pay equivalent, graduate flag, the advertiser's job reference, recruiter type and whether the job is still live. One extra small request and one 'detail' event per job.

## `onlyNewOrChanged` (type: `boolean`):

Remember what earlier runs of this search returned and output only new jobs or jobs whose title or salary changed. Use with a Schedule; unchanged jobs are not charged. With this on, Max jobs is the number of jobs checked per run; sort by date to watch the newest jobs.

## `monitoringKey` (type: `string`):

Name for this watch, so several schedules on the same search stay separate; defaults to a key derived from the search input

## `proxyConfiguration` (type: `object`):

Reed blocks Apify datacenter IPs, so the default is Apify RESIDENTIAL proxy with UK IPs (any other proxy that gets blocked is switched to it automatically). Traffic is small: about 15 KB per 100 jobs and 5 KB per job description, so roughly 0.2 MB per 1,000 jobs (about 3 MB with descriptions), billed by Apify as residential proxy data.

## Actor input object example

```json
{
  "keywords": [
    "python developer"
  ],
  "location": "London",
  "workingHours": "",
  "workplaceType": "",
  "postedWithin": "",
  "postedBy": "",
  "graduateOnly": false,
  "easyApplyOnly": false,
  "visaSponsorshipOnly": false,
  "excludeTrainingCourses": true,
  "maxItems": 100,
  "splitLargeSearches": true,
  "includeDetails": false,
  "onlyNewOrChanged": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "GB"
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# 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 = {
    "keywords": [
        "python developer"
    ],
    "location": "London",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "GB"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("tortuga/reed-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 = {
    "keywords": ["python developer"],
    "location": "London",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "GB",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("tortuga/reed-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 '{
  "keywords": [
    "python developer"
  ],
  "location": "London",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "GB"
  }
}' |
apify call tortuga/reed-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tortuga/reed-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/70E9g4vsP78Q21rZI/builds/eoZzckD618MTFjkSz/openapi.json
