s1jobs Scraper icon

s1jobs Scraper

Scrape jobs from s1jobs.com across Scotland and the UK. Search by keyword, location, or URLs. Returns title, parsed salary band, company, logo, GPS…

Start using this actor on Apify ↗Need a custom scraper?Contact us ↗

s1jobs Scraper at a glance

s1jobs Scraper is a ready-to-run Apify actor from abotapi for collecting jobs data. Its documented output includes job id, title, change type (incremental mode), company and city, which you can export as JSON, CSV or Excel or read through the Apify API. It costs $2.20 per 1,000 results on the Apify Free plan and from $1.40 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, Automation, Developer Tools
Pricing
$2.20 per 1,000 results (Free plan), from $1.40 on paid plans
Output
Documented below · JSON, CSV, Excel
Inputs
25 options

Scrape jobs from s1jobs.com across Scotland and the UK. Search by keyword, location, or URLs. Returns title, parsed salary band, company, logo, GPS location, skills, contract type, and 90+ fields per job, with optional full description, postcode, and apply links.

What s1jobs Scraper can do

  • 100+ fields per job, key values under several names. Most key values are exposed under camelCase, snake_case and nested shapes (for example salary.min, salaryLow, salaryRangeLow, location.postalCode, employer.name), so the output is a drop-in replacement no matter which schema your pipeline already expects.
  • Two ways to search. Build a keyword and location search from the form, or paste s1jobs.com search URLs you already refined in your browser. Multiple URLs are paginated for you.
  • Location narrowing follows the site's own logic. A search for a town returns the commutable area around it too, and a name the site's own search box would correct on its own (for example "Oban" to "Oban, Argyll and Bute") is resolved the same way.
  • Six client-side filters for Search mode. Contract type, full or part time, direct employer or recruitment agency, minimum salary (by year, day or hour), public sector only, and jobs with video only.
  • Full detail enrichment on request. Fetch each job's complete record to add the full description, postcode, structured location, salary band, matched and unmatched skills, accreditations, and the apply method, URL and email.
  • Resume and Incremental & Dedup mode. Continue one interrupted run from a pasted ID, or schedule the same search and get back only what changed.

Choose what to collect

These inputs let you configure s1jobs Scraper – Scotland & UK Jobs, Salaries & Details. Open the actor on Apify to enter your values and review the current options.

Supported input fields
InputWhat it controls
modestring · requiredHow to find jobs: build a search from filters, or paginate URLs you paste.

Choices: search, url

locationsarrayTowns, cities, or counties. Examples: 'Glasgow', 'Edinburgh', 'Aberdeen', 'Fife'. One search runs per location. s1jobs searches the area around the place you name, so nearby commutable towns come back too (a Glasgow search also returns jobs in Renfrew and Wishaw). If s1jobs does not list the name on its own, the closest name it does list is used instead, for example 'Oban' becomes 'Oban, Argyll and Bute'. Leave empty to list jobs from everywhere. Search mode only: this builds the search URL and is NOT applied to the URLs you paste in URL mode.
keywordsstringRole, skill, or company to search for. Example: 'nurse', 'warehouse', 'project manager', 'driver'. Leave empty to list all jobs in the location. Search mode only: this builds the search URL and is NOT applied to the URLs you paste in URL mode.
contractTypestringFilter by contract arrangement. Search mode only: this filter is applied to search results and is NOT applied to the URLs you paste in URL mode.

Choices: any, permanent, contract, temporary

workingHoursstringFilter by full time or part time. Search mode only: this filter is applied to search results and is NOT applied to the URLs you paste in URL mode.

Choices: any, full, part

advertiserTypestringRestrict to direct employers or recruitment agencies. Search mode only: this filter is applied to search results and is NOT applied to the URLs you paste in URL mode.

Choices: any, employer, agency

minSalaryintegerLowest salary to include. Combined with the salary period below. Jobs that quote no numeric salary (for example 'Competitive') are always kept. Leave empty for no minimum. Search mode only: this filter is applied to search results and is NOT applied to the URLs you paste in URL mode.
Show 18 more inputs
More input fields
InputWhat it controls
salaryTypestringUnit for the minimum salary filter. Search mode only, exactly like the minimum salary it belongs to.

Choices: annual, daily, hourly

publicSectorOnlybooleanKeep only public-sector roles. Search mode only: this filter is applied to search results and is NOT applied to the URLs you paste in URL mode.
hasVideoOnlybooleanKeep only jobs that include a recruiter video. Search mode only: this filter is applied to search results and is NOT applied to the URLs you paste in URL mode.
postedWithinHoursintegerKeep only jobs published within the last N hours (for example 24 for the last day). Leave empty for no limit. Search mode only: it is NOT applied to the URLs you paste in URL mode. Combine with Sort by Most recent to stop early on fresh jobs.
sortBystringResult ordering. Search mode only: it is written into the search URL. In URL mode the ordering already present in the URL you paste is used instead.

