Jobsite UK $1.5๐Ÿ’ฐ Jobs, Details & Company Scraper avatar

Jobsite UK $1.5๐Ÿ’ฐ Jobs, Details & Company Scraper

Pricing

from $1.00 / 1,000 results

Go to Apify Store
Jobsite UK $1.5๐Ÿ’ฐ Jobs, Details & Company Scraper

Jobsite UK $1.5๐Ÿ’ฐ Jobs, Details & Company Scraper

From $1/1K. Collect UK job listings from Jobsite.co.uk at scale. Search by keyword, location, filters, or paste search URLs. Returns 35+ clean fields per job from search pages. Optional detail mode adds full description, GPS coordinates, employment type, and company profile.

Pricing

from $1.00 / 1,000 results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

5 days ago

Last modified

Share

Jobsite.co.uk Jobs Scraper

Collect UK job listings from Jobsite.co.uk at scale. This scraper reads the structured data the site renders into every search page, so it returns 35+ clean fields per job without opening a browser. Search by keyword, location, and filters, or paste search URLs directly. An optional detail mode opens each job page for the full description, GPS coordinates, employment type, and company profile.

Why this scraper

  • 35+ fields per job straight from the listing page, including parsed salary (min, max, currency, period), the original posting source, skills, and a text snippet.
  • Listing pages run on Datacenter connections, so a basic run is fast and inexpensive and works on the free plan.
  • Optional full details add the complete job description, latitude and longitude, employment type, valid-through date, apply type, and company profile (benefits, videos, industries).
  • Two modes: build a search from filters, or paginate any Jobsite.co.uk search URL.
  • Server-side filters match the website: keyword, location, job type, advertiser type, minimum salary, posted-within, and sort order.
  • Built-in connection management: country rotation, automatic failover, retry handling, and a residential request cap so a run can never overspend.
  • Walks the whole catalogue by default. maxPages defaults to 0 (unlimited), so the run walks every result page per search/URL, stopping on its own once the site's reported page count is reached, a page comes back empty, or a page repeats jobs already seen this walk. There is no artificial page-number ceiling; the only cap you need is maxListings.
  • maxListings is the sole cap on volume (default 20, so a first run is small and fast; set 0 for unlimited).
  • Resumable runs. Set resumeFromRunId to a previous run or dataset id to collect only the jobs that run doesn't already have (a delta); combine both datasets for the full set. Long unlimited runs also checkpoint their progress to the key-value store, so an Apify platform migration or a Resurrect of a failed run picks up where it left off instead of starting over.
  • Incremental mode for recurring/scheduled runs. Turn on incrementalMode for a search you run repeatedly (e.g. daily) to get only NEW and CHANGED jobs each time. Unlike resumeFromRunId (which finishes one specific interrupted run by id), incremental mode remembers state itself between runs โ€” no id to paste. See "Incremental & dedup mode" below.

Data you get

Sample shape: values are illustrative placeholders, not from a live listing.

FieldExample
jobId100000001
titleSample Job Title
jobUrlhttps://www.jobsite.co.uk/job/sample-job-title/sample-company-job100000001
sourceSiteTotaljobs.com
employer.nameSample Company
employer.urlhttps://www.jobsite.co.uk/jobs/sample-company?cmpId=0000000&cmp=1
employer.logoUrlhttps://www.jobsite.co.uk/CompanyLogos/00000000000000000000000000000000.png
location.textSample Town, Sample County (AA0), AA0 0AA
location.postalCodeAA0 0AA
salary.rawTextยฃ30,000 - ยฃ40,000 per annum
salary.min30000
salary.max40000
salary.currencyGBP
salary.periodyear
datePosted2026-01-01T00:00:00.000Z
workFromHomeHybrid
skills["Sample Skill A", "Sample Skill B"]
textSnippetShort preview of the job description appears here.
crossPostedCount1
isSponsoredfalse

When fetchDetails is enabled, each record is also enriched with:

FieldExample
description<p>Full HTML job description...</p>
descriptionTextFull plain-text job description appears here.
employmentType["FULL_TIME"]
industrySample Industry
jobLocationTypeTELECOMMUTE
validThrough2026-02-01T00:00:00.000Z
directApplytrue
applyTypeDirectApply
location.latitude51.0000
location.longitude0.0000
location.localitySample Town
company.jobsCount10
company.benefits[]
contactPhones["+440000000000"]
contactEmails["recruiter@example.com"]

