# SEEK Jobs Scraper - Australia & New Zealand Job Listings (`abotapi/seek-scraper`) Actor

From $0.7/1K. Scrape SEEK.com.au and SEEK.co.nz jobs by keyword, location, or filters. Extract full descriptions, companies, salaries, locations, classifications, listing dates, and more across Australia and New Zealand.

- **URL**: https://apify.com/abotapi/seek-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** Jobs, Developer tools, Automation
- **Stats:** 142 total users, 6 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $0.70 / 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.
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

## SEEK Jobs Scraper (Australia & New Zealand)

Extract job listings from **SEEK.com.au** and **SEEK.co.nz**, the largest job boards in Australia and New Zealand with hundreds of thousands of live roles. Get comprehensive data including full descriptions, companies, salaries, locations, classifications, and listing dates for any keyword, location, or filter combination.

### What does SEEK Jobs Scraper do?

This Actor collects job data from SEEK in two ways:

1. **Search by filters.** Enter keywords, location, classification, work type, and salary range. Select AU or NZ via the `region` input. The Actor returns every matching job, paginating automatically.
2. **Fetch by URL.** Paste SEEK search URLs directly (e.g. `/software-engineer-jobs/in-Sydney` for AU or `/software-engineer-jobs/in-Auckland` on seek.co.nz for NZ). Region is auto-detected per URL, so you can mix AU and NZ URLs in the same run.

A single toggle switches between fast card-only output and fully-enriched records with the complete HTML job description, company overview, expiry date, and more.

The Apify form groups inputs into two modes: **Option 1: Search by filters** and **Option 2: Paste SEEK URLs** (which overrides Option 1). The relationship is visible at a glance. If you fill both, the actor logs exactly which fields were ignored.

#### Key Features

| Feature | Description |
|---------|-------------|
| **AU + NZ coverage** | `region=AU` → seek.com.au, `region=NZ` → seek.co.nz. URL mode auto-detects per URL. |
| **Structured filters** | Keywords, location, classification (multi-select, 30 options), work type (multi-select, 4 options), work arrangement (Remote / Hybrid / On-site), salary range (annual or hourly), date range |
| **URL mode** | Paste SEEK search URLs; filters parsed automatically; multi-URL supported |
| **Full URL grammar** | Keyword URLs (`/python-jobs`), classification landing pages (`/jobs-in-accounting`), subclassifications (`/jobs-in-accounting/payroll`, 394 known), work-type shortcuts (`/jobs-in-accounting/full-time`), classification + location (`/jobs-in-accounting/in-All-Perth-WA`) |
| **Forward pagination** | Walks pages 1→2→3… until the cap is hit or results run out |
| **Mid-URL resume** | URLs with `?page=5` start at page 5 and continue forward |
| **Page-fail tolerance** | If one page fails after retries, the Actor logs it and skips to the next |
| **Full job descriptions** | Optional HTML body + plain text, ad bullet points, expiry, contacts |
| **Company profiles** | Industry, size, website, specialities, star rating, review count, perks and awards for the hiring company |
| **Parsed salary** | Minimum, maximum and period read out of SEEK's free-text salary label |
| **Cross-URL dedup** | Same job appearing under two searches is emitted once |
| **Total item cap** | `maxItems` bounds the run across all URLs and pages |
| **Wall-clock cap** | `maxTimeSec` stops pagination after N seconds and flushes partial results |
| **Free-tier friendly** | Keeps running when Apify Proxy isn't available on your plan |

### What data can you extract?

<table>
<tr><td>

**Identity and link**

- Job ID
- Canonical job URL
- Apply URL
- SEEK role ID
- Share link
- Job title

</td><td>

**Company**

- Company name and ID
- Company profile URL and open-jobs URL
- Company overview (paragraphs)
- Industry, company size, website
- Specialities and head-office location
- Star rating, review count, salary rating
- Perks and benefits, awards
- Logo and cover image
- Advertiser name, ID, verification, and registration date