Choices: relevance, date

urlsarrays1jobs.com pages to scrape (URL mode). Supported: search-result and listing pages (keyword, location, category, category plus location, collection, filtered, sorted or paginated), employer pages (an employer's jobs page or company profile, which return that employer's live jobs), and single job pages. A page number in a listing URL is honoured as the starting point. Company-directory index pages and links to other sites are skipped with a warning. The field is pre-filled with one example per supported page type. Single job pages are served first, then the listing and employer pages in the order given; the Total jobs limit is shared across all of them and each URL gets an equal share of it, so with the default limit the last samples can return few or no rows. Raise the limit or remove URLs you do not need. The Search mode fields above (locations, keywords, contract type, hours, advertiser type, minimum salary, public sector only, jobs with video only and sort) are NOT applied to these URLs, so build the filtering you want into the URL itself.
fetchDetailsbooleanFetch the per-job record to add the full description, postcode, structured location, salary band, matched and unmatched skills, accreditations and apply links. Adds ~20 fields. On = richest output (recommended). Off = fast, listing fields only.
maxListingsintegerTotal jobs to collect across all searches. This is THE limit on the run (default 20). Set 0 for no limit (a search still stops after 1000 pages). Maximum 100000.
maxPagesintegerOptional per-search safety stop on pages walked (20 jobs per page). This does NOT cap the run - leave it empty (unlimited) and the run defers to Max jobs for its size, walking every result page. Only set a value if you want to hard-stop pagination for one location/URL early. A hard ceiling of 1000 pages per search always applies.
resumeFromRunIdstringID of a previous run of this actor (or a dataset ID). Jobs already in that dataset (matched by job id) are skipped, so this run returns only NEW jobs, a delta. Combine both runs' datasets for the full set. Leave empty for a normal fresh run. For recurring daily monitoring of the same search, use Incremental mode below instead.
incrementalModebooleanTurn 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 detail-mode setup; use State key when you want to name or deliberately share a monitoring campaign. A job counts as UPDATED when any returned field changes (title, description, salary, contract, location, dates, flags and so on); scrapedAt, sourceSearchUrl and any field listed in Ignore fields never do. A job whose detail fetch fails in a run is skipped until the next run. To continue one specific interrupted run instead, use Resume from a previous run above.
stateKeystringOptional. 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 detail settings: different searches then never mix state with each other.
emitUnchangedbooleanOff 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.
emitExpiredbooleanOff 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 capped it or when Resume was used. This returns (and bills) extra synthetic rows, so leave it off unless you need expiry tracking.
ignoreFieldsForChangesarrayOptional. Field names that never make a job UPDATED, in addition to the built-in handling (scrapedAt and sourceSearchUrl are already ignored). They are still returned in every row. Use a dotted name such as location.text to ignore one key inside an object. Example: skills, or advertType if you do not care about those changes.
mcpConnectorsarrayOptionally 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).
notionParentPageUrlstringURL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.
maxNotifyListingsintegerCap 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.

jobIdJob ID (text)
titleTitle (text)
changeTypeChange type (incremental mode) (text)
companyCompany (text)
cityCity (text)
salarySalary (object)
contractTypeContract (text)
datePostedPosted (text)
jobUrlURL (link)
changedFieldsChanged fields (incremental mode) (array)
firstSeenAtFirst seen (incremental mode) (date)
lastSeenAtLast seen (incremental mode) (date)
Show 17 more fields
employmentTypeEmployment (array)
industryIndustry (text)
jobWorkingLocationWork type (text)
validThroughValid through (text)
applicationMethodApply method (text)
applicationUrlApply URL (link)
skillsSkills (array)
postcodePostcode (text)
description_textDescription (text)
companyNameCompany (text)
companyTypeCompany type (text)
companyProfileUrlCompany profile (link)
companyDescriptionAbout (text)
applyTypeApply type (text)
applyMethodApply method (text)
applyUrlApply URL (link)
externalApplyUrlExternal apply URL (link)

Example output

An example from this actor’s documentation. Values are illustrative; this is not a fresh live result.