contactPhones and contactEmails are a best-effort harvest of any contact details a recruiter typed into the job description (or exposed as a tel/mailto link). The platform does not publish structured company contact details, so these are populated only on the minority of posts (mostly recruitment agencies) that include them; most records return empty arrays.

How to use

Basic search by location:

{
"mode": "search",
"locations": ["London"],
"maxListings": 20
}

Keyword search with filters:

{
"mode": "search",
"locations": ["Manchester"],
"keywords": "java developer",
"jobType": "permanent",
"minSalary": 50000,
"salaryType": "annual",
"postedWithin": 7,
"sortBy": "date",
"maxListings": 100
}

Full details (needs Apify Residential GB):

{
"mode": "search",
"locations": ["London"],
"keywords": "nurse",
"fetchDetails": true,
"maxListings": 50,
"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "GB" }
}

Paginate search URLs directly (multiple supported):

{
"mode": "url",
"urls": [
"https://www.jobsite.co.uk/jobs/in-london",
"https://www.jobsite.co.uk/jobs/contract/in-leeds?postedWithin=3"
],
"maxListings": 50
}

Walk the whole catalogue for a location (no page cap, still bounded by maxListings):

{
"mode": "search",
"locations": ["London"],
"maxPages": 0,
"maxListings": 0
}

Resume a previous run to collect only new jobs since then:

{
"mode": "search",
"locations": ["London"],
"maxListings": 0,
"resumeFromRunId": "<a previous run id or dataset id from this account>"
}

Track a search on a daily schedule, returning only new/changed jobs each run:

{
"mode": "search",
"locations": ["London"],
"keywords": "nurse",
"maxListings": 0,
"incrementalMode": true,
"emitExpired": true
}

Incremental & dedup mode

Set incrementalMode: true for a search you run on a recurring schedule (e.g. once a day) and want only what changed since the last run, instead of the whole list every time. The actor remembers the jobs it saw last time in its own key-value store baseline โ€” keyed automatically by your search filters, or by stateKey if you set one โ€” and classifies every job it scans against that baseline:

changeTypeMeaning
NEWNot seen in any previous run for this state key.
UPDATEDSeen before, but one or more tracked fields changed (see changedFields).
UNCHANGEDIdentical to the last run. Suppressed by default โ€” not pushed, not charged โ€” unless emitUnchanged is on.
REAPPEAREDWas previously marked EXPIRED, now seen again.
EXPIREDSeen in a previous run, not found in this one, only emitted when emitExpired is on and this run reached a natural, uncapped end for every search (no maxListings/maxPages truncation, and not a resumeFromRunId run) โ€” a capped or partial scan cannot tell "gone" apart from "not reached yet", so it is skipped rather than guessed.

This is a separate mechanism from resumeFromRunId: Resume finishes one specific interrupted/previous run by pasting its id; Incremental mode tracks the same recurring search automatically, run after run, with no id needed. Combining both is only meaningful to bootstrap a brand-new incremental baseline from an existing resume dataset (first run only) โ€” once a baseline exists for a state key, a run also setting resumeFromRunId is rejected with an explanation, since resuming would prevent this run from scanning the full search and make later EXPIRED detection unreliable.

Fields excluded from change detection (present in the pushed row as usual, just not compared to decide changeType):

  • sourceSearchUrl, travelTime โ€” describe the search, not the job (which location/URL/distance this run happened to find it under), and can shift across runs with zero change to the job itself.
  • description, descriptionText, validThrough, employmentType, industry, directApply, applyType, jobLocationType, applicantLocationRequirements, contractType, workType, company, contactPhones, contactEmails, detailFetched, externalId, and location.latitude/longitude/locality/region/country/streetAddress/postalCode โ€” populated or refined only by detail-page enrichment (fetchDetails). A job fetched without detail (or one whose detail fetch happened to fail this run only) would otherwise look "changed" purely because of enrichment availability, not a real site change.
  • datePosted is normalized, not excluded: a pure relative-time render ("Posted 2 days ago") is blanked before comparison since it would drift every run on its own, but an absolute date is kept and still bills UPDATED on a genuine repost.

Everything else โ€” title, salary, employer, location text/postcode, skills, sponsorship flags, cross-post count, and so on โ€” is real listing data and a change bills UPDATED as expected.

Input parameters

ParameterTypeDefaultDescription
modestringsearchsearch builds URLs from filters; url paginates pasted URLs.
locationsarray["London"]Towns, cities, counties, or regions. One search per location.
keywordsstring(empty)Job title, skill, or company to search for.
jobTypestringanypermanent, contract, temporary, part-time, work-from-home.
companyTypestringanyemployer (direct) or agency.
minSalaryinteger(empty)Minimum salary, paired with salaryType.
salaryTypestringannualannual, daily, or hourly.
postedWithininteger01, 3, 7, or 14 days. 0 = any time.
sortBystringrelevancedate, salary-desc, salary-asc, distance.
urlsarray(example)Search URLs to paginate (URL mode).
fetchDetailsbooleanfalseOpen each job page for the full detail fields.
maxListingsinteger20The sole cap on total jobs collected across all searches. 0 = unlimited.
maxPagesinteger0Optional bound on result pages (25 jobs each) walked per search/URL. 0 = walk the whole catalogue: stops on its own at the site's reported page count, an empty page, or a page that repeats jobs already served this walk, never an artificial page cap. Does not cap job count; use maxListings for that.
maxResidentialRequestsinteger0Cap on Residential requests per run. 0 = unlimited.
resumeFromRunIdstring(empty)Optional id of a previous run (or dataset) of this actor. Jobs already in that dataset are skipped, so this run returns only new jobs (a delta).
incrementalModebooleanfalseTrack a recurring search across runs; only NEW/UPDATED jobs are returned by default. See "Incremental & dedup mode" above.
stateKeystring(empty)Optional label for the incremental baseline. Leave empty to derive it automatically from the search filters.
emitUnchangedbooleanfalseIncremental mode only. Also return jobs with no change (changeType: UNCHANGED).
emitExpiredbooleanfalseIncremental mode only. Emit changeType: EXPIRED rows for jobs no longer found, when this run reached a natural, uncapped end.
proxyobjectApify proxyConnection settings.

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 record, 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.

  1. Authorize a connector once under Apify โ†’ Settings โ†’ Integrations (Notion, Linear, Airtable, or Apify).
  2. Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
  3. For Notion, also set notionParentPageUrl to 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.

Output example

Sample shape: values are illustrative placeholders, not from a live listing.

{
"rowType": "job",
"jobId": 100000001,
"harmonisedId": "00000000-0000-0000-0000-000000000000",
"jobUrl": "https://www.jobsite.co.uk/job/sample-job-title/sample-company-job100000001",
"sourceSite": "Totaljobs.com",
"title": "Sample Job Title",
"datePosted": "2026-01-01T00:00:00.000Z",
"employer": {
"id": 0,
"name": "Sample Company",
"url": "https://www.jobsite.co.uk/jobs/sample-company?cmpId=0&cmp=1",
"logoUrl": "https://www.jobsite.co.uk/CompanyLogos/0.png",
"isAnonymous": false
},
"location": {
"text": "Sample Town, Sample County (AA0), AA0 0AA",
"postalCode": "AA0 0AA",
"locality": "Sample Town",
"region": "Sample County",
"country": "GB",
"latitude": 51.0000,
"longitude": 0.0000
},
"salary": { "rawText": "ยฃ30,000 - ยฃ40,000 per annum", "min": 30000, "max": 40000, "currency": "GBP", "period": "year" },
"skills": ["Sample Skill A", "Sample Skill B"],
"textSnippet": "Short preview of the job description appears here.",
"crossPostedCount": 1,
"partnership": { "isBackfilled": true, "isCrossPosted": false, "sourceSiteFriendlyName": "Totaljobs.com" },
"employmentType": ["FULL_TIME"],
"industry": "Sample Industry",
"applyType": "DirectApply",
"descriptionText": "Full plain-text job description appears here.",
"company": { "jobsCount": 10, "industries": [], "benefits": [] }
}

Plan requirement

  • Listing mode works on any Apify plan using the default Apify proxy (Datacenter).
  • Full details (fetchDetails) require Apify Residential with country GB. Datacenter and non-GB residential connections are refused on job pages. Residential is available on the Starter plan and above.
  • Use maxResidentialRequests to put a hard cap on residential usage per run.