# s1jobs.com scraper (`memo23/s1jobs-scraper`) Actor

Scrape Scottish job postings (all sectors) from s1jobs.com — title, salary, employer, location, real lat/lng coordinates, posted/closing dates, full description, structured skills, and the actual recruiter apply URL or apply email. Works with any listing or vacancy URL. JSON or CSV out.

- **URL**: https://apify.com/memo23/s1jobs-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** Jobs, Automation, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.90 / 1,000 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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## s1jobs.com Scraper

**Turn s1jobs.com into structured Scottish vacancy data — across every sector.** Scrape every job from any s1jobs listing URL — title, salary band, employer (with logo, accreditations, URN), location with real lat/long coordinates, posted/closing dates, full description, structured skills, contract type, and the actual recruiter apply URL or apply email — pulled straight from s1jobs' public JSON API. JSON or CSV out, no compute charge per run, just per result.

#### How it works

![How s1jobs Scraper works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-s1jobs.png)

#### ✨ Why use this scraper?

Tracking the Scottish job market across every sector — engineering, healthcare, hospitality, public sector? Building salary benchmarks across regions? Need a clean dataset of Scottish vacancies without scrolling s1jobs manually?

- 🎯 **Two starting points.** Paste an s1jobs listing URL (`/jobs/{location}/`, `/jobs/{sector}/{location}/`) or a direct vacancy URL — both classified automatically.
- ⚡ **Public JSON API as the data source.** Each vacancy comes from `/api/job/{id}` — far richer than HTML scraping (structured skills, accreditations, sponsorship flags, apply method, employer URN, premier vs standard advert type).
- 📍 **Real coordinates, not just postcodes.** Optional one-fetch-per-vacancy pull of lat/lng from the page's JSON-LD geo block.
- 📧 **Apply URL or email captured.** No JS evaluation, no click-through resolver — `/api/job/{id}` returns the recruiter destination directly (Aplitrak, PeopleHR, Workday, JobTrain, employer's own ATS, etc.) or the recruiter's email.
- 🇬🇧 **All sectors, all regions of Scotland.** s1jobs is the largest Scottish-only job board — engineering, healthcare, charity, hospitality, public sector, retail.
- 📤 **Clean exports.** One row per vacancy with company enrichment merged in. JSON + CSV exported automatically.

#### 🎯 Use cases

| Team | What they build |
|------|-----------------|
| **Recruitment / agencies** | Daily new-vacancy feeds across Scotland, sliced by sector or region |
| **Compensation & benefits** | Salary benchmarks by sector, region, and contract type for Scotland |
| **Talent acquisition** | Competitive intelligence on what other Scottish employers are paying |
| **Researchers / journalists** | Scottish labour-market datasets across all sectors |
| **Workforce strategy** | Skills-demand mapping using the structured `skills[]` and `coreSkills[]` arrays |
| **ATS aggregators** | Real recruiter apply URLs (Aplitrak, Workday, PeopleHR, etc.) for redirect-and-track use cases |

#### 📥 Supported inputs

You can pass two kinds of URL in `startUrls`. Each URL is classified automatically.

| URL pattern | Behaviour |
|---|---|
| `https://www.s1jobs.com/jobs/{location}/` | **Listing** by location (e.g. `/jobs/glasgow/`) |
| `https://www.s1jobs.com/jobs/{sector}/{location}/` | **Listing** by sector + location (e.g. `/jobs/accountancy/glasgow/`) |
| `https://www.s1jobs.com/jobs/{location}/{contract}/` | **Listing** by location + contract type (e.g. `/jobs/glasgow/permanent/`) |
| `https://www.s1jobs.com/job/{slug}-{numeric-id}` | **Vacancy detail** — fetched via `/api/job/{id}` JSON |

Easiest workflow: apply your filters on s1jobs.com in the browser, copy the URL out of the address bar, paste into `startUrls`.

**Not supported:**

- Company profile URLs as a starting point (they're fetched automatically as enrichment when org enrichment is on)
- Hosts outside `s1jobs.com` / `www.s1jobs.com`

#### ⚠️ Proxy requirement

s1jobs.com IP-blocks many cloud / datacenter / generic proxies. **You'll want a UK residential proxy.** The actor defaults to Apify Residential pinned to `country: GB`; if you see consistent connection timeouts, you may need to bring your own pool (Evomi, BrightData, Smartproxy, etc. — any UK residential exit node works).

#### 🔄 How it works

1. **Classify each `startUrl`** as a listing URL or a single vacancy URL.
2. **Walk listing pagination** (`?page=2`, `?page=3`, …) until `<a rel="next">` disappears or `maxItems` is reached.
3. **Fetch each vacancy via `/api/job/{id}` JSON** — all the structured data in one call.
4. **Optionally** fetch the vacancy's HTML page once to extract lat/lng coordinates (only field not in the API).
5. **Optionally** fetch each unique company profile page once for the company website + a fuller description.
6. **Push one merged row per vacancy** to the dataset and export `data.csv` + `data.json` at the end.

#### ⚙️ Input parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `startUrls` | array | `["https://www.s1jobs.com/jobs/glasgow/"]` | s1jobs listing URLs and/or vacancy URLs. Mix both freely. |
| `enrichOrganisation` | boolean | `true` | Fetch each unique company profile once for `companyWebsite`, `companyDomain`, and a fuller `companyDescription`. The vacancy JSON API already includes the company name, logo, accreditations and a short description — disable this if those are enough. |
| `includeCoordinates` | boolean | `true` | Fetch each vacancy's HTML page once to extract lat/lng. Disable to save one HTTP call per vacancy when coordinates aren't needed. |
| `maxItems` | integer | `1000` | Hard cap on jobs collected. s1jobs has thousands of jobs across Scotland; this cap limits billing. |
| `maxConcurrency` / `minConcurrency` | integer | `10` / `1` | Parallel HTTP request limits. |
| `maxRequestRetries` | integer | `5` | Retries before a request is given up. |
| `proxy` | object | Apify residential, GB | UK residential proxy strongly recommended (s1jobs IP-blocks many other proxies). |

#### 📊 Output overview

Each scraped vacancy is one **single dataset row** of `type: "job"`. When `enrichOrganisation` is `true`, the company's website, domain and a fuller description are merged into the same row — no separate organisation rows, so the dataset row count equals the job count exactly.

#### 📦 Output sample

One merged row per vacancy (trimmed to the most useful fields):

```json
{
    "type": "job",
    "jobId": "126751069",
    "vacancyUuid": "2b47dff6-3bc0-4752-9a9d-b3a6ee20a109",
    "jobReference": "038",
    "jobUrl": "https://www.s1jobs.com/job/scheduling-lead-126751069",
    "title": "Scheduling Lead",
    "companyName": "Redress Scotland",
    "companyId": 3037932,
    "companyUrn": "RED54621GS",
    "companyType": "Employer",
    "companyConfidential": false,
    "companyProfileUrl": "https://www.s1jobs.com/companies/redress-scotland-3037932",
    "logoUrl": "https://www.s1jobs.com//ui/img/shared/company_logos/3dd3725857bbc09e422bc941282b2906.png",
    "companyImages": ["https://www.s1jobs.com/ui/img/shared/company_profiles/..."],
    "companyAccreditations": [],
    "companyDescription": "Redress Scotland is the body responsible for ...",
    "location": "Bearsden, East Dunbartonshire",
    "addressLocality": "Bearsden",
    "postcode": "G611AA",
    "coordinates": { "latitude": 55.9195, "longitude": -4.33371 },
    "salary": {
        "currency": "GBP",
        "min": 49401,
        "max": 59152,
        "rate": null,
        "raw": "£49401 - £59152 per annum"
    },
    "contractType": "Permanent",
    "hours": "Full",
    "workingHourPattern": null,
    "coreSkills": ["Admin / Secretarial / PA"],
    "primaryCoreSkill": "Admin / Secretarial / PA",
    "specialisms": [],
    "skills": [
        "Scheduling and calendar management",
        "Project coordination",
        "Remote work proficiency",
        "Time management",
        "Information security and confidentiality"
    ],
    "jobSkills": { "skills": [...], "computer_skills": [], "soft_skills": [], "language_skills": [], "other_skills": [...] },
    "accreditations": [],
    "publicSectorType": null,
    "postedDate": "Mon, 27 Apr 2026 07:08:07 GMT",
    "closingDate": null,
    "description": "<div><p>Redress Scotland have been operational now for a few years...</p></div>",
    "applyType": "external",
    "applyMethod": "url",
    "applyUrl": "https://www.s1jobs.com/job/scheduling-lead-126751069",
    "applyEmail": null,
    "externalApplyUrl": "https://www.aplitrak.com/?adid=bWljaGVsbGUubmFpcm4uMjAxMzUuNDU0QHJlZHJlc3NzY290bGFuZC5hcGxpdHJhay5jb20",
    "requiresCv": false,
    "apprenticeship": null,
    "graduateSuitable": false,
    "immediateStart": null,
    "isSponsored": true,
    "isFeatured": false,
    "advertType": "Premier",
    "jobBoost": "S1 Social Boost",
    "talentPoolId": null,
    "companyWebsite": null,
    "companyDomain": null,
    "scrapedAt": "2026-05-09T00:14:52.114Z"
}
````

#### 🗂 Key output fields

| Group | Fields |
|---|---|
| **Identifiers** | `type`, `jobId` (numeric), `vacancyUuid` (s1's internal UUID), `jobReference` (employer's own ref), `jobUrl`, `scrapedAt` |
| **Role** | `title`, `description` (HTML), `coreSkills[]`, `primaryCoreSkill`, `specialisms[]`, `skills[]`, `jobSkills` (full structured object), `accreditations[]`, `publicSectorType` |
| **Dates** | `postedDate`, `closingDate` |
| **Employer** | `companyName`, `companyId` (numeric), `companyUrn` (S1's internal employer reference), `companyType`, `companyConfidential`, `companyProfileUrl`, `logoUrl`, `companyImages[]`, `companyAccreditations[]` |
| **Location** | `location` (display string), `addressLocality`, `postcode`, `coordinates.{latitude,longitude}` (when `includeCoordinates: true`) |
| **Compensation** | `salary.{currency,min,max,rate,raw}`, `contractType`, `hours`, `workingHourPattern` |
| **Apply flow** | `applyType` (`email` / `external` / `unknown`), `applyMethod` (s1's raw value: `"url"` / `"email"`), `applyUrl` (the s1jobs page), `applyEmail`, `externalApplyUrl` (real recruiter destination — Aplitrak, PeopleHR, employer ATS, etc.) |
| **Advert flags** | `requiresCv`, `apprenticeship`, `graduateSuitable`, `immediateStart`, `isSponsored`, `isFeatured`, `advertType` (`Premier` / `Standard`), `jobBoost`, `talentPoolId` |
| **Company enrichment** *(merged into the same row when `enrichOrganisation: true`)* | `companyDescription`, `companyWebsite`, `companyDomain` |

#### ❓ FAQ

**Why does the actor need a UK residential proxy?**
s1jobs.com IP-blocks a wide range of cloud, datacenter, and generic proxy networks. Direct connections from cloud-hosted runners frequently time out. A UK residential proxy (Apify `RESIDENTIAL` group with `country: GB`, or your own pool) is the most reliable path. The actor's default proxy config already pins this.

**Where does the apply URL come from?**
From s1jobs' public JSON API: `/api/job/{id}` returns `application_url.application_url` directly when `application_method` is `"url"`, and `application_email_address` when it's `"email"`. No JS evaluation, no click-through resolver needed.

**Why is `vacancyUuid` different from `jobId`?**
`jobId` is the numeric ID in the URL (e.g. `126751069`); `vacancyUuid` is s1jobs' internal UUID for the same row (e.g. `2b47dff6-3bc0-4752-9a9d-b3a6ee20a109`). Both come from the API; use `jobId` as the stable join key.

**Can I scrape private pages or applicant data?**
No. The scraper accesses only publicly available pages and the public `/api/job/` endpoint — no logged-in content, no recruiter-only views, no candidate data.

**How do I limit results?**
Set `maxItems`. The actor stops walking pagination as soon as the cap is reached, so a `maxItems: 100` run typically only fetches 3–4 listing pages.

#### 💬 Support

- For issues or feature requests, please use the **Issues** tab on the actor's Apify Console page.
- Author's website: <https://muhamed-didovic.github.io/>
- Email: <muhamed.didovic@gmail.com>

#### 🛠 Additional services

- Custom output shape, additional fields, or one-off datasets: <muhamed.didovic@gmail.com>
- Need a similar scraper for other UK or regional job boards (CharityJob, Goodmoves, TotalJobs, etc.)? Drop an email.
- For API access (no Apify fee, just a usage fee for the API): <muhamed.didovic@gmail.com>

#### 🔎 Explore more scrapers

If this s1jobs Scraper was useful, see other scrapers and actors at [memo23's Apify profile](https://apify.com/memo23) — covering job boards, real estate, social media, and more.

***

### ⚠️ Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by s1jobs, Newsquest Media Group, or any of their subsidiaries or affiliates. All trademarks mentioned are the property of their respective owners.

The scraper accesses only publicly available vacancy pages, the public `/api/job/{id}` JSON endpoint, and public company-profile pages on s1jobs.com — no authenticated endpoints, recruiter-only features, or content behind a s1jobs login. Users are responsible for ensuring their use complies with s1jobs.com's Terms of Service, applicable data-protection law (GDPR, CCPA, etc.), and any contractual obligations of their own organisation.

***

### SEO Keywords

s1jobs scraper, scrape s1jobs, s1jobs api, s1jobs.com scraper, Apify s1jobs, scottish jobs scraper, scotland jobs api, scotland recruitment data, scottish vacancies scraper, glasgow jobs scraper, edinburgh jobs scraper, aberdeen jobs scraper, scottish salary benchmark, scotland labour market data, scottish hiring trends, scotland job board scraper, newsquest jobs scraper, charityjob alternative scraper, goodmoves alternative scraper, totaljobs alternative scraper, scottish job listings api

# Actor input Schema

## `startUrls` (type: `array`):

Full s1jobs.com URLs to crawl. Mix listing and vacancy URLs in the same array if useful.

## `enrichOrganisation` (type: `boolean`):

When enabled, each unique company profile page is fetched once to add `companyWebsite`, `companyDomain`, and a fuller `companyDescription`. The vacancy JSON API already includes the company name, logo, accreditations and a short description — disable this if those are enough.

## `includeCoordinates` (type: `boolean`):

When enabled, each vacancy fetches its detail HTML page once to extract latitude and longitude from the embedded JSON-LD geo block. Costs one extra HTTP call per vacancy.

## `maxItems` (type: `integer`):

Hard cap on the number of vacancies collected. s1jobs has thousands of jobs across Scotland; use this cap to limit billing.

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

Maximum number of vacancy API calls processed in parallel.

## `minConcurrency` (type: `integer`):

Minimum number of vacancy API calls processed in parallel.

## `maxRequestRetries` (type: `integer`):

Number of retries before a failed request is given up.

## `proxy` (type: `object`):

s1jobs.com IP-blocks many cloud and datacenter proxies — a UK residential proxy is strongly recommended.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.s1jobs.com/jobs/glasgow/"
  ],
  "enrichOrganisation": true,
  "includeCoordinates": true,
  "maxItems": 1000,
  "maxConcurrency": 10,
  "minConcurrency": 1,
  "maxRequestRetries": 5,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "GB"
  }
}
```

# 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 = {
    "startUrls": [
        "https://www.s1jobs.com/jobs/glasgow/"
    ],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "GB"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/s1jobs-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 = {
    "startUrls": ["https://www.s1jobs.com/jobs/glasgow/"],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "GB",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/s1jobs-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    "https://www.s1jobs.com/jobs/glasgow/"
  ],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "GB"
  }
}' |
apify call memo23/s1jobs-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "s1jobs.com scraper",
        "description": "Scrape Scottish job postings (all sectors) from s1jobs.com — title, salary, employer, location, real lat/lng coordinates, posted/closing dates, full description, structured skills, and the actual recruiter apply URL or apply email. Works with any listing or vacancy URL. JSON or CSV out.",
        "version": "0.0",
        "x-build-id": "uGxxGJLtBKfe8fTZe"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/memo23~s1jobs-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-memo23-s1jobs-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/memo23~s1jobs-scraper/runs": {
            "post": {
                "operationId": "runs-sync-memo23-s1jobs-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/memo23~s1jobs-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-memo23-s1jobs-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "startUrls": {
                        "title": "s1jobs URLs",
                        "type": "array",
                        "description": "Full s1jobs.com URLs to crawl. Mix listing and vacancy URLs in the same array if useful.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "enrichOrganisation": {
                        "title": "Fetch company profile (adds website + domain + fuller description)",
                        "type": "boolean",
                        "description": "When enabled, each unique company profile page is fetched once to add `companyWebsite`, `companyDomain`, and a fuller `companyDescription`. The vacancy JSON API already includes the company name, logo, accreditations and a short description — disable this if those are enough.",
                        "default": true
                    },
                    "includeCoordinates": {
                        "title": "Include map coordinates (lat/lng)",
                        "type": "boolean",
                        "description": "When enabled, each vacancy fetches its detail HTML page once to extract latitude and longitude from the embedded JSON-LD geo block. Costs one extra HTTP call per vacancy.",
                        "default": true
                    },
                    "maxItems": {
                        "title": "Maximum items to scrape",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Hard cap on the number of vacancies collected. s1jobs has thousands of jobs across Scotland; use this cap to limit billing.",
                        "default": 1000
                    },
                    "maxConcurrency": {
                        "title": "Max concurrency",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Maximum number of vacancy API calls processed in parallel.",
                        "default": 10
                    },
                    "minConcurrency": {
                        "title": "Min concurrency",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Minimum number of vacancy API calls processed in parallel.",
                        "default": 1
                    },
                    "maxRequestRetries": {
                        "title": "Max request retries",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Number of retries before a failed request is given up.",
                        "default": 5
                    },
                    "proxy": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "s1jobs.com IP-blocks many cloud and datacenter proxies — a UK residential proxy is strongly recommended.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ],
                            "apifyProxyCountry": "GB"
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