</td></tr>
<tr><td>

**Location**

- Location label (e.g. `Suburb, City STATE`)
- Area (e.g. `CBD & Inner Suburbs`)
- SEO hierarchy (e.g. `[Suburb STATE postcode, All City STATE]`)
- Country code

</td><td>

**Classification**

- Classification ID and label
- Subclassification ID and label
- Work types (Full time, Contract, …)
- Work arrangement (Remote, Hybrid, On-site)

</td></tr>
<tr><td>

**Compensation and dates**

- Salary label (as displayed by SEEK)
- Parsed salary minimum and maximum
- Salary period (annual / hourly / daily / monthly)
- Salary currency
- Listing date (UTC + relative display)
- Expires at (UTC)
- Listing status, expired flag, verified signal

</td><td>

**Content and presentation**

- Teaser and short summary
- Bullet points from the ad
- Description sections
- Full description HTML (with `includeFullDescription`)
- Plain-text description (stripped HTML)
- Contact emails and phone numbers published in the ad
- Applies-on-employer-site flag
- Job video URL

</td></tr>
</table>

### How to use the SEEK Jobs Scraper

#### Search by keywords and location (AU)

```json
{
  "region": "AU",
  "keywords": "software engineer",
  "location": "Sydney",
  "sortmode": "ListedDate",
  "includeFullDescription": true,
  "maxItems": 200
}
```

#### Search in New Zealand

```json
{
  "region": "NZ",
  "keywords": "software engineer",
  "location": "Auckland",
  "includeFullDescription": true,
  "maxItems": 200
}
```

#### Mixed AU + NZ URLs in one run

```json
{
  "urls": [
    { "url": "https://www.seek.com.au/nurse-jobs/in-Sydney" },
    { "url": "https://www.seek.co.nz/software-engineer-jobs/in-Auckland" }
  ],
  "includeFullDescription": false,
  "maxItems": 500
}
```

Region is auto-detected from each URL's host. Output rows carry the correct `countryCode` and canonical `url` for the region.

#### Filter by salary, work type, and recency

```json
{
  "keywords": "data engineer",
  "location": "All Melbourne VIC",
  "classification": ["6281"],
  "workType": ["242"],
  "salaryType": "annual",
  "salaryMin": 120000,
  "salaryMax": 200000,
  "daterange": 7,
  "sortmode": "ListedDate",
  "maxItems": 300
}
```

The Apify UI renders `classification`, `workType` and `workArrangement` as multi-select dropdowns with human-readable names, so you don't need to memorize the IDs. When scripting via API, pass the IDs directly (e.g. `"6281"` = Information & Communication Technology, `"242"` = Full time, `"3"` = Remote).

#### Remote-only jobs, paid by the hour

```json
{
  "keywords": "registered nurse",
  "location": "All-Australia",
  "workArrangement": ["3"],
  "salaryType": "hourly",
  "salaryMin": 40,
  "salaryMax": 80,
  "maxItems": 100
}
```

With `salaryType=hourly`, the salary range is read as dollars **per hour**. Use `workArrangement` `"1"` for on-site, `"2"` for hybrid, `"3"` for remote — combine them to widen the search.

#### Fetch specific searches by URL

```json
{
  "urls": [
    { "url": "https://www.seek.com.au/python-jobs/in-Sydney?daterange=14" },
    { "url": "https://www.seek.com.au/golang-jobs/in-Brisbane" }
  ],
  "includeFullDescription": true,
  "maxItems": 300
}
```

Each URL is processed in order. The Actor parses the keyword, location, and query-string filters, then paginates forward.

#### Supported URL shapes

