# Totaljobs Scraper - UK Job Board (`parsebird/totaljobs-scraper`) Actor

Scrape job listings from Totaljobs.com by keyword and location. Get titles, employers, salaries, full descriptions, company details, and incremental change tracking. Export as JSON, CSV, or Excel.

- **URL**: https://apify.com/parsebird/totaljobs-scraper.md
- **Developed by:** [ParseBird](https://apify.com/parsebird) (community)
- **Categories:**
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.79 / 1,000 jobs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

### Totaljobs Scraper

Scrape job listings from **[Totaljobs.com](https://www.totaljobs.com)**, one of the UK's largest job boards, into clean, structured JSON. The Totaljobs Scraper searches by keyword and location, pulls the job title, employer, salary, full description, postcode, and geo-coordinates, and can track what changed between scheduled runs — without the Totaljobs API.

<table><tr>
<td style="border-left:4px solid #E4002B;padding:12px 16px;font-weight:600">
Search any keyword across any UK town or region, apply 15+ filters (contract type, salary, posting date, radius in miles, remote, keyword rules, custom field rules), enrich each job with its full description, employment type and industry, and turn on incremental mode to get only NEW / UPDATED / EXPIRED jobs.
</td>
</tr></table>

##### Copy to your AI assistant

Copy this block into ChatGPT, Claude, Cursor, or any LLM to start using this actor.

```
Actor: parsebird/totaljobs-scraper (Apify). Scrapes job listings from totaljobs.com (UK) by keyword and location. Call with ApifyClient.
Input JSON fields: query: string or JSON array of strings — job keywords; location: string or JSON array — UK city/region; startUrls: string[] — Totaljobs search or job URLs (overrides query/location); sort: "relevance"|"date"|"salary_low"|"salary_high"; age: int — keep jobs posted within the last N days; remote: bool; radius: "5"|"10"|"20"|"30" miles (others reduced to 30); minSalary: int GBP/year; contractType: FULL_TIME|PART_TIME|CONTRACT|TEMPORARY|INTERNSHIP|APPRENTICESHIP|FREELANCE|MINI_JOB|WORKING_STUDENT|VOLUNTEER|THESIS|DUAL_STUDY; workType: FULL_TIME|PART_TIME; experience: no|required|executive; companyId: int; language: e.g. "en"; applicationMethod: INTERNAL|EXTERNAL; excludeSponsored: bool; includeKeywords/excludeKeywords: {"keywords":[...],"matchTitle":true,"matchDescription":true,"matchSkills":true}; fromDate/toDate: YYYY-MM-DD; maxAgeMinutes: int; customFilters: [{"field":"unifiedSalary.min","op":"gte","value":50000}]; includeDetails: bool (default true); descriptionFormat: html|text|markdown|original; maxResults: int (default 100, 0=unlimited); maxPages: int (default 10); compact: bool; descriptionMaxLength: int; excludeEmptyFields: bool; outputFields: string[] (dot notation ok); datasetName: string; mode: "full"|"incremental"; stateStoreName: string (default totaljobs-state); emitUnchanged/emitExpired/skipReposts: bool; dedupStoreName: string; dedupKey: string (default jobKey); proxyConfiguration: object (UK RESIDENTIAL preset).
Output: one item per job — jobKey, legacyJobId, harmonisedId, title, company, companyId, companyUrl, companyLogoUrl, companyWebsite, companyRating, location, postCode, locationDetail{city,region,country,postalCode,lat,lng}, description, descriptionLength, textSnippet, textSnippetCleaned, unifiedSalary{min,max,currency,period,salaryAvailable}, salaryText, workFromHome, employmentType, contractType, directApply, applicationMethod, industry, language, isSponsored, isTopJob, isHighlighted, isAnonymous, hasFuturePosting, partnership{isPartnershipJob,isCrossPosted,isBackfilled}, metaData{positionOnPage,positionAbsolute}, section, topLabels, skills, datePosted, postedDaysAgo, publishFromDate, publishToDate, validThrough, canonicalUrl, url, portalUrl, geo, query, scrapedAt, detailsFetched, similarJobCount, isRepost. Incremental mode adds changeType, firstSeenAt, lastSeenAt, repostOfId, repostDetectedAt.
Example: { "query": "data engineer", "location": "London", "maxResults": 50 }
API: https://api.apify.com/v2/acts/parsebird~totaljobs-scraper  ·  Token: https://console.apify.com/account/integrations
```

### What does Totaljobs Scraper do?

[Totaljobs.com](https://www.totaljobs.com) lists hundreds of thousands of live vacancies across the United Kingdom. There is no public Totaljobs search API — this scraper reads the site's own search results and job pages and returns them as structured data. For every keyword and location it extracts:

- 🏷️ **Job identity** — title, employer, location, postcode, remote flag, and a canonical `totaljobs.com/job/...` link.
- 💰 **Pay** — the salary text as shown, plus a normalised `unifiedSalary` object with `min`, `max`, `currency`, and pay `period` (year / month / week / day / hour).
- 📋 **Full description** (optional) — the complete job description as HTML, plain text, Markdown, or the site's original format.
- 🏢 **Employer data** — company name, numeric ID, logo, and — where the employer has a Totaljobs profile — website and rating.
- 📅 **Dates** — when the job was posted, how many days ago, and when the listing expires (`validThrough`).
- 📊 **Placement signals** — sponsored / top-job / highlighted flags and the position the job held on the results page.
- 🌍 **Geo** — city, region, country, postcode, latitude and longitude from the job page.

Turn on **incremental mode** and each run compares against the last one with the same state store, so you get only the jobs that are `NEW`, `UPDATED`, `REAPPEARED`, or `EXPIRED`.

### What data can you extract from Totaljobs?

| Field | Description |
|-------|-------------|
| `jobKey` | Totaljobs' own numeric listing ID (stable identity) |
| `legacyJobId` / `harmonisedId` | Numeric and UUID identifiers |
| `title` | Job title |
| `company` / `companyId` | Employer name and numeric ID |
| `companyUrl` / `companyLogoUrl` / `companyWebsite` / `companyRating` | Employer links and profile data |
| `location` / `postCode` / `locationDetail` | Display location, postcode, plus city / region / country / lat / lng |
| `unifiedSalary` | `min`, `max`, `currency`, `period`, `salaryAvailable` |
| `salaryText` | Salary exactly as shown on the listing |
| `description` / `descriptionLength` | Full description in your chosen format (with `includeDetails`) |
| `employmentType` / `contractType` / `workArrangement` | Schema.org type, permanence label, and on-site / hybrid / remote |
| `workFromHome` / `directApply` / `applicationMethod` | Remote flag and how to apply |
| `industry` / `skills` | Industry classification and tagged skills |
| `datePosted` / `postedDaysAgo` / `validThrough` | Posting and expiry timing |
| `isSponsored` / `isTopJob` / `isHighlighted` / `hasFuturePosting` | Placement and status signals |
| `similarJobCount` | Number of similar jobs Totaljobs shows on the page |
| `url` / `canonicalUrl` / `sourceUrl` | Job link, canonical link, and the search page it came from |
| `changeType` / `firstSeenAt` / `lastSeenAt` | Added in incremental mode |

Not every listing has every field — salary, employer profile, and exact skills vary by posting.

### Input parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| query | string / array | No\* | — | Job keyword(s). JSON array runs multiple searches. |
| location | string / array | No\* | — | UK city or region. JSON array for multiple. |
| startUrls | array | No\* | — | Totaljobs search or job URLs (overrides query/location). |
| sort | string | No | `relevance` | `relevance`, `date`, `salary_low`, `salary_high`. |
| age | integer | No | — | Keep only jobs posted within the last N days. |
| remote | boolean | No | `false` | Remote / work-from-home only. |
| radius | string | No | — | Search radius in **miles** (5 / 10 / 20 / 30 answered). |
| minSalary | integer | No | 0 | Minimum annual salary (GBP). |
| contractType / workType / experience | string | No | — | Employment-type filters (applied to each job). |
| companyId | integer | No | — | Restrict to one employer by numeric ID. |
| language / applicationMethod | string | No | — | Posting language / apply method filters. |
| excludeSponsored | boolean | No | `false` | Drop promoted listings. |
| includeKeywords / excludeKeywords | object | No | — | Keyword rules on title / description / skills. |
| fromDate / toDate / maxAgeMinutes | string / integer | No | — | Date-window filters. |
| customFilters | array | No | — | Field-level rules (`gte`, `includes`, …). |
| includeDetails | boolean | No | `true` | Fetch each job's detail page. |
| descriptionFormat | string | No | `html` | `html` / `text` / `markdown` / `original`. |
| maxResults | integer | No | 100 | Max jobs to return (billed rows). 0 = unlimited. |
| maxPages | integer | No | 10 | Max result pages (25 jobs/page). Auto-raised as needed. |
| compact / descriptionMaxLength / excludeEmptyFields / outputFields | — | No | — | Output-shaping options. |
| datasetName | string | No | — | Push to a custom named dataset (`{DATE}` / `{TIME}` masks). |
| mode | string | No | `full` | `full` or `incremental` change tracking. |
| stateStoreName / emitUnchanged / emitExpired / skipReposts | — | No | `totaljobs-state` | Incremental-mode settings. |
| dedupStoreName / dedupKey | string | No | — | Cross-run deduplication (full mode). |
| proxyConfiguration | object | No | UK RESIDENTIAL | Apify Proxy settings. |

\* Provide at least one of `query`, `location`, or `startUrls`.

### Example input

```json
{
  "query": "data engineer",
  "location": "London",
  "contractType": "FULL_TIME",
  "minSalary": 60000,
  "maxResults": 100
}
```

Incremental tracking:

```json
{
  "query": "data engineer",
  "maxResults": 200,
  "mode": "incremental",
  "stateStoreName": "data-engineer-tracker"
}
```

### Output example

```json
{
  "jobKey": "106464063",
  "legacyJobId": 106464063,
  "harmonisedId": "ac402b3b-a5cb-472a-b535-d3abba5c5b2f",
  "title": "Domestic Appliance Engineer",
  "company": "RECRUIT123 LIMITED",
  "companyId": 1051840,
  "companyUrl": "https://www.totaljobs.com/jobs/recruit123?cmpId=1051840&cmp=1",
  "companyLogoUrl": "https://www.totaljobs.com/CompanyLogos/4360d0fffa3c441b93f31e568ccfefb8.png",
  "location": "Birmingham (B33), B33",
  "postCode": "B33",
  "locationDetail": { "city": "Birmingham", "region": "West Midlands", "country": "GB", "postalCode": "B33", "lat": 52.48075, "lng": -1.79307 },
  "unifiedSalary": { "min": null, "max": null, "currency": null, "period": null, "salaryAvailable": false },
  "salaryText": "Competitive salary",
  "description": "<p><b>Are you looking for a role that offers flexibility?</b></p>...",
  "descriptionLength": 2025,
  "workFromHome": false,
  "employmentType": "FULL_TIME",
  "contractType": "Permanent",
  "directApply": true,
  "applicationMethod": "INTERNAL",
  "industry": "Engineering, Engineering-Maintenance",
  "language": "en",
  "isSponsored": false,
  "topLabels": ["NEW"],
  "datePosted": "2026-01-06T08:06:14.8Z",
  "postedDaysAgo": 2,
  "validThrough": "2026-02-17T08:06:14.8Z",
  "canonicalUrl": "https://www.totaljobs.com/job/domestic-appliance-engineer/recruit123-limited-job106464063",
  "url": "https://www.totaljobs.com/job/domestic-appliance-engineer/recruit123-limited-job106464063",
  "portalUrl": "https://www.totaljobs.com",
  "geo": "TOTALJOBS",
  "query": "engineer",
  "scrapedAt": "2026-09-09T10:00:00.000Z",
  "detailsFetched": true,
  "similarJobCount": 10,
  "isRepost": false
}
```

Download the dataset as JSON, CSV, Excel, XML, or HTML from the **Storage** tab or the [Apify API](https://docs.apify.com/api/v2).

### How to scrape Totaljobs

1. Open the **Input** tab of the Totaljobs Scraper.
2. Enter a **search term** — a job title or skill such as `data engineer` or `care assistant`.
3. Optionally set a **location** (`London`, `Manchester`), a **contract type**, a **minimum salary**, a **radius** in miles, and a **"posted within"** window.
4. Set **Max results** — start with 25–50 to keep the first run fast and cheap.
5. Click **Start**. Results stream into the dataset as they are scraped.
6. Export from the **Storage** tab, pull the data via API, or connect an [integration](https://docs.apify.com/platform/integrations) (Google Sheets, Slack, Zapier, Make, webhooks).

To scrape Totaljobs on a schedule, use Apify [Schedules](https://docs.apify.com/platform/schedules) and set `mode` to `incremental` so each run returns only what changed.

#### Python and JavaScript API examples

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("parsebird/totaljobs-scraper").call(run_input={
    "query": "data engineer",
    "location": "London",
    "maxResults": 50,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], item["company"], item["unifiedSalary"])
```

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('parsebird/totaljobs-scraper').call({
    query: 'data engineer',
    location: 'London',
    maxResults: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Filtering and monitoring

- **Server-side filters** (handled by Totaljobs' own search): keyword, location, contract prefix, minimum salary, radius in miles.
- **Client-side filters** (applied to each parsed job): posted-within days, work type, experience, company ID, language, application method, sponsored, include/exclude keywords, date window, max age, and free-form `customFilters` on any output field (dot notation, e.g. `unifiedSalary.min`).
- **Incremental mode**: set `mode` to `incremental` and reuse a `stateStoreName`. The first run records a baseline; later runs emit only `NEW` / `UPDATED` / `REAPPEARED` jobs (add `emitUnchanged` / `emitExpired` for the rest). Reposts of expired jobs are detected and tagged.
- **Cross-run dedup**: in `full` mode, set `dedupStoreName` to push only jobs never seen in previous runs with that store.

### How much does it cost to scrape Totaljobs?

This actor uses **pay-per-result** pricing:

| Plan | Price per 1,000 jobs |
|------|----------------------|
| Free | **$0.99** |
| Bronze | $0.89 |
| Silver | $0.89 |
| Gold | $0.79 |

One event is charged per job row pushed to the dataset. Scraping 100 jobs with full details costs about **$0.10** on the Free plan. Apify platform usage (compute + UK residential proxy) is billed separately per your plan.

### Use cases

- 📈 **UK job-market research** — track vacancy volume and salaries for a role or sector over time.
- 🧭 **Recruiting and sourcing** — monitor new listings in a city and category every morning.
- 💷 **Salary benchmarking** — aggregate `unifiedSalary.min` / `unifiedSalary.max` by role, seniority, and location.
- 🔁 **Job-board aggregation** — feed Totaljobs listings into your own product alongside other sources.
- 🔔 **Alerting** — schedule with `mode: incremental` + `maxAgeMinutes: 60` and route new jobs to Slack or a webhook.

### How it works

1. The actor builds a Totaljobs search URL from your keyword, location, minimum salary and radius, and requests it through Apify's UK residential proxy.
2. It reads the listing data embedded in each results page and follows pagination up to `maxPages` (25 jobs per page), deduplicating by job key.
3. With `includeDetails` on (or when a client-side filter needs it), it opens each job page for the full description, employment type, industry, ISO dates, and geo-coordinates.
4. Client-side filters run, incremental diffing or cross-run dedup is applied, output is shaped, and each row is pushed and billed once.

### FAQ

**Do I need a Totaljobs account?**
No. The scraper only reads public search results and job pages.

**Why do some jobs have no salary or employer profile?**
Many UK listings show "Competitive" instead of a figure, and employer profiles (website, rating) exist only for companies with a Totaljobs company page. Every other field is still returned.

**Why is the radius in miles?**
Totaljobs is a UK board and its search works in miles. Only 5, 10, 20 and 30 are answered by the site; any other choice is reduced to 30 miles (about 48 km) and noted in the run log.

**How do the advanced contract types map?**
Totaljobs' search supports a few contract prefixes (permanent, part-time, contract, temporary, work-from-home). Values like `INTERNSHIP` or `FREELANCE` are mapped to the closest prefix and then enforced against each job's parsed employment type.

**Can I run this on a schedule?**
Yes. Use Apify [Schedules](https://docs.apify.com/platform/schedules) with `mode: incremental`, and [webhooks](https://docs.apify.com/platform/integrations/webhooks) or [integrations](https://docs.apify.com/platform/integrations) to route new jobs into your tools.

**Something looks wrong or a field is missing.**
Open an issue on the **Issues** tab with your input and the run ID.

### Is it legal to scrape Totaljobs?

Scraping publicly available data is legal in most jurisdictions, and this actor only reads pages any visitor can load without logging in. It does not bypass authentication and does not collect personal data about individuals. You are responsible for how you use the data — review Totaljobs' Terms and Conditions and Apify's guide on [the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/) before large-scale or commercial use.

### Related actors

- [IrishJobs.ie Scraper](https://apify.com/parsebird/irishjobs-scraper) — Ireland's job board on the same platform, identical structured output
- [Jobs.ie Scraper](https://apify.com/parsebird/jobs-ie-scraper) — the other big Irish job board
- [NHS UK Jobs Scraper](https://apify.com/parsebird/nhs-uk-jobs-scraper) — UK healthcare jobs
- [Indeed Jobs Scraper](https://apify.com/parsebird/indeed-jobs-scraper) — Indeed listings across 60+ countries

Browse all [ParseBird actors](https://apify.com/parsebird) for more job boards and data sources.

# Actor input Schema

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

Direct Totaljobs search URLs (e.g. `https://www.totaljobs.com/jobs/software-developer/in-london`) or job-detail URLs (`https://www.totaljobs.com/job/.../...job123456789`). When provided, Search term and Location are ignored.

## `query` (type: `string`):

Job search keyword, e.g. `data engineer` or `software-developer`. Use a JSON array `["query1", "query2"]` to run several searches. Not required when Start URLs is provided.

## `location` (type: `string`):

City or region, e.g. `London`, `Manchester`, `Birmingham`. Use a JSON array for multiple locations.

## `geo` (type: `string`):

Fixed to Totaljobs (UK). Informational only.

## `sort` (type: `string`):

Order results are returned in.

## `age` (type: `integer`):

Only keep jobs posted within this many days (applied to each job's posting date).

## `remote` (type: `boolean`):

Only show remote / work-from-home positions.

## `radius` (type: `string`):

Search radius around the location, in MILES — this is a UK board and it searches in miles, not kilometres. Only 5, 10, 20 and 30 are answered; any other choice is reduced to 30 miles (about 48 km) and noted in the log. Requires a location.

## `minSalary` (type: `integer`):

Minimum annual salary filter, in pounds.

## `contractType` (type: `string`):

Filter by contract / employment type.

## `experience` (type: `string`):

Filter by experience level (best-effort, applied to the parsed job).

## `workType` (type: `string`):

Filter by work schedule (full-time / part-time).

## `companyId` (type: `integer`):

Filter to a single employer by its numeric Totaljobs company ID (see the `companyId` output field).

## `language` (type: `string`):

Filter by job-posting language, e.g. `en` or `de`.

## `applicationMethod` (type: `string`):

Filter by how to apply. `INTERNAL` = apply on Totaljobs, `EXTERNAL` = apply on the employer's site.

## `excludeSponsored` (type: `boolean`):

Skip sponsored / promoted listings (`isSponsored = true`).

## `includeKeywords` (type: `object`):

Require at least one of these keywords in the title / description / skills. Example: {"keywords":\["React","Node.js"],"matchTitle":true,"matchDescription":true,"matchSkills":true}.

## `excludeKeywords` (type: `object`):

Exclude jobs containing any of these keywords. Same config shape as Include keywords.

## `fromDate` (type: `string`):

Only include jobs posted on or after this date. Accepts `YYYY-MM-DD` or ISO-8601.

## `toDate` (type: `string`):

Only include jobs posted on or before this date.

## `maxAgeMinutes` (type: `integer`):

Only include jobs posted within the last N minutes. 0 = no limit. Pairs well with hourly scheduled runs (e.g. 60).

## `customFilters` (type: `array`):

Rules applied to any output field. Each rule: {"field":"","op":"includes|notIncludes|equals|notEquals|gt|gte|lt|lte","value":...}. Example: \[{"field":"location","op":"includes","value":"London"}, {"field":"unifiedSalary.min","op":"gte","value":50000}].

## `includeDetails` (type: `boolean`):

Fetch each job's detail page for the full description, ISO dates, employment type, industry, and geo-coordinates. Slower but much richer data.

## `detailEngine` (type: `string`):

Controls how job detail pages are fetched. Auto (recommended) lets the actor choose the best method automatically. Lightweight is faster; Enhanced is heavier but more reliable.

## `descriptionFormat` (type: `string`):

Format for the job description text (requires Include full details).

## `maxResults` (type: `integer`):

Maximum number of job listings to return. This is the number of billed rows. 0 = unlimited.

## `maxPages` (type: `integer`):

Maximum search-result pages to scrape (25 jobs/page). Automatically raised when Max results requires more pages, so this is rarely a hard cap.

## `compact` (type: `boolean`):

Return only the 11 most essential fields (jobKey, title, company, location, url, portalUrl, datePosted, workFromHome, unifiedSalary, geo, description) — for AI-agent and MCP workflows where token budget matters.

## `descriptionMaxLength` (type: `integer`):

Truncate the description field to this many characters, appending '...' if truncated. 0 = no truncation.

## `excludeEmptyFields` (type: `boolean`):

Drop null, empty-string, and empty-array fields from each record. Smaller payloads for AI agents and dashboards.

## `outputFields` (type: `array`):

Return only this subset of fields. Supports dot notation, e.g. `locationDetail.city` or `unifiedSalary.min`. Empty = all fields.

## `datasetName` (type: `string`):

Custom named dataset. Supports masks: {DATE} = YYYYMMDD, {TIME} = HHMMSS.

## `mode` (type: `string`):

`full` returns all jobs found. `incremental` returns only jobs not seen (or changed) since previous runs with the same state store. State is scoped per query + location combination.

## `stateStoreName` (type: `string`):

Key-value store name for incremental state. Use the same name across scheduled runs.

## `emitUnchanged` (type: `boolean`):

In incremental mode, also emit records that haven't changed since the last run.

## `emitExpired` (type: `boolean`):

In incremental mode, also emit records that are no longer found on the site.

## `skipReposts` (type: `boolean`):

Exclude listings detected as reposts of previously seen jobs.

## `dedupStoreName` (type: `string`):

Named key-value store for cross-run dedup (used when Mode is `full`). Same name across runs = only new jobs are pushed.

## `dedupKey` (type: `string`):

Field used as the unique key for dedup.

## `proxyConfiguration` (type: `object`):

Totaljobs blocks datacenter ranges and throttles by IP, so UK residential routing is preset. Change it only for an account-specific setup.

## Actor input object example

```json
{
  "startUrls": [],
  "query": "data engineer",
  "geo": "TOTALJOBS",
  "sort": "relevance",
  "remote": false,
  "excludeSponsored": false,
  "maxAgeMinutes": 0,
  "includeDetails": true,
  "detailEngine": "auto",
  "descriptionFormat": "html",
  "maxResults": 25,
  "maxPages": 5,
  "compact": false,
  "descriptionMaxLength": 0,
  "excludeEmptyFields": false,
  "outputFields": [],
  "mode": "full",
  "stateStoreName": "totaljobs-state",
  "emitUnchanged": false,
  "emitExpired": false,
  "skipReposts": false,
  "dedupKey": "jobKey",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "GB"
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

# 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": [],
    "query": "data engineer",
    "location": "",
    "geo": "TOTALJOBS",
    "minSalary": 0,
    "language": "",
    "fromDate": "",
    "toDate": "",
    "maxResults": 25,
    "maxPages": 5,
    "outputFields": [],
    "datasetName": "",
    "stateStoreName": "totaljobs-state",
    "dedupStoreName": "",
    "dedupKey": "jobKey",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "GB"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("parsebird/totaljobs-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": [],
    "query": "data engineer",
    "location": "",
    "geo": "TOTALJOBS",
    "minSalary": 0,
    "language": "",
    "fromDate": "",
    "toDate": "",
    "maxResults": 25,
    "maxPages": 5,
    "outputFields": [],
    "datasetName": "",
    "stateStoreName": "totaljobs-state",
    "dedupStoreName": "",
    "dedupKey": "jobKey",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "GB",
    },
}

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

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).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": [],
  "query": "data engineer",
  "location": "",
  "geo": "TOTALJOBS",
  "minSalary": 0,
  "language": "",
  "fromDate": "",
  "toDate": "",
  "maxResults": 25,
  "maxPages": 5,
  "outputFields": [],
  "datasetName": "",
  "stateStoreName": "totaljobs-state",
  "dedupStoreName": "",
  "dedupKey": "jobKey",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "GB"
  }
}' |
apify call parsebird/totaljobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,parsebird/totaljobs-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/QcOoRtoYnAtNA6ITX/builds/kG4Z6a4qXk17o4RSr/openapi.json
