Totaljobs Scraper - UK Jobs, Salaries & Employers
Pricing
from $1.20 / 1,000 listing results
Totaljobs Scraper - UK Jobs, Salaries & Employers
Scrape UK job listings from Totaljobs.com by keyword, location, filters, or URL. Extract 40+ fields including title, parsed salary range and period, employer, logo, GPS location, skills, employment type, full description, posting date, and apply link.
Pricing
from $1.20 / 1,000 listing results
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
Totaljobs.com Scraper: UK Job Listings, Parsed Salaries, and Full Job Details
Totaljobs.com Scraper turns Totaljobs.com into a clean UK jobs data feed. Search by keyword, location, job type, salary, and posting age, or paste any Totaljobs.com search link and let it paginate forward on its own. Every job comes back with 35+ structured fields straight from the listing page, and an optional detail pass adds the full description, GPS coordinates, a structured address, employment type, a valid-through date, and a company profile. Export to JSON, CSV, or Excel, pull it through the API, or run it on a schedule and get only new and changed jobs back.
Why This Scraper?
- 35+ fields per job from the listing page alone, no detail fetch required: title, parsed salary, employer, logo, location, posting source, and more.
- Two ways to run. Build a search from keyword, location, and filters, or paste any Totaljobs.com search link and walk it forward.
- Salary parsed for you. The free-text salary string on each listing is split into minimum, maximum, currency, and period (year, day, or hour), covering the daily and hourly rates common in UK job ads.
- Real server-side filters. Job type, advertiser type (direct employer vs. agency), minimum salary by period, posted-within window, and sort order, all sent to the site itself rather than filtered after the fact.
- Optional full detail pass. GPS coordinates, a structured address, the full description, employment type, a valid-through date, an apply type, a company profile, and any recruiter phone number or email visible on the listing itself.
- One clear cap.
maxListingsis the single limit on how many jobs a run collects; leavemaxPagesunset to walk a search all the way to its natural end. - Resumable and repeatable. Continue an interrupted run with
resumeFromRunId, or turn on incremental mode to run the same search on a schedule and receive only new, updated, or reappeared jobs, with unchanged jobs suppressed and not billed.
Use Cases
- Recruitment agencies and job boards: aggregate live postings from Totaljobs.com to cross-post, compare, or fill gaps in your own listings.
- Salary benchmarking and workforce research: build a dataset of parsed salary ranges by role, location, and job type across a whole market.
- Market and competitor monitoring: track which employers are hiring, for which roles, and how listings change over time with incremental mode.
- Recruitment and HR-tech lead generation: identify direct employers vs. agencies posting in a sector, with company profiles when the detail pass is on.
Data You Get
Sample shape: values are illustrative placeholders, not from a live listing.
| Field | Example |
|---|---|
jobId | 100234567 |
title | Warehouse Operative |
jobUrl | "https://www.totaljobs.com/job/warehouse-operative/sample-employer-job100234567" |
applyUrl | "https://www.totaljobs.com/job/warehouse-operative/sample-employer-job100234567" |
brand | totaljobs |
sourceSite | Totaljobs.com |
datePosted | 2026-03-14T00:00:00.000Z |
employer.name | Sample Employer |
employer.logoUrl | "https://www.totaljobs.com/CompanyLogos/00000000000000000000000000000000.png" |
location.text | Slough, Berkshire, SL1 |
location.postalCode | ZZ1 1ZZ |
salary.rawText | £24,000 - £27,500 per annum |
salary.min / salary.max | 24000 / 27500 |
salary.currency | GBP |
salary.period | year |
textSnippet | Join our busy distribution centre team on a full time basis, no experience necessary. |
isSponsored | false |
skills | [] (returned for every job; populated only when the listing itself includes skill tags) |
description (detail) | Full HTML job description appears here when Fetch full job details is enabled. |
employmentType (detail) | ["FULL_TIME"] |
industry (detail) | Logistics |
validThrough (detail) | 2026-04-14T00:00:00.000Z |
applyType (detail) | internal |
location.latitude / location.longitude (detail) | 51.5100 / -0.5900 |
contactPhones / contactEmails (detail) | ["0000000000"] / ["careers@sample-employer.example"] |
Every record also carries a numeric employer id and company link, a crossPostedCount of how many other employers currently have a duplicate of the same ad, a handful of ad-placement flags (isHighlighted, isTopJob, isTrafficFromPartner) set by the site's own ranking rather than by the employer, and internal bookkeeping fields (scrapedAt, detailFetched, sourceSearchUrl). The detail pass additionally fills a structured address (locality, region, country, streetAddress), the working arrangement (jobLocationType, contractType, workType), and a company profile object with benefits, size, founding year, and job count when the employer has published one. When incremental mode is on, every record also carries changeType, changedFields, firstSeenAt, and lastSeenAt (see How to Use below); an EXPIRED row repeats the last known shape of a job that is no longer found.
How to Use
- Pick a mode:
search(build a search from filters) orurl(paste Totaljobs.com search links). - For search mode, fill in locations, keywords, and any filters. For URL mode, paste one or more search-result links.
- Turn on Fetch full job details if you need the full description, GPS, or company profile.
- Set Max jobs to control run size and cost, then click Start.
Basic search in one city:
{"mode": "search","locations": ["London"],"keywords": "nurse","maxListings": 20,"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "GB" }}
Filtered search (permanent nurse roles, at least £30,000 a year, posted in the last 7 days, newest first):
{"mode": "search","locations": ["London"],"keywords": "nurse","jobType": "permanent","minSalary": 30000,"salaryType": "annual","postedWithin": "7","sortBy": "date","maxListings": 100,"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "GB" }}
Full details (adds description, GPS, employment type, company profile):
{"mode": "search","locations": ["London"],"keywords": "nurse","fetchDetails": true,"maxListings": 50,"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "GB" }}
Paginate pasted search links (filter fields above are ignored in URL mode):
{"mode": "url","urls": ["https://www.totaljobs.com/jobs/in-london","https://www.totaljobs.com/jobs/in-manchester"],"maxPages": 5,"maxListings": 200,"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "GB" }}
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/totaljobs-com-scraper").call(run_input={"mode": "search", "locations": ["London"], "keywords": "nurse"})for job in client.dataset(run["defaultDatasetId"]).iterate_items():print(job["title"], job["salary"]["rawText"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/totaljobs-com-scraper').call({ mode: 'search', locations: ['London'], keywords: 'nurse' });const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets, or webhooks from the Integrations tab.
Caps: Max jobs and Max pages
maxListings is the one limit that matters for cost: it is the total number of jobs a run scans across every location or URL, and it defaults to 20 so a first run stays small. Set it to 0 to remove the limit. maxPages is an optional safety limit on how many result pages (25 jobs each) a single search walks; leave it empty or 0 and the run instead stops on its own once it reaches the site's own reported page count, a page comes back with no new jobs, or the search is otherwise exhausted, never an artificial page-number ceiling. Under incremental mode, maxListings counts jobs scanned and classified, not jobs actually returned, so a quiet recurring run that suppresses most of a page still stops once it has looked at that many jobs, instead of paging deeper trying to make up the quota with fresh jobs.
Detail enrichment and its surcharge
Turning on fetchDetails fetches each job's own page and adds the full job description, GPS coordinates, a structured address, employment type, a valid-through date, an apply type, a company profile, and any recruiter phone number or email visible on the listing itself. This needs a residential connection routed through the UK; other connection types are refused on job pages.
Each detail-enriched job that is actually pushed to the dataset incurs a detail-enrichment charge on top of the base per-result price. The charge is counted only when the record reaches the dataset, never merely because its detail page was fetched: a job whose detail page was fetched to check for changes and then suppressed by incremental mode, because nothing about it had actually changed, is never charged for that detail pass.
Resume and recurring updates
There are two different tools here. resumeFromRunId continues one specific earlier run: point it at that run's id (or its dataset id) and this run skips every job already collected there, returning only the ones it doesn't already have. Because that skip check runs before anything is counted against maxListings, already-seen jobs never eat into this run's cap, and a page that is entirely already-collected does not stop the walk before it has found anything new. But once the walk has found at least one new job this search, an all-duplicate page still ends that search, the same as a normal run, so a resume is not guaranteed to page all the way to the end of a large result set if new and already-seen jobs are interleaved. An automatic same-run checkpoint also protects a long run against a platform migration or a Resurrect of a failed run, with no input needed.
Incremental mode (incrementalMode) is for running the exact same search again and again, for example on a daily schedule. The actor remembers the previous run of that search itself, so no run id is ever pasted. The first run for a given search returns every job as NEW. Later runs return only NEW and UPDATED jobs by default; a job that is unchanged since the last run is suppressed and not billed, unless emitUnchanged is turned on. REAPPEARED can only ever be produced for a job that an earlier run had already marked as no longer present, and that marking itself only happens as part of a completed EXPIRED pass: a previous run needs to have had emitExpired on and to have reached a genuine, uncapped, non-resumed end of the search. If emitExpired has never been on, or no run has ever completed that full a scan, a job that stops appearing is never marked gone, so it can't later come back as REAPPEARED either; it would simply look UNCHANGED or UPDATED once seen again. EXPIRED rows follow the same gate: they are only produced, and only billed, on a run that has emitExpired on and completes a full scan of the tracked search, never on a run capped by maxListings or maxPages, a resumeFromRunId run, or one resumed from a mid-scan checkpoint. State is isolated automatically per mode, locations, keywords, job type, advertiser type, salary filter, posted-within window, sort order, URLs, and the detail-fetch setting; maxListings, maxPages, and maxNotifyListings are cost knobs, not filters, so raising a limit on a later run never re-bills the whole catalogue. Set stateKey to name or deliberately share a monitoring campaign.
Send results into your apps (MCP connectors)
Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.
What gets written to the connector: a condensed, human-readable summary of each job, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.
- Authorize a connector once under Apify → Settings → Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Pipe results into your apps" input field. If the picker is empty, you haven't authorized a connector yet.
- For Notion, also set
notionParentPageUrlto the page where items should be created.
The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search builds a search from filters; url paginates search links you paste. |
locations | array | (empty; prefilled with ["London"]) | Towns, cities, counties, or regions (search mode). One search runs per location; leave empty to default to London. |
keywords | string | (empty) | Job title, skill, or employer to search for. Empty lists all jobs in the location. |
jobType | string | any | any / permanent / contract / temporary / part-time / work-from-home. |
companyType | string | any | any / employer (direct) / agency. |
minSalary | integer | (empty) | Lowest salary to include, paired with the salary period below. |
salaryType | string | annual | annual / daily / hourly, the unit for the minimum salary filter. |
postedWithin | string | 0 | 0 (any time) / 1 / 3 / 7 / 14 days. |
sortBy | string | relevance | relevance / date / salary-desc / salary-asc / distance. |
urls | array | (empty; prefilled with one London search link) | Totaljobs.com search-result links to scrape (URL mode). Filter fields above are ignored. |
fetchDetails | boolean | false | Fetch each job's own page to add the full description, GPS, structured address, employment type, valid-through date, and company profile. |
maxListings | integer | 20 | Total jobs to collect (or scan, in incremental mode) across all searches. 0 = unlimited. |
maxPages | integer | (empty) | Optional safety limit on result pages (25 jobs each) walked per search or URL. Leave empty or 0 to walk the whole search: it stops on its own at Max jobs, the site's own last page, or a repeat-page guard. |
resumeFromRunId | string | (empty) | Id of a previous run of this actor, or a dataset id. Jobs already in that dataset are skipped, so this run returns only the new ones. |
incrementalMode | boolean | false | Turn on for daily or recurring monitoring of the same search. Returns only NEW and UPDATED jobs after the first run by default. |
stateKey | string | (empty) | Optional. Name a monitoring campaign explicitly, or share state across differently configured runs. |
emitUnchanged | boolean | false | Also return jobs unchanged since the last run, marked UNCHANGED (extra billed rows). |
emitExpired | boolean | false | Also return jobs no longer found, marked EXPIRED. Only produced once a run fully scans the tracked search. |
proxy | object | (empty; prefilled with Residential, country GB) | Connection settings. |
mcpConnectors | array | (empty) | Optionally pipe results into the apps you already use via Model Context Protocol (MCP) connectors (Notion, Linear, Airtable, Apify). Authorize a connector once under Apify, Settings, Integrations, then select it here. |
notionParentPageUrl | string | (empty) | URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors. |
maxNotifyListings | integer | 50 | Cap on items written to each connector per run. Does not affect the dataset. |
Output Example
Sample shape: values are illustrative placeholders, not from a live listing.
{"rowType": "job","brand": "totaljobs","jobId": 100234567,"jobUrl": "https://www.totaljobs.com/job/warehouse-operative/sample-employer-job100234567","applyUrl": "https://www.totaljobs.com/job/warehouse-operative/sample-employer-job100234567","sourceSite": "Totaljobs.com","title": "Warehouse Operative","datePosted": "2026-03-14T00:00:00.000Z","employer": {"id": 4820001,"name": "Sample Employer","url": "https://www.totaljobs.com/jobs/sample-employer-ltd?cmpId=4820001","logoUrl": "https://www.totaljobs.com/CompanyLogos/00000000000000000000000000000000.png","isAnonymous": false},"location": {"text": "Slough, Berkshire, SL1","postalCode": "ZZ1 1ZZ","locality": "Slough","region": "Berkshire","country": "GB","latitude": 51.51,"longitude": -0.59,"lat": 51.51,"lng": -0.59,"streetAddress": "1 Acme Way"},"salary": { "rawText": "£24,000 - £27,500 per annum", "min": 24000, "max": 27500, "currency": "GBP", "period": "year" },"skills": [],"textSnippet": "Join our busy distribution centre team on a full time basis, no experience necessary.","isSponsored": false,"crossPostedCount": 0,"description": "Full HTML job description appears here when Fetch full job details is enabled.","descriptionText": "Full job description text appears here when Fetch full job details is enabled.","employmentType": ["FULL_TIME"],"industry": "Logistics","validThrough": "2026-04-14T00:00:00.000Z","directApply": true,"applyType": "internal","contactPhones": ["0000000000"],"contactEmails": ["careers@sample-employer.example"],"detailFetched": true}
Plan Requirement
Totaljobs.com accepts a residential connection routed through the UK most reliably, which is the prefilled default. Listing pages are frequently refused on other connection types, and full job details (fetchDetails) always need that UK residential route; the run automatically retries with a different connection when one is refused. Set proxy.apifyProxyGroups to ["RESIDENTIAL"] with apifyProxyCountry "GB" if you change the connection settings and results become sparse.
FAQ
How much does it cost?
You pay per job returned, with the detail-enrichment surcharge billed only for jobs where fetchDetails actually fetched and pushed a detail page. The Pricing tab shows the current rates. Use Max jobs to cap the cost of any run.
Is it legal to scrape Totaljobs.com?
This actor collects only publicly available job listing data. You are responsible for how you use it: follow Totaljobs.com's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Take particular care with any recruiter phone number or email address the detail pass surfaces from a listing; it is public on the page, but it is still someone's contact information.
Can I get only new or changed jobs on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new, updated, and (once a prior complete scan has marked a job gone with Emit expired on) reappeared or expired jobs, and unchanged ones are not billed.
Why did my run return fewer jobs than I expected?
Check Max jobs: it caps the total scanned across all locations or URLs, and defaults to 20. Set it higher, or to 0, to walk a search to its natural end. In incremental mode, most jobs on a quiet recurring run are unchanged and suppressed by design; that is not a failed run.
Why did my run fail instead of returning an empty dataset?
If every result page is refused, the run stops with a clear message so "no jobs match this search" is never confused with "nothing could be read". A genuine zero-match search (a real result page reporting zero jobs) still succeeds with an empty dataset.
Can I use it with AI agents or MCP?
Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear, or Airtable.
🔗 Want more jobs data?
Pair this actor with these related scrapers from the same team:
| 🏨 Caterer.com Scraper Scrape UK hospitality jobs from Caterer.com, including chef, hotel, restaurant, bar, and... | 💼 IrishJobs.ie Scraper Scrape job listings from IrishJobs.ie by keyword, location, job type, salary, recency, or... |
| 💼 Reed.co.uk Scraper Scrape Reed.co.uk jobs, companies, courses, and reviews. Search by keyword, location... | 💼 s1jobs Scraper Scrape jobs from s1jobs.com across Scotland and the UK. Search by keyword, location, or... |
| 💼 StepStone.de Scrape StepStone.de jobs by keyword, location, filters, or URL. Extract 35+ fields... | 💼 Nofluffjobs From $1/1K. Extract IT jobs from NoFluffJobs.com across Poland, Czechia, Slovakia... |
💬 Support & custom scrapers
- 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
- 🛠️ Need another site, extra fields or a private build? Email abotapi@proton.me or message Telegram @abotapi.
- ⭐ Enjoying it? A quick review on the actor page helps other users find it.