| Path | Interpretation |
|---|---|
| `/jobs` | All jobs |
| `/jobs/in-<location>` | Filter by location only |
| `/<keyword>-jobs` | Filter by keyword (e.g. `/python-jobs`, `/software-engineer-jobs`) |
| `/<keyword>-jobs/in-<location>` | Keyword + location |
| `/jobs-in-<classification>` | Classification landing page (e.g. `/jobs-in-accounting` → classification=1200) |
| `/jobs-in-<classification>/in-<location>` | Classification + location |
| `/jobs-in-<classification>/<subclassification>` | Classification + subclass (e.g. `/jobs-in-accounting/payroll` → 1200 + 1468) |
| `/jobs-in-<classification>/<work-type>` | Classification + Full time / Part time / Contract-Temp / Casual-Vacation |
| `/jobs-in-<classification>/<work-arrangement>` | Classification + On-site / Hybrid / Remote |

Query-string filters are honored on top of any of the above: `?classification=6281&subclassification=6290&worktype=242&salaryrange=100000-200000&daterange=7&page=2`.

Unknown classification or subclassification slugs (e.g. `/jobs-in-fake-class`) are rejected with a clear error that lists the valid slugs. Non-search paths like `/job/<id>`, `/companies/<slug>`, `/career-advice/...` are also rejected.

#### Resume from a specific page

```json
{
  "urls": [
    { "url": "https://www.seek.com.au/software-engineer-jobs/in-Sydney?page=5" }
  ],
  "maxItems": 100
}
```

Pagination starts at page 5 and walks forward until 100 items are collected.

#### Card-only mode (no detail fetch)

```json
{
  "keywords": "nurse",
  "location": "Brisbane",
  "includeFullDescription": false,
  "maxItems": 1000
}
```

Skips the per-job detail fetch entirely. Still returns title, company, location, classifications, work types, salary label, listing date, bullet points, and teaser.

#### Time-capped run

```json
{
  "keywords": "software engineer",
  "location": "All-Australia",
  "maxItems": 0,
  "maxTimeSec": 300
}
```

Keeps paginating for at most 5 minutes; partial results are always flushed to the dataset.

### Input Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `region` | string | `AU` | `AU` (seek.com.au) or `NZ` (seek.co.nz). Auto-detected per URL in URL mode. |
| `keywords` | string | | Job title or keywords (e.g. `software engineer`). Empty = match everything in the location. |
| `location` | string | `All-Australia` | Search location (`Sydney`, `All Melbourne VIC`, `All-Australia`, etc.) |
| `classification` | string\[] | `[]` | Top-level classifications. Multi-select dropdown (30 options) in the UI; accepts raw IDs (e.g. `"6281"` for ICT) via API. |
| `workType` | string\[] | `[]` | Work types. Multi-select dropdown (Full time / Part time / Contract/Temp / Casual/Vacation) in the UI; accepts raw IDs (`"242"`–`"245"`) via API. |
| `workArrangement` | string\[] | `[]` | Where the job is done. Multi-select dropdown (On-site / Hybrid / Remote) in the UI; accepts raw IDs (`"1"`–`"3"`) via API. |
| `salaryType` | string | `annual` | The unit `salaryMin`/`salaryMax` are read in: `annual` or `hourly`. |
| `salaryMin` | integer | | Minimum salary, in the unit set by `salaryType`. Rounded down by SEEK. |
| `salaryMax` | integer | | Maximum salary, in the unit set by `salaryType`. If set out of order with `salaryMin`, they're auto-swapped with a warning. |
| `daterange` | integer | | Listed within N days. Must be one of `1, 3, 7, 14, 31`. Other values are cleared with a warning. |
| `sortmode` | string | `ListedDate` | `ListedDate` or `KeywordRelevance` |
| `urls` | object\[] | `[]` | SEEK search URLs. When set, the structured filters above are ignored (a warning lists what was dropped). |
| `includeFullDescription` | boolean | `true` | Fetch each job's full detail on top of the search card: description, ad bullet points, contacts, and the employer's company profile (industry, size, website, rating, reviews, perks). Batched per page of results — one extra request covers up to 22 jobs. |
| `maxItems` | integer | `20` | Total cap across ALL URLs and pages. Set `0` for unlimited. |
| `maxTimeSec` | integer | `0` | Global wall-clock cap in seconds. `0` = no limit. |
| `resumeFromRunId` | string | *(empty)* | Continue one specific interrupted run. See "Resume and recurring updates" below. |
| `incrementalMode` | boolean | `false` | Track a scheduled search across runs and classify changes. See below. |
| `stateKey` | string | *(empty)* | Optional name for the Incremental mode baseline. Auto-derived when empty. |
| `emitUnchanged` | boolean | `false` | Also push rows unchanged since the last Incremental mode run. Bills extra rows. |
| `emitExpired` | boolean | `false` | Push a synthetic row for jobs that dropped out of a fully-scanned search. Bills extra rows. |
| `proxyConfiguration` | object | Apify datacenter | Proxy config; auto-falls back to a backup pool if Apify proxy isn't available |

### Resume and recurring updates

**Resume (`resumeFromRunId`)** continues one specific interrupted run: paste the run ID or dataset ID from a previous run and this one skips every job already collected there, picking up only what's still missing.

**Incremental mode (`incrementalMode`)** is for a search you run on a *schedule* (daily/weekly) against the same keywords/location/filters. Turn it on and the actor remembers what the search returned last time and classifies every job as:

- `NEW` — not seen before
- `UPDATED` — content changed since last time (see `changedFields`)
- `UNCHANGED` — identical to last time
- `REAPPEARED` — was gone, is back
- `EXPIRED` — tracked before, no longer found (only after a run that scanned every page of every search with nothing capping, time-limiting, or interrupting it — a partial scan can't tell "gone" from "not reached yet")

Off by default, so every existing scheduled run is unaffected. `stateKey` names the saved baseline; leave it empty and the actor derives one automatically from `region`/`keywords`/`location`/`classification`/`subclassification`/`workType`/`workArrangement`/`salaryType`/`salaryMin`/`salaryMax`/`daterange`/`sortmode`/`urls`/`includeFullDescription`, so two differently-configured searches never share a baseline by accident.

By default, only `NEW`/`UPDATED`/`REAPPEARED`/`EXPIRED` rows are pushed. **Turning on `emitUnchanged` or `emitExpired` bills extra rows** (the per-result event, plus the detail-enrichment surcharge if `includeFullDescription` is on) for the additional rows those toggles push — leave them off if you only want to pay for what actually changed.

### Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step **after** the scrape — the Apify dataset is never changed.

**What gets written to the connector:** a condensed, human-readable **summary** of each record — not the full JSON. Each item becomes one entry with a **title** and its key fields flattened to plain text. The **complete record always stays in the Apify dataset**.

1. Authorize a connector once under **Apify → Settings → Integrations** (Notion, Linear, Airtable, or Apify).
2. Select it in the **"Pipe results into your apps"** input field. (If the picker is empty, you haven't authorized a connector yet.)
3. For **Notion**, also set `notionParentPageUrl` to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

### Output Example

```json
{
  "id": "<JOB_ID>",
  "url": "https://www.seek.com.au/job/%3CJOB_ID%3E",
  "jobLink": "https://www.seek.com.au/job/%3CJOB_ID%3E",
  "applyLink": "https://www.seek.com.au/job/%3CJOB_ID%3E/apply",
  "title": "<Job title>",
  "teaser": "<One-line summary of the role.>",
  "jobHook": "<One-line summary of the role.>",
  "abstract": "<Short summary of the role, as written by the employer.>",
  "content": "<p><strong>About the role</strong></p><ul><li>...</li></ul>",
  "contentText": "About the role …",
  "contentSections": ["About the role", "First requirement", "Second requirement"],
  "bulletPoints": [
    "<Bullet point 1>",
    "<Bullet point 2>",
    "<Bullet point 3>"
  ],
  "companyName": "<Company name>",
  "companyId": "<COMPANY_ID>",
  "companyUrl": "https://www.seek.com.au/companies/%3Ccompany-slug%3E-%3CCOMPANY_ID%3E",
  "companyNameSlug": "<company-slug>-<COMPANY_ID>",
  "companyProfileId": 123456,
  "companyOverview": "<Company overview paragraphs joined together …>",
  "companyIndustry": "Healthcare Services",
  "companySize": "More than 10,000 employees",
  "companyWebsite": "https://www.example-employer.com.au/",
  "companySpecialities": ["<Speciality 1>", "<Speciality 2>"],
  "companyPrimaryLocation": "<Street, Suburb STATE postcode>",
  "companyLogo": "https://image-service-cdn.seek.com.au/%3Casset-id%3E",
  "companyCoverImage": "https://image-service-cdn.seek.com.au/%3Casset-id%3E",
  "companyRating": 3.3,
  "companyReviewCount": 81,
  "companySalaryRating": 86,
  "companyPerks": ["<Perk 1>", "<Perk 2>"],
  "companyAwards": [{ "name": "<Award name>", "year": 2025, "imageUrl": null }],
  "advertiserId": "<ADVERTISER_ID>",
  "advertiserName": "<Advertiser name>",
  "locationLabel": "<Suburb, City STATE>",
  "locationSeoHierarchy": ["<Suburb STATE postcode>", "All <City> STATE"],
  "countryCode": "AU",
  "classifications": [
    {
      "id": "<CLASS_ID>",
      "label": "<Top-level classification>",
      "subId": "<SUB_ID>",
      "subLabel": "<Subclassification>"
    }
  ],
  "classificationInfo": {
    "classification": "<Top-level classification>",
    "subClassification": "<Subclassification>"
  },
  "workTypes": ["Full time"],
  "workTypeIds": ["242"],
  "workArrangements": [],
  "workArrangementLabels": ["Hybrid"],
  "workArrangementDisplayText": "Hybrid",
  "salaryLabel": "$120,000 - $140,000 per year + super",
  "salary": "$120,000 - $140,000 per year + super",
  "salaryMin": 120000,
  "salaryMax": 140000,
  "salaryPeriod": "annual",
  "salaryCurrency": "AUD",
  "phoneNumber": null,
  "phoneNumbers": ["0412 345 678"],
  "emails": ["recruiter@example.com"],
  "contactMatches": [
    { "type": "Email", "value": "recruiter@example.com" },
    { "type": "Phone", "value": "0412 345 678" }
  ],
  "shareLink": "https://www.seek.com.au/job/%3CJOB_ID%3E?tracking=SHR-WEB-SharedJob-anz-1",
  "listingDate": "2026-04-17T01:53:13Z",
  "listingDateDisplay": "2d ago",
  "postedTime": "2d ago",
  "expiresAt": "2026-05-14T14:00:00.000Z",
  "isVerified": true,
  "isExpired": false,
  "status": "Active",
  "isLinkOut": false,
  "sourceZone": "anz-1",
  "jobVideoUrl": null,
  "displayTags": [],
  "roleId": "<ROLE_ID>",
  "tags": [{ "type": "EARLY_APPLICANT", "label": "Be an early applicant" }],
  "jobLocationInfo": {
    "displayLocation": "<Suburb, City STATE>",
    "location": "All <City> STATE",
    "area": "CBD & Inner Suburbs",
    "countryCode": "AU",
    "seoHierarchy": ["<Suburb STATE postcode>", "All <City> STATE"]
  },
  "branding": {
    "serpLogoUrl": "https://bx-branding-gateway.cloud.seek.com.au/%3Casset-id%3E/jdpLogo"
  },
  "advertiser": {
    "logo": "https://bx-branding-gateway.cloud.seek.com.au/%3Casset-id%3E/jdpLogo",
    "id": "<ADVERTISER_ID>",
    "name": "<Advertiser name>",
    "isVerified": true,
    "registrationDate": "2022-04-14T03:02:19.728Z"
  },
  "companyOpenJobs": "https://www.seek.com.au/%3CAdvertiser-Name%3E-jobs/at-this-company",
  "companyTags": [],
  "advertiserRaw": { "...": "full upstream advertiser block (verbatim)" },
  "employerRaw": { "...": "full upstream employer block (verbatim — all logo/description fields)" },
  "brandingRaw": { "...": "full upstream branding block (verbatim — all logo URLs)" },
  "companyProfileRaw": { "...": "full upstream companyProfile block (verbatim)" },
  "phoneNumbersFromBody": ["0412 345 678", "(02) 9876 5432"],
  "isFeatured": true,
  "displayType": "promoted",
  "adProductType": null,
  "detailFetched": true,
  "scrapedAt": "2026-04-20T00:40:05.202399+00:00"
}
```

> Fields from `abstract` down to `companyAwards`, plus `contactMatches`, `isExpired`, `status` and `isLinkOut`, are populated only when **Fetch full job description** is on. `detailFetched` tells you, per record, whether that detail actually arrived.

### Tips

- **Pagination is automatic.** The Actor walks pages until `maxItems` is reached or results run out.
- **`maxItems` is a global cap, not per-URL.** With three URLs and `maxItems=50`, URL 1 paginates until the budget is filled; URLs 2 and 3 run only if budget remains.
- **Set `includeFullDescription=false` for high-volume runs.** Skipping the detail fetch trims request count and cost, at the price of the description, contacts and company profile.
- **`salaryType` changes what the salary range means.** With `salaryType=hourly`, enter `salaryMin=40`/`salaryMax=80` — dollars per hour, not per year.
- **Region auto-detected in URL mode.** Mixing `seek.com.au` and `seek.co.nz` URLs in the same input is supported; each URL is routed to its own market.
- **No proxy group is required for typical searches.** For 10k+ job runs, switch to `apifyProxyGroups: ["RESIDENTIAL"]` on a paid Apify plan.
- **Skipped pages are logged, not fatal.** If a single page fails after retries, the Actor moves to the next one. Three consecutive failures end the URL's run cleanly.
- **One page fetched, all 22 items kept.** Partial pages (e.g. when `maxTimeSec` fires mid-page) are flushed to the dataset, so no work is lost.
- **Input conflicts surface as warnings, not silent drops.** Out-of-order salary range → auto-swapped. Unsupported `daterange` value → cleared with a warning. URLs set alongside structured filters → filters ignored (listed in a warning). A fully unbounded run (both `maxItems` and `maxTimeSec` = 0) also warns.

# Actor input Schema

## `region` (type: `string`):

Country market to search. AU = seek.com.au, NZ = seek.co.nz.

## `keywords` (type: `string`):

Job title or keywords (e.g. 'software engineer'). Leave empty to match all jobs in the location.

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

Where to search. AU examples: 'Sydney', 'All Melbourne VIC', 'All-Australia', 'Brisbane CBD & Inner Suburbs'. NZ examples: 'Auckland', 'Wellington', 'All-New-Zealand'.

## `classification` (type: `array`):

Filter by one or more top-level classifications. Leave empty for all. Subclassifications can still be used via URL mode.

## `workType` (type: `array`):

Filter by one or more work types. Leave empty for all.

## `workArrangement` (type: `array`):

Filter by where the job is done. Leave empty for all arrangements.

## `salaryType` (type: `string`):

The unit the salary range below is measured in. Choose 'Hourly rate' for hourly-paid roles — then enter the range in dollars per hour (e.g. 30 to 60), not per year.

## `salaryMin` (type: `integer`):

Optional minimum salary, in the unit chosen above. Rounded down by SEEK.

## `salaryMax` (type: `integer`):

Optional maximum salary, in the unit chosen above.

## `daterange` (type: `integer`):

Only return jobs listed in the last N days. SEEK only accepts one of: 1, 3, 7, 14, 31. Other values are dropped with a warning.

## `sortmode` (type: `string`):

ListedDate = newest first. KeywordRelevance = best match.

## `urls` (type: `array`):

Paste one or more SEEK search URLs (e.g. https://www.seek.com.au/software-engineer-jobs/in-Sydney).

## `includeFullDescription` (type: `boolean`):

If true, each job also gets: the full description (HTML + plain text + sections), the ad's bullet points, expiry date, application-type flag, contact details when published, and the employer's company block — industry, company size, website, specialities, star rating, review count, and perks. Leave off for a faster, lighter run that returns search-card fields only.

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

Total cap across ALL URLs and ALL pages (not per-URL). Example: maxItems=50 with 3 URLs paginates URL 1 until the budget is filled; URLs 2 and 3 run only if budget remains. Set to 0 for unlimited.

## `maxTimeSec` (type: `integer`):

Wall-clock cap across ALL URLs and pages. When exceeded, the actor stops paginating, flushes whatever it already fetched to the dataset, and exits cleanly. Set to 0 for no time limit.

## `resumeFromRunId` (type: `string`):

Paste a previous run ID or dataset ID to continue an interrupted crawl: jobs already collected there are skipped so you get only what's still missing. One-off continuation of a SPECIFIC run - for ongoing scheduled monitoring of the same search, use Incremental mode below instead.

## `incrementalMode` (type: `boolean`):

For a search you run on a schedule (e.g. daily/weekly): remembers what this exact search returned last time and classifies every job as NEW / UPDATED / UNCHANGED / REAPPEARED / EXPIRED, so you can act on only what changed. Off by default so existing scheduled runs are unaffected. Separate from Resume above, which continues one specific interrupted run. Uses State key below to isolate different searches; see Emit unchanged rows / Emit expired rows to control which of those get pushed (both bill extra rows when on).

## `stateKey` (type: `string`):

Names the saved baseline Incremental mode compares against. Leave empty to auto-derive one from your region/keywords/location/classification/workType/workArrangement/salary/daterange/sortmode/urls/includeFullDescription - two differently-configured searches never share a baseline even with this left empty. Set your own text only if you want to explicitly reuse or separate baselines yourself. Ignored when Incremental mode is off.

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

When Incremental mode is on: also push rows classified UNCHANGED (identical to last run), not just NEW/UPDATED/REAPPEARED/EXPIRED. Off by default to save you from paying for rows that didn't change. Turning this on bills the per-result event (and the detail-enrichment surcharge, if Fetch full job description is on) for every unchanged row too.

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

When Incremental mode is on: push a synthetic EXPIRED row for jobs tracked in a previous run that no longer appear in this one. Only fires after a run that scanned every page of every search with no cap, time limit, or resume truncating it - a partial scan can't tell 'gone' apart from 'not reached yet', so it's skipped (with a log line) otherwise. Off by default; turning it on bills the per-result event for each EXPIRED row emitted.

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

Uses Apify Proxy by default. If your account can't access it (free plan), the actor falls back to a backup proxy pool automatically. For heavy/production workloads, set apifyProxyGroups to \["RESIDENTIAL"] on an Apify paid plan.

## `mcpConnectors` (type: `array`):

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).

## `notionParentPageUrl` (type: `string`):

URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "region": "AU",
  "keywords": "software engineer",
  "location": "Sydney",
  "classification": [],
  "workType": [],
  "workArrangement": [],
  "salaryType": "annual",
  "salaryMin": 100000,
  "salaryMax": 200000,
  "daterange": 7,
  "sortmode": "ListedDate",
  "urls": [],
  "includeFullDescription": true,
  "maxItems": 200,
  "maxTimeSec": 300,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": []
  },
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset items (one per job)

# 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 = {
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": []
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/seek-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 = { "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": [],
    } }

# Run the Actor and wait for it to finish
run = client.actor("abotapi/seek-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 '{
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": []
  }
}' |
apify call abotapi/seek-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/seek-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/pFPvioQoH1mSIdNpm/builds/MVksKgsOEEbqtl2sf/openapi.json