{
  "jobId": "482910",
  "title": "Registered Nurse",
  "company": "Sample Care Group",
  "companyName": "Sample Care Group",
  "companyLogo": "https://www.s1jobs.com/img/company/0000.png",
  "employer": {
    "name": "Sample Care Group",
    "logoUrl": "https://www.s1jobs.com/img/company/0000.png",
    "url": "https://www.s1jobs.com/jobs/?CompanyId=0000"
  },
  "city": "Glasgow",
  "county": "Lanarkshire",
  "country": "Scotland",
  "postcode": "G1 1AA",
  "coordinates": {
    "lat": 55.86,
    "lng": -4.25
  },
  "location": {
    "text": "Glasgow, Lanarkshire",
    "locality": "Glasgow",
    "region": "Lanarkshire",
    "country": "Scotland",
    "postalCode": "G1 1AA",
    "lat": 55.86,
    "lng": -4.25
  },
  "salary": {
    "rawText": "£30,000 - £35,000",
    "min": 30000,
    "max": 35000,
    "currency": "GBP",
    "period": "annual"
  },
  "salaryLow": 30000,
  "salaryHigh": 35000,
  "contractType": "Permanent",
  "fullOrPartTime": "Full",
  "employmentType": [
    "PERMANENT",
    "FULL_TIME"
  ],
  "workingHourPattern": "Regular working hours",
  "skills": [
    "Healthcare / Pharmaceuticals"
  ],
  "primaryCoreSkill": "Healthcare / Pharmaceuticals",
  "skillsUnmatchedCount": 16,
  "jobTypes": [
    "Nursing"
  ],
  "datePosted": "Fri, 05 Jun 2026 08:00:00 GMT",
  "expiryDate": "Sun, 05 Jul 2026 08:00:00 GMT",
  "closingDate": null,
  "isSponsored": false,
  "isFeatured": false,
  "isPublicSector": false,
  "hasVideo": false,
  "applicationMethod": "url",
  "applicationUrl": "https://example.com/apply/482910",
  "applicationEmail": "jobs@example.com",
  "description_text": "As a Registered Nurse you will play a central role in delivering high quality care...",
  "jobUrl": "https://www.s1jobs.com/job/registered-nurse-482910",
  "canonicalUrl": "https://www.s1jobs.com/job/registered-nurse-482910",
  "status": "live",
  "detailFetched": true,
  "scrapedAt": "2026-06-15T00:00:00+00:00"
}

Ways to use this data

  • Recruiters and staffing agencies: monitor competitor postings, salary bands and time-to-fill signals across Scotland.
  • Job boards and aggregators: mirror s1jobs.com listings into your own search index, refreshed on a schedule.
  • Salary and labour-market researchers: build historical datasets of salary bands, contract types and skills demand by region.
  • HR tech and ATS integrations: feed matched jobs straight into your applicant pipeline or a Notion, Airtable or Linear workspace via MCP connectors.
  • Career sites and job alert tools: track new and updated postings for a saved search and notify users only when something actually changes.

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 s1jobs Scraper return?

The documented output for s1jobs Scraper includes job id, title, change type (incremental mode), company, city, salary, contract and posted. Availability of each field depends on the source page and the selected mode.

How much does s1jobs Scraper cost?

It costs $2.20 per 1,000 results on the Apify Free plan and from $1.40 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. Each run then returns only new, updated and reappeared jobs, and unchanged ones are not billed unless you turn that on too. If you also turn on emitExpired, track one location or URL per run: overlapping locations in one run can mark still-live jobs EXPIRED (see the next question).

Why did my second location return fewer jobs than its total, or mark live jobs EXPIRED?

Nearby locations on s1jobs.com overlap, because each location search also covers the commutable area around it. When a later location's search reaches a page made up entirely of jobs an earlier location already returned, after it has already found some new jobs, it treats that page as the end of its results and stops, so jobs on its later pages are skipped. That early stop still counts as a full scan for incremental mode, so with emitExpired on, the skipped jobs can be marked EXPIRED while still live. The same can happen to a Resume run when new jobs were posted since the earlier run. Run each overlapping location or URL as its own run for complete results. The full example is under Resume and recurring updates above.

Why weren't my filters applied to the URLs I pasted?

Contract type, hours, advertiser type, minimum salary, public sector and video filters only build a search in Search mode. A pasted URL in URL mode already carries whatever facets you set when you refined it in your browser, so this actor scrapes it as given rather than second-guessing it. Build the filtering into the URL itself, or switch to Search mode.

Why did my run fail instead of returning an empty dataset?

If s1jobs.com refuses every request, the run stops with a clear message so "no jobs for this search" is never confused with "nothing could be read". Run it again in a few minutes, or try a different connection under Connection.

Ready to collect with s1jobs Scraper?

Run it on Apify with your own input and export the results as JSON, CSV or Excel.