CWJobs UK Scraper at a glance
CWJobs UK Scraper is a ready-to-run Apify actor from abotapi for collecting jobs data. Its documented output includes job title, change type (incremental mode), employer, location and salary, which you can export as JSON, CSV or Excel or read through the Apify API. It costs $1.70 per 1,000 results on the Apify Free plan and from $1.00 on paid plans, with smaller per-run or optional feature charges listed on Apify.
- Runs on
- Apify cloud: console, API, schedules and integrations
- Data type
- Jobs, Lead Generation, Developer Tools
- Pricing
- $1.70 per 1,000 results (Free plan), from $1.00 on paid plans
- Output
- Documented below · JSON, CSV, Excel
- Inputs
- 25 options
Scrape CWJobs.co.uk tech and IT job listings by keyword, location, salary, work type, date or URL. Extract job titles, salary ranges, GPS coordinates, full descriptions, posting dates and employer details. Supports advanced filters, sorting and structured data for job market research.
What CWJobs UK Scraper can do
- 40+ named fields per job, including a rich employer profile (company size, founded year, industry, total jobs at that employer, and a hosted profile video where published).
- Structured salary parsing. Minimum, maximum, currency and period are broken out from the salary text band, not left as free text.
- Full location data. GPS coordinates, postal code and locality on every job that publishes them.
- Two ways in. Keyword and location search with server-side filters (work type, minimum salary, posting recency, sort order), or paste listing and job URLs you already have.
- Unlimited catalogue walks. Leave Max listing pages at 0 to walk an entire search, bounded by Max jobs, the site's own last page, or a stop once a page adds nothing new, never an artificial page cap.
- Delta resume and incremental mode. Continue an interrupted run without duplicate rows or double charges, or schedule the same search and get back only NEW, UPDATED and REAPPEARED jobs, with unchanged jobs suppressed and never billed.
Choose what to collect
These inputs let you configure CWJobs UK Scraper - Tech Jobs, Salaries & Employers. Open the actor on Apify to enter your values and review the current options.
| Input | What it controls |
|---|---|
modestring · required | How to choose jobs. 'Search' builds listing pages from your keywords and locations. 'Direct URLs' takes CWJobs listing or job URLs you already have. |
keywordsarray | Search mode only. Job keywords or titles, one per line (e.g. 'javascript', 'devops', 'data engineer'). Leave empty to list every job in the chosen locations. Each keyword is combined with each location. |
locationsarray | Search mode only. Locations, one per line (e.g. 'london', 'manchester', 'remote'). Leave empty to search the whole UK. Each location is combined with each keyword. |
workTypestring | Filter by contract type. 'Any' applies no filter. |
minSalaryinteger | Only jobs paying at least this amount (in the salary period below). Leave empty for no salary filter. |
salaryPeriodstring | The period the minimum salary applies to. |
postedWithinstring | Only jobs posted within this many days. 'Any time' applies no filter. |
Show 18 more inputs
| Input | What it controls |
|---|---|
sortBystring | Result ordering. 'Most recent' sorts by posting date (newest first); 'Relevance' is the site default. |
workFromHomeboolean | Keep only jobs the site lists with work-from-home options. In search mode this adds the site's own work-from-home filter to every search; in URL mode add it to the URL yourself. |
urlsarray | URL mode only. CWJobs listing URLs (e.g. https://www.cwjobs.co.uk/jobs/javascript/in-london, with optional ?page=N and filter parameters such as radius, postedwithin, sort) or direct job URLs (e.g. https://www.cwjobs.co.uk/job/...-job12345678). Multi-URL supported. Leaving the field untouched scrapes one example of each supported listing shape. Filter fields above are ignored in URL mode; pagination starts at the page in the URL and walks forward, keeping your query parameters. |
fetchDetailsboolean | Open each job page for the full description, GPS coordinates, posting and expiry dates, work type, and the rich employer profile (company size, founded year, industry, total jobs, video). Turn off for a faster, leaner run that returns only the fields visible on the listing page. |
descriptionFormatstring | How the job description is returned: HTML as published (default), plain text, or Markdown. Only affects output; change detection is unaffected. |
descriptionMaxLengthinteger | Truncate each description to this many characters after formatting. 0 keeps the full text. |
compactboolean | Drop the nested employer profile object and the listing snippet from each row for smaller datasets. Flat employer fields stay. |
maxPagesinteger | How many listing pages to walk per search or URL (about 25 jobs per page). Leave at 0 to walk the whole catalogue: the run stops at Max jobs, the site's own last page, or a repeat-page guard, not an artificial page cap. |
maxListingsinteger | Maximum number of jobs to scrape across all searches. This is the main limit. Set 0 for unlimited (bounded by Max listing pages, if set). In Incremental mode this counts jobs SCANNED, not jobs returned, otherwise a quiet recurring run with nothing changed would page deeper to backfill this many rows and cost would never drop. |
resumeFromRunIdstring | Optional. ID of a previous run of this actor (or a dataset ID). Jobs already in that dataset are skipped, so this run returns only NEW jobs (a delta). Combine both runs' datasets for the full set. Max jobs then counts only the new jobs. For recurring daily/weekly monitoring of the same search, use Incremental mode below instead. |
incrementalModeboolean | Turn this on for daily or recurring monitoring. The first run returns all matching jobs as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED jobs. Turn on "Emit unchanged" or "Emit expired" only when you also want those jobs returned (and billed). State is kept separately for each search/URL and filter/detail setup; use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above. |
stateKeystring | Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the search/URL and filter/detail settings, different searches then never mix state with each other. |
emitUnchangedboolean | Off by default. Turn on to also return jobs that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have, so leave it off unless you specifically want the full snapshot every run. |
emitExpiredboolean | Off by default. Turn on to also return jobs that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search, not when Max jobs / Max listing pages capped it, or when Resume was used. This returns, and bills, extra synthetic rows, so leave it off unless you need expiry tracking. |
ignoreFieldsForChangesarray | Optional. Field names to exclude from UPDATED change detection, in addition to the built-in handling (scrape time, relative posted age and the top-job / free-listing ad flags never trigger a false UPDATED). Use it when another field is noisy in your setup. Dotted names reach nested fields, for example salary.min. Ignored fields stay in the output; they just no longer make a job UPDATED. Changing this list never re-bills your tracked jobs. |
mcpConnectorsarray | Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON, the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com). |
notionParentPageUrlstring | URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors. |
maxNotifyListingsinteger | Cap on items written to each connector per run. Does not affect the dataset. |
Fields in the output
The documented dataset includes the fields below. Availability can depend on the source page and selected mode.
titleJob Title (text)changeTypeChange type (incremental mode) (text)employerNameEmployer (text)locationTextLocation (text)salaryTextSalary (text)workTypeType (text)datePostedPosted (text)companyEmployeesCompany Size (text)companyJobsCountJobs at Company (number)jobUrlURL (link)changedFieldsChanged fields (incremental mode) (array)firstSeenAtFirst seen (incremental mode) (date)Show 10 more fields
lastSeenAtLast seen (incremental mode) (date)salaryMinSalary min (number)salaryMaxSalary max (number)salaryCurrencyCurrency (text)salaryPeriodSalary period (text)employmentTypeEmployment type (text)validThroughValid through (text)descriptionDescription (text)latitudeLatitude (number)longitudeLongitude (number)Example output
An example from this actor’s documentation. Values are illustrative; this is not a fresh live result.
{
"rowType": "job",
"listingUrl": "https://www.cwjobs.co.uk/jobs/javascript/in-london",
"jobId": "10000001",
"externalId": "00000000-0000-0000-0000-000000000000",
"jobUrl": "https://www.cwjobs.co.uk/job/sample-job-title/sample-employer-job10000001",
"title": "Sample Senior Software Engineer",
"description": "Full job description text appears here when detail fetching is on.",
"snippet": "Short preview text taken from the listing card.",
"workType": "Permanent",
"employmentType": "FULL_TIME",
"industry": "IT, IT-Software Development",
"datePosted": "2026-01-01T00:00:00.000Z",
"validThrough": "2026-02-01T00:00:00.000Z",
"postedAgo": "3 days ago",
"isPremium": true,
"isTopJob": false,
"isFreeListing": false,
"directApply": true,
"applyType": "internal",
"jobLocationType": "TELECOMMUTE",
"salaryText": "£55,000 - £65,000 per annum",
"salaryMin": 55000,
"salaryMax": 65000,
"salaryCurrency": "GBP",
"salaryPeriod": "annum",
"locationText": "Sample Town, Sample County, AA1, GB",
"locationLocality": "Sample Town",
"locationRegion": "Sample County",
"locationPostalCode": "AA1",
"locationCountry": "GB",
"latitude": 51.5,
"longitude": -0.1,
"employerName": "Sample Employer Ltd",
"employerId": 5551234,
"employerLogoUrl": "https://www.cwjobs.co.uk/CompanyLogos/00000000000000000000000000000000.png",
"employerProfileUrl": "https://www.cwjobs.co.uk/jobs/sample-employer-ltd?cmpId=5551234",
"companyEmployees": "50 - 199",
"companyFounded": 2005,
"companyIndustries": [
"IT & Internet"
],
"companyJobsCount": 8,
"employer": {
"name": "Sample Employer Ltd",
"employees": "50 - 199",
"founded": 2005,
"industries": [
"IT & Internet"
],
"jobsCount": 8,
"description": "Company profile description appears here.",
"videoUrl": "https://video.example.com/000000000"
},
"scrapedAt": "2026-01-01T00:00:00.000Z"
}Ways to use this data
- Tech recruiters and staffing agencies: monitor new IT and software vacancies across UK cities and pull employer profiles for outreach lists.
- Compensation researchers: build salary bands for tech roles by keyword, location and work type from the parsed salary fields.
- Job boards and aggregators: mirror CWJobs listings into your own search product on a recurring schedule.
- Market and competitor trackers: watch an employer's hiring pace (jobs count) and job description changes over time with incremental mode.
Before you run
Start with a small input and check the resulting records against your expected fields. Source content and actor options can change; the current Apify listing is the reference for availability and pricing.
Questions about this actor
What data does CWJobs UK Scraper return?
The documented output for CWJobs UK Scraper includes job title, change type (incremental mode), employer, location, salary, type, posted and company size. Availability of each field depends on the source page and the selected mode.
How much does CWJobs UK Scraper cost?
It costs $1.70 per 1,000 results on the Apify Free plan and from $1.00 on paid plans, with smaller per-run or optional feature charges listed on Apify. The Apify listing shows the current rate for every plan.
Can I get only new or changed jobs on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode for the same search. Each run then returns only new, updated and reappeared jobs; jobs with no real change are suppressed and not billed unless you turn on Emit unchanged.
What is the difference between Resume and Incremental mode?
Resume (resumeFromRunId) continues one specific interrupted run and returns only the jobs not already in that run's dataset. Incremental mode is for running the same search again and again (for example daily) and getting back only what changed each time; the actor remembers the previous run itself, no ID required. See "Resume vs. incremental mode" above.
Why did my run return an empty dataset instead of an error?
If every connection attempt to the site is refused across every search, or a search genuinely matches nothing, this run finishes with an empty dataset and a status message explaining why, rather than an error. The run does fail outright in two narrower cases instead: a resumeFromRunId that cannot be resolved, or turning on Incremental mode together with resumeFromRunId when a baseline for that search already exists. Widen your filters, check the run's status message and log, or review your connection settings, then run it again.
Why are snippet, postedAgo or isPremium empty on a job I pasted directly?
Those three fields come only from a listing search-results card. A job reached by pasting its own job page URL has no listing card behind it, so they always come back empty (null or false) even with detail fetching on. Paste the listing page instead, or use search mode, to get every field on that job.
