# Hays Jobs Scraper: 8 Countries, Salary, Descriptions (`santamaria-automations/hays-scraper`) Actor

Scrape Hays jobs from 8 country sites (UK, US, CA, IE, NL, ES, PT, AE). Returns title, location, salary parsed from the advert text, full description, work arrangement, employment type and industry. Search by keyword, URL or job link. Filter by job type, working pattern, industry.

- **URL**: https://apify.com/santamaria-automations/hays-scraper.md
- **Developed by:** [NanoScrape](https://apify.com/santamaria-automations) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 serp job results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Hays Scraper - UK, US, CA, IE, NL, ES, PT, AE Jobs

Pull live job listings from [Hays](https://www.hays.co.uk), one of the largest specialist recruitment agencies, by keyword, search URL or direct job URL. Each row has the title, canonical job URL, location, structured salary (min, max, currency, period), employment and contract type, industry, publish and expiry dates, and the full description as text, HTML and Markdown. No API key, no login.

Supported Hays sites: United Kingdom, United States, Canada, Ireland, Netherlands, Spain, Portugal and the United Arab Emirates. These are the sites that run the Hays job portal; each was tested against the live site.

### Sample output

```json
{
  "id": "4831598",
  "title": "Management Accountant",
  "job_url": "https://www.hays.co.uk/job-detail/management-accountant-warrington_4831598",
  "company_name": "Hays",
  "location": "Warrington",
  "city": "Warrington",
  "region": "North West",
  "country": "GB",
  "employment_type": "Full-time",
  "contract_type": "permanent",
  "industry": "Manufacturing & Production",
  "category": "Part Qualified Accountant",
  "salary_text": "£30,000 - £35,000",
  "salary_min": 30000,
  "salary_max": 35000,
  "salary_currency": "GBP",
  "salary_period": "year",
  "salary_source": "text",
  "work_arrangement": "hybrid",
  "remote_option": "hybrid",
  "description_snippet": "Management Accountant Location: Warrington (Hybrid Working) ...",
  "description_md": "Management Accountant\nLocation: Warrington (Hybrid Working)\n...",
  "posted_at_datetime": "2026-09-29T00:00:00Z",
  "posted_at_text": "2026-09-29",
  "expires_at": "2026-12-27",
  "headline": "Manufacturing Accountant | Warrington | £35K + Study Support | Hybrid",
  "contact_name": "Lauren Taylor",
  "contact_office": "Liverpool, Part 2nd Floor, 5 St Paul’s Square",
  "job_status": "online",
  "source_platform": "hays",
  "search_query": "accountant"
}
```

### Pricing

| Event | Price |
|-------|-------|
| Actor start | $0.001 per run start |
| Search result (every job returned) | $0.003 per job returned (about $3 per 1,000) |
| Detail result (added when the description was parsed) | +$0.005 per job enriched with full details (about $8 per 1,000 jobs with details) |

Every returned job is billed the search result. A job whose description was parsed is billed the detail result on top of it. Jobs dropped by the strict keyword match are not billed.

New to Apify? Every account gets a $5 free monthly platform credit, enough for hundreds of results before you commit to paying anything. Test with a small `maxResults` first.

### Input

| Field | Type | Description | Example |
|-------|------|-------------|---------|
| `searchQueries` | array | Job title or skill keywords. Each runs as its own search and rows are tagged with `search_query`. | `["accountant", "site manager"]` |
| `searchUrls` | array | Hays search URLs. The keyword (`q=`) and location are read from the URL, the country from the domain. | `["https://www.hays.co.uk/job-search?q=accountant"]` |
| `directUrls` | array | Hays job-detail URLs for still-alive checks or specific vacancies. Removed vacancies come back as offline rows and are not billed. | `["https://www.hays.co.uk/job-detail/management-accountant-warrington_4831598"]` |
| `country` | string | Site for keyword searches: `uk`, `us`, `ca`, `ie`, `nl`, `es`, `pt`, `ae`. Default `uk`. | `"uk"` |
| `location` | string | City or region, for example `Manchester`. Empty searches the whole country. | `"Manchester"` |
| `jobType` | string | `any` (default), `permanent`, `contract` or `temporary`. Applied by the Hays search. | `"permanent"` |
| `workingPattern` | string | `any` (default), `flexible`, `fullTime` or `partTime`. Applied by the Hays search. | `"flexible"` |
| `industry` | string | Client industry exactly as the site labels it, for example `Accountancy Firms`. Labels differ per country site. | `"Accountancy Firms"` |
| `sortBy` | string | `newest` (default, publish date descending), `relevance` or `title`. | `"newest"` |
| `postedWithinDays` | number | Only jobs published in the last N days. Empty means no limit. | `7` |
| `maxResults` | integer | Total cap across everything. Default 10, 0 means no cap. | `100` |
| `maxResultsPerQuery` | integer | Cap per keyword or URL. Default 50, 0 means no cap. | `50` |
| `scrapeDetails` | boolean | Include the full description in four formats. Default true. | `true` |
| `strictKeywordMatch` | boolean | Title-first relevance filter: keep only jobs where every keyword word (stemmed) appears in the title. Single-word keywords also match the category. Description-only matches are dropped. Default true. | `true` |
| `maxPages` | integer | Safety limit on result pages per keyword (10 jobs per page). Default 50. | `50` |
| `maxConcurrency` | integer | Keywords or URLs processed in parallel, each with its own session. Default 3. | `3` |

An empty input (`{}`) browses the newest 10 jobs on the UK site.

#### Example

```json
{
  "searchQueries": ["accountant", "nurse"],
  "country": "uk",
  "sortBy": "newest",
  "postedWithinDays": 14,
  "maxResults": 100,
  "maxResultsPerQuery": 50
}
```

### Output fields

**Core**

- `id`, `job_ref`: Hays job reference number, unique per posting.
- `title`: Job title.
- `headline`: Advert headline shown above the description, for example "Manufacturing Accountant | Warrington | £35K + Study Support | Hybrid".
- `job_url`: Canonical Hays job page URL. `source_url` carries the same value.
- `apply_url`: Apply link on the Hays site.
- `company_name`: Always "Hays". Hays advertises on behalf of its clients and normally does not name the hiring company. `company` is a deprecated duplicate.
- `source_platform`: Always "hays".
- `search_query`: Keyword that produced the row. Null for browse runs and direct URLs.
- `job_status`: `online`, or `offline` for direct URLs that no longer exist.
- `scraped_at`: ISO timestamp.

**Location**

- `location`, `city`, `region` (duplicates removed; `state` is a duplicate), `country` (ISO alpha-2), `latitude`, `longitude`.

**Role**

- `employment_type`: Full-time, Part-time, Temporary or Contract.
- `contract_type`: `permanent`, `contract` or `temporary`.
- `flexible_working`: True when Hays marks the job as flexible.
- `industry`: Client industry from Hays.
- `work_arrangement` and `remote_option` (same value): `remote`, `hybrid` or `onsite`, detected from the headline, the flexible working flag and the description. Null when nothing is stated.
- `category`: Hays specialism, for example "Senior Finance Qualified".

**Salary**

- `salary_text`: Salary text as displayed on the site.
- `salary_min`, `salary_max`: Numeric bounds parsed from `salary_text` (handles `k`, ranges, "up to", per hour, day or year), in `salary_period` units. "Up to" adverts have only a max. Text without numbers ("Competitive", "To £££") gives null.
- `salary_source`: `text` when the numbers come from `salary_text`, `band` when the advert has no salary text and the Hays internal band is used.
- `salary_currency`: ISO 4217 code such as GBP, USD, EUR.
- `salary_period`: `hour`, `day`, `week`, `month` or `year`. Taken from the salary text ("per hour", "per day", "per annum", "p/h"), otherwise inferred from the amount scale.

**Description** (when `scrapeDetails` is true)

- `description_full`: Full plain text.
- `description_snippet`: First 300 characters, including the trailing ellipsis.
- `description_html`: Full description as HTML.
- `description_md`: Full description as Markdown.

**Dates and contact**

- `posted_at_datetime`, `posted_at_text`: Publish date. `posted_at` is a duplicate of the text form. The site publishes a date, so the time part is always midnight UTC.
- `expires_at`: Posting expiry date.
- `contact_name`, `contact_email`, `contact_phone`, `contact_office`: The Hays consultant named on the job page and their office (city and address), when shown.

#### Deprecation notes

`company`, `state`, `source_url` and `posted_at` are legacy aliases kept for one year (until 2027-09-29). Migrate to `company_name`, `region`, `job_url` and `posted_at_text`. Both forms are emitted in every row during the window.

### Use with AI Agents (MCP)

Connect this actor to any MCP-compatible AI client: Claude Desktop, Claude.ai, Cursor, VS Code, LangChain, LlamaIndex, or custom agents.

Configure the MCP server with the Hays Scraper preconfigured at `mcp.apify.com?tools=santamaria-automations/hays-scraper`.

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=santamaria-automations/hays-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}
```

For per-tool schemas and copy-paste snippets for MCP clients, see the [MCP tab](https://console.apify.com/actors/N8MGQrQUhFrOgxMay/info/api/mcp?build=latest).

See the [auto-generated API tab](https://console.apify.com/actors/N8MGQrQUhFrOgxMay/info/api) for language-specific examples (cURL, JS, Python, .NET, Ruby, PHP).

### Why this actor

- Reads the same data feed the Hays job pages use, so descriptions are complete and salary bands are structured rather than parsed from text.
- Eight Hays country sites behind one input, with sort by newest and a posted-within-days cutoff for scheduled runs.
- Strict keyword match is title-first: it removes the jobs the Hays search adds only because the words appear in the description, and you are not billed for them.
- Consultant contact name, email and phone on every row where Hays shows them.

### Common use cases

- Refresh a daily list of new finance, tax or technology vacancies in a UK region and push them to a CRM.
- Track day-rate and hourly contract pay for a skill across Hays UK, IE and NL.
- Feed job descriptions into an LLM pipeline for skills extraction.
- Check whether saved Hays vacancies are still online with direct URLs.

### Notes and limits

- Hays search returns loosely related jobs for some keywords. With `strictKeywordMatch` on (default) only jobs whose title contains every keyword word are kept (stemmed, so "accountant" matches "accounting"; single-word keywords also match the category), so rare keywords can return fewer rows than `maxResults`. A nonsense keyword returns nothing.
- Jobs are advertised by Hays. The end client is normally not named, so `company_name` is always "Hays".
- Salary numbers are read from the salary text shown on the advert, because the Hays internal band often contradicts it. The band is used only when an advert has no salary text.
- Sites that do not run the Hays job portal (Germany, Austria, Switzerland, France, Australia and others) are not supported. Search URLs from those sites are skipped with a warning.
- Offline direct URLs are returned with `job_status: "offline"`, the id taken from the URL, and are not billed.
- Filters the Hays site shows but this actor does not offer: minimum and maximum pay (`minPay`, `maxPay`) and the pay-type facet are not applied by the Hays search backend (the result count does not change), so they are not supported. `sortType` and the other filter parameters in a pasted search URL are ignored too: use the `sortBy`, `jobType`, `workingPattern` and `industry` inputs instead.

### Related actors

- [Website Job Extractor](https://apify.com/santamaria-automations/website-job-extractor): extract jobs from any company careers page.
- [Indeed Jobs Scraper](https://apify.com/santamaria-automations/indeed-http-scraper): jobs from Indeed across many countries.
- [Glassdoor Scraper](https://apify.com/santamaria-automations/glassdoor-scraper): jobs, salaries and company ratings.
- [Reed UK Scraper](https://apify.com/santamaria-automations/reed-uk-scraper): UK job board listings.
- [Totaljobs Scraper](https://apify.com/santamaria-automations/totaljobs-scraper): UK jobs and salaries.

### Support

- **Questions or issues?** Email contact@nanoscrape.com, we typically reply within 6 hours. You can also open a ticket in the [Issues tab](https://console.apify.com/actors/N8MGQrQUhFrOgxMay/info/issues) on the actor page.
- **Feature request for this actor?** Open a ticket in the [Issues tab](https://console.apify.com/actors/N8MGQrQUhFrOgxMay/info/issues) or email contact@nanoscrape.com with the field you need and, if possible, a URL that shows the data live.
- **Need a scraper for a job board we don't cover yet?** Email contact@nanoscrape.com with the target site and your rough usage volume. We ship new boards regularly.

# Actor input Schema

## `searchQueries` (type: `array`):

Job title or skill keywords, for example 'accountant' or 'site manager'. Each keyword runs as its own search on the chosen country site and rows are tagged with search_query. Leave everything empty to browse the newest jobs.

## `searchUrls` (type: `array`):

Hays search URLs from a supported site (uk, us, ca, ie, nl, es, pt, ae). The keyword (q=) and location are read from the URL and the country is taken from the domain.

## `directUrls` (type: `array`):

Hays job-detail URLs for still-alive checks or specific vacancies. Each row gets job_status online or offline. Offline rows (vacancy removed) carry the id from the URL and are not billed.

## `country` (type: `string`):

Hays country site used for keyword searches. Only sites that run the Hays job portal are listed. Ignored for search URLs and direct URLs.

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

City or region to search in, for example 'Manchester'. Leave empty to search the whole country. Applies to keyword searches and search URLs.

## `jobType` (type: `string`):

Only return permanent, contract or temporary roles. Applied by the Hays search itself, so it also lowers the page count and cost. 'any' returns all types.

## `workingPattern` (type: `string`):

Filter by working pattern. 'flexible' keeps jobs Hays marks as flexible working, 'fullTime' and 'partTime' keep jobs of that pattern. Applied by the Hays search itself. 'any' applies no filter.

## `industry` (type: `string`):

Client industry exactly as the Hays site labels it, for example 'Accountancy Firms', 'Government & Public Services', 'Banking & Financial Services' or 'Manufacturing & Production'. Labels differ per country site. A label the site does not know returns no results. Leave empty for all industries.

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

Result order. 'newest' sorts by publish date, newest first (best for scheduled runs). 'relevance' uses the Hays relevance ranking. 'title' sorts alphabetically.

## `postedWithinDays` (type: `number`):

Only return jobs published in the last N days (cutoff at midnight UTC of that day). Leave empty for no date limit. Works best with sort 'newest', which stops early once jobs are older than the cutoff.

## `maxResults` (type: `integer`):

Total cap across all keywords, search URLs and direct URLs. Set 0 for no cap. Start small when testing.

## `maxResultsPerQuery` (type: `integer`):

Cap per keyword or per search URL, so one broad keyword cannot use up the whole budget. Set 0 for no per-query cap.

## `scrapeDetails` (type: `boolean`):

Return the full job description in four forms (description_full, description_snippet, description_html, description_md). Every job costs $0.003; jobs with a description cost an extra $0.005.

## `strictKeywordMatch` (type: `boolean`):

Hays search also returns loosely related jobs that only mention your words in the description. When on, a job is kept only if every keyword word appears in its title (word stems, so 'accountant' matches 'accounting'). For single-word keywords the job category is also checked. Description-only matches are dropped and not billed. Turn off to keep everything Hays returns.

## `maxPages` (type: `integer`):

Safety limit on result pages per keyword or URL (10 jobs per page).

## `maxConcurrency` (type: `integer`):

Number of keywords or URLs processed in parallel, each with its own session. Higher is faster and safe up to about 5.

## Actor input object example

```json
{
  "searchQueries": [
    "accountant"
  ],
  "country": "uk",
  "location": "Manchester",
  "jobType": "any",
  "workingPattern": "any",
  "industry": "Accountancy Firms",
  "sortBy": "newest",
  "postedWithinDays": 7,
  "maxResults": 10,
  "maxResultsPerQuery": 50,
  "scrapeDetails": true,
  "strictKeywordMatch": true,
  "maxPages": 50,
  "maxConcurrency": 3
}
```

# Actor output Schema

## `jobListings` (type: `string`):

Dataset of scraped Hays jobs. One row per job.

# 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 = {
    "searchQueries": [
        "accountant"
    ],
    "maxResults": 10,
    "maxResultsPerQuery": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("santamaria-automations/hays-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 = {
    "searchQueries": ["accountant"],
    "maxResults": 10,
    "maxResultsPerQuery": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("santamaria-automations/hays-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 '{
  "searchQueries": [
    "accountant"
  ],
  "maxResults": 10,
  "maxResultsPerQuery": 50
}' |
apify call santamaria-automations/hays-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,santamaria-automations/hays-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/N8MGQrQUhFrOgxMay/builds/cNy1SNrej0y29KNZ4/openapi.json
