# 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
- **Features:** Limited permissions
- **Stats:** 273 total users, 73 monthly users, 99.4% runs succeeded, 2 bookmarks
- **User rating**: No ratings yet

## 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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## SEEK Scraper: Job Listings, Salaries & Company Profiles

SEEK Scraper turns SEEK, the largest job site in Australia and New Zealand, into structured job data. Search by keyword, location and filters, or paste SEEK search URLs, mixing seek.com.au and seek.co.nz links in one run. Every job returns the employer, location, classification and a parsed salary range, and, when enabled, the full description, ad bullet points, published contacts and the employer's company profile. Export to JSON, CSV or Excel, or read the results through the API.

### Why This Scraper?

- **Two ways to search.** Build a query from keywords, location and filters, or paste one or more SEEK search URLs and skip the filter fields entirely.
- **AU and NZ in one run.** URL mode auto-detects the market per link, so seek.com.au and seek.co.nz URLs can be mixed in the same input.
- **Full detail on demand.** Turn on Fetch full job description for the HTML and plain text body, ad bullet points, published contacts and the employer's company profile.
- **Parsed, not just displayed, salary.** A minimum, maximum, period and currency are parsed out of SEEK's free text salary label.
- **Employer profiles included.** Industry, size, website, specialities, star rating, review count, perks and awards for the hiring company.
- **Wide filter set.** Classification, work type, work arrangement, salary range and listing date, or the full SEEK URL grammar in URL mode.
- **Built for schedules.** Incremental mode returns only new, updated and reappeared jobs on recurring runs, and a genuine connection failure fails loudly instead of returning an empty dataset.

### Use Cases

- **Job board aggregators:** feed AU and NZ listings with full detail into your own site or app.
- **Recruitment and sourcing:** search by classification, work type and salary band to find roles matching a candidate profile.
- **Compensation benchmarking:** collect parsed salary ranges across a classification or location to build a pay band dataset.
- **Employer research:** pull company profiles, ratings and perks alongside their open roles.
- **Market monitoring:** schedule a search with Incremental mode and get only new or changed listings.

### Data You Get

> Sample shape: values are illustrative placeholders, not from a live record.

| Field | Example |
| --- | --- |
| `id` / `url` | job id and its canonical SEEK URL |
| `applyLink` / `shareLink` | the apply URL and a tracked share link |
| `title` / `teaser` / `abstract` | job title, one-line summary, and a short job summary (when enabled) |
| `companyName` / `companyId` / `companyUrl` / `companyOpenJobs` | employer name, id, profile URL, and the SEEK page listing that employer's open jobs (paste it back into URL mode to scrape them) |
| `advertiserName` / `advertiserId` | the advertiser (recruiter or employer) placing the ad |
| `locationLabel` / `jobLocationInfo` / `locationSuburb` / `locationState` / `locationPostcode` | display location, SEO hierarchy, country code, and (when enabled) suburb, state and postcode, e.g. `"Sydney"` / `"New South Wales"` / `"2000"` |
| `classifications` / `classificationInfo` | classification and subclassification, ids and labels |
| `workTypes` / `workArrangementLabels` | `["Full time"]` / `["Hybrid"]` |
| `salaryLabel` / `salaryMin` / `salaryMax` / `salaryPeriod` / `salaryCurrency` | `"$120,000 - $140,000 per year + super"`, parsed into `120000` / `140000` / `"annual"` / `"AUD"`. The currency is the one SEEK records on the ad, else one written in the pay text (`NZD 30 - 35 per hour`, `A$85000`), else the currency of the SEEK site the ad is on (AUD on seek.com.au, NZD on seek.co.nz). It is empty when the ad states no figure. |
| `listingDate` / `listingDateDisplay` | `"2026-04-17T01:53:13Z"` / `"2d ago"` |
| `expiresAt` / `isExpired` / `status` / `isVerified` / `isFeatured` / `displayType` | `"2026-05-14T14:00:00.000Z"` / `false` / `"Active"` / `true` / `true` / `"promoted"` (`expiresAt`, `isExpired` and `status` when enabled) |
| `bulletPoints` | `["3 sample ad highlights"]` (when enabled) |
| `content` / `contentText` / `contentMarkdown` | full description as HTML, plain text and (when **Description format** is Markdown or All) Markdown (when enabled) |
| `urlsFromBody` / `socialProfiles` | web links written in the ad, and the ones that are social profiles (LinkedIn, Facebook, Instagram, X and more) (when enabled) |
| `companyOverview` / `companyIndustry` / `companySize` / `companyWebsite` / `companyLogo` / `companyCoverImage` | employer profile, logo and cover image URL (`companyCoverImage` when enabled) |
| `companyRating` / `companyReviewCount` / `companySalaryRating` / `companyPerks` / `companyAwards` | `3.3` / `81` / `86`, plus perks and awards (when enabled) |
| `phoneNumbers` / `emails` | contacts published in the ad (when enabled) |
| `isLinkOut` / `jobVideoUrl` | applies on the employer's own site, and a job video URL, when present (when enabled) |
| `numApplicants` / `applicantCountLabel` / `applicantVolumeLabel` / `resumePercentage` / `coverLetterPercentage` | applicant count, label and volume, plus the share of applicants who attached a resume / cover letter: `71` / `"71 applicants"` / `"Medium application volume"` / `99` / `46` (when enabled; empty on very fresh ads) |
| `employerQuestions` / `hasRoleRequirements` / `isPrivateAdvertiser` | the employer's screening questions, whether the ad has any, and `true` when the employer is hidden as "Private Advertiser" (when enabled) |
| `recruiterProfile` | on agency ads with a SEEK recruiter profile: name, photo, profile URL, and (when enabled) rating, review count, placements, phone, agency name and website, location, specialisations |
| `isRepost` / `repostOfId` | `true` and the earlier job id when the same advertiser re-listed the same title in the same place |
| `searchQuery` / `searchUrl` | the keywords and the SEEK search page that found the job, handy when one run combines several searches |
| `detailFetched` / `scrapedAt` | whether the full detail actually arrived on this row, and `"2026-04-20T00:40:05.202399+00:00"` |

`content` through `companyAwards`, plus `expiresAt`, `isExpired`, `status`, `isVerified`, `isLinkOut`, `jobVideoUrl` and `companyCoverImage`, are filled only when **Fetch full job description** is on. `detailFetched` shows per record whether that detail arrived.

### How to Use

1. Pick a **mode**. Leave it on **Auto** (the default) and either fill in region, keywords, location and filters, or edit the **SEEK search URLs** list to paste your own links. Choose **Search** or **URL** to force one way.
2. Turn on **Fetch full job description** for the body, contacts and company profile, or leave it off for a lighter, faster run.
3. Set **Max items to return** and **Max run time** to control run size and cost.
4. Click **Start**, then download the dataset as JSON, CSV or Excel, or read it through the API.

**Search by keywords and location (AU):**

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

**Filter by classification, work type and salary:**

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

**Mixed AU and NZ search URLs:**

```json
{
  "mode": "url",
  "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
}
```

#### Choosing a mode

| Mode | What runs |
| --- | --- |
| `auto` (default) | URL mode if you changed the **SEEK search URLs** list, otherwise the search fields (region, keywords, location and filters), exactly as before. |
| `search` | Always the search fields. Any pasted links are ignored, and the log says so. |
| `url` | Always the links in the list. Every search field is ignored. |

The **SEEK search URLs** list ships pre-filled with one example of each supported link shape (the table below, first 11 rows). That has one visible effect: **if you choose URL mode and do not edit the list, the run scrapes one example of each of those 11 link shapes** (set a low **Max items to return** for a quick look). In `auto` mode the untouched list does nothing (this holds for the sample list and for the longer pre-filled form list, which adds legacy-host and variant links), so an API call that sends only keywords and a location behaves exactly as it always did. A list that is different from the shipped one in any way, even in order, counts as yours and switches `auto` to URL mode. If URL mode is on and the list is empty, the run stops with a message saying so. When `auto` picks URL mode because you edited the list while you also set keywords, a company name or a non-default location, the run log says those search fields are ignored.

The shipped job links (`/job/<id>` and `?jobId=`) point at one live ad. Ads close after about a month; a closed one gets a warning for that link only (`could not be fetched (expired, removed, or an invalid id)`), the other links still run, and the run does not fail on it.

#### Every supported URL shape

Paste any of these into **URL mode**; region (AU/NZ) is auto-detected per URL. The first 11 rows are the shipped sample list. Hosts: `au.seek.com` and `nz.seek.com` are SEEK's current hosts; `www.seek.com.au`, `seek.com.au`, `m.seek.com.au` and `www.seek.co.nz` links are read the same way. New Zealand searches and job lookups go straight to `nz.seek.com`, SEEK's current NZ host, which saves a redirect on every request.

| Shape | Example | What it does |
| --- | --- | --- |
| Classification + sub + location (3-segment) | `https://au.seek.com/jobs-in-information-communication-technology/engineering-software/in-All-Sydney-NSW` | classification + subclassification + location |
| Keyword + location + work-type (3-segment) | `https://au.seek.com/software-engineer-jobs/in-All-Sydney-NSW/full-time` | keyword + location + work type/arrangement |
| Keyword + classification combo page (NZ) | `https://nz.seek.com/accountant-jobs-in-accounting/in-All-Auckland` | keyword + classification + location |
| Location only | `https://au.seek.com/jobs/in-All-Sydney-NSW` | every job in that location |
| Bare city (NZ) | `https://nz.seek.com/jobs/in-Wellington` | SEEK's own page for this link is the whole-city page `All Wellington`, so that is what is searched (about 2,300 jobs, where the suburb alone has about 1,800) |
| `?advertiserid=` | `https://au.seek.com/jobs?advertiserid=3490876` | jobs from one employer only |
| `?where=` | `https://au.seek.com/jobs?where=All-Perth-WA` | location, as a query param instead of a path segment |
| Keyword search, paginated | `https://au.seek.com/software-engineer-jobs?page=2` | starts at page 2 and walks forward; an incremental run never marks jobs `EXPIRED` from it, because pages 1 and earlier were not read |
| Direct job link | `https://au.seek.com/job/95066648` | fetches that ONE job by id, never a text search |
| Job share link | `https://au.seek.com/jobs?jobId=95066648` | same: SEEK shows an unfiltered search for this link, so the id is read from it and that one job is fetched |
| Company page | `https://www.seek.com.au/companies/seek-432306` (`/company/<slug>` also matches) | resolved to that employer's `advertiserid` search by reading it off the company's own current job ad (never guessed) |
| Keyword search page | `https://www.seek.com.au/software-engineer-jobs/in-Sydney` | keyword + location |
| Classification landing page | `https://www.seek.com.au/jobs-in-information-communication-technology` | classification |
| Classification + sub + location + work-type (4-segment) | `https://www.seek.com.au/jobs-in-accounting/accounts-payable/in-All-Melbourne-VIC/full-time` | classification + subclassification + location + work type |
| Location + work-type + arrangement (4-segment) | `https://www.seek.com.au/jobs/in-All-Melbourne-VIC/full-time/hybrid` | location + work type + work arrangement |
| Location with a comma | `https://nz.seek.com/jobs/in-Hutt-Central,-Wellington` | suburb + city location, as SEEK's own suburb links write it |
| Jobs at one company | `https://www.seek.com.au/Turner-&-Townsend-jobs/at-this-company` | that employer's jobs only (SEEK's exact-employer filter); the same link the `companyOpenJobs` output field carries |
| Employer link | `https://www.seek.com.au/National-Civil-&-Foundations-Pty-Ltd-jobs` | employer name as keywords, punctuation kept (`+` in a link is a literal hyphen, so `Coca+Cola` reads as `Coca-Cola`) |
| `?distance=` | `https://www.seek.com.au/nurse-jobs/in-Parramatta-NSW-2150?distance=10` | search radius in km around a suburb (1-100) |
| Tracking params | any shape above + `?utm_source=...&gclid=...` | ignored, never changes the result |
| Older hosts | `https://www.seek.com.au/jobs/in-All-Sydney-NSW`, `https://seek.com.au/jobs/in-All-Adelaide-SA`, `https://m.seek.com.au/jobs/in-All-Hobart-TAS`, `https://www.seek.co.nz/jobs/in-Wellington` | same results as the `au.seek.com` / `nz.seek.com` form of the link |

A bare place name in a link (`/jobs/in-Wellington`, `/jobs/in-Sydney`) is searched the way SEEK's own site shows it: the site redirects the link to the whole-area page (`All Wellington`, `All Sydney NSW`), and the log line `location 'Wellington' is SEEK's whole-area page 'All Wellington'` says when that happened. A place SEEK does not know (a typo) is reported by name instead of returning a silent empty run.

A `/companies/<slug>-<id>` link is SEEK's company-profile/review page, not a job search, and its own id is a *different* SEEK id from the job-search `advertiserid`; there is no reliable way to convert one into the other from the URL text alone. The actor instead fetches the company page live, reads a job id off one of its own current ads, and resolves that job's `advertiserid` through the same job-detail lookup used for a direct job link, then searches that employer's jobs. If the company has no job currently live on its profile page (so there is nothing to read an id off), that single URL is skipped with a loud per-URL warning in the run log, never a silent guess; paste one of that company's own job links instead, or filter by employer name in Keywords.

Any other URL (the bare home page, the companies or recruiters directory, career advice), or an unrecognized path/segment, is skipped with a specific per-URL warning in the run log, never a silent zero or a misread "every job" search.

**Remote roles paid hourly, monitored on a schedule:**

```json
{
  "keywords": "registered nurse",
  "workArrangement": ["3"],
  "salaryType": "hourly",
  "salaryMin": 40,
  "salaryMax": 80,
  "incrementalMode": true,
  "stateKey": "remote-nurse-au"
}
```

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/seek-scraper").call(run_input={
    "region": "AU",
    "keywords": "software engineer",
    "location": "Sydney",
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["title"], job["companyName"], job["salaryLabel"])
```

JavaScript:

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/seek-scraper').call({
  region: 'AU',
  keywords: 'software engineer',
  location: 'Sydney',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Or connect it to Slack, email, Make, Zapier, n8n, Google Sheets or webhooks from the **Integrations** tab.

#### Resume and recurring updates

- **Resume** (`resumeFromRunId`) continues one specific interrupted run: paste its run or dataset ID and the actor skips every job already collected there, returning only what's still missing.
- **Incremental mode** (`incrementalMode`) is for a search you run on a schedule. Each job is classified `NEW`, `UPDATED` (with `changedFields`), `UNCHANGED` (suppressed and not billed unless `emitUnchanged` is on), `REAPPEARED`, or `EXPIRED` (only after a run that scanned every page of every search, and only with `emitExpired`). `stateKey` names or shares the stored baseline. `UPDATED` means a real change to the job: any output field differs from the saved copy (title, description, salary, location, work type, classification, advertiser, company rating or review count, expiry or status, the listing date itself), and `changedFields` names which. These never cause `UPDATED` on their own: `scrapedAt`, the relative "N ago" times (`listingDateDisplay`, `postedTime`), `detailFetched`, the repost flags (`isRepost`, `repostOfId`), the applicant numbers (`numApplicants`, `applicantCountLabel`, `applicantVolumeLabel`, `resumePercentage`, `coverLetterPercentage`) `companyOpenJobs` and `salaryCurrency` (both are derived from fields that are compared); add more with `ignoreFieldsForChanges`. If the full-description fetch fails for a job on one run, its description and company details are carried over from the saved copy instead of reading as a change. A capped, filtered or page-2-onward run never marks jobs `EXPIRED`. Incremental rows also carry `firstSeenAt`, `lastSeenAt` and `previousSeenAt` (when the search last saw the job before this run). With incremental mode off, output is exactly as before.

### 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 job, 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.

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `auto` | `auto` (URL mode if you edited the URL list, otherwise search), `search` (ignore pasted links) or `url` (scrape the list, ignore the search fields). |
| `region` | string | `AU` | `AU` (seek.com.au) or `NZ` (seek.co.nz). Auto-detected per URL in URL mode. |
| `keywords` | string | (none) | Job title or keywords. Leave empty to match every job in the location. |
| `keywordsList` | array | (none) | More keyword searches, one search each, merged and de-duplicated under one `maxItems` cap. |
| `companyName` | string | (none) | Only jobs advertised by this employer, using SEEK's own exact-employer filter (any case), e.g. `Turner & Townsend`. Combines with keywords and location. |
| `location` | string | `All-Australia` | Search location as a plain name (suburb, city, area, state or postcode), for example `Sydney`, `All Melbourne VIC`, `Parramatta NSW 2150`, `All-Australia`. The log shows which SEEK location it matched; a name SEEK does not recognise is reported by name. |
| `locationsList` | array | (none) | More locations, one search each (every keyword in every location). Replaces `location` while it is on its default. |
| `radius` | integer | (none) | Search radius in km (1-100) around a suburb or city location. SEEK's default is 50 km. |
| `classification` | array | `[]` | Top-level classifications. Leave empty for all. |
| `subclassification` | array | `[]` | Specific roles inside a classification, picked by name (e.g. "Information & Communication Technology › Developers/Programmers"). |
| `workType` | array | `[]` | Work types: full time, part time, contract or temp, casual or vacation. |
| `workArrangement` | array | `[]` | Where the job is done: on-site, hybrid, or remote. |
| `salaryType` | string | `annual` | Unit for `salaryMin`/`salaryMax`: `annual`, `monthly` or `hourly`. |
| `salaryMin` | integer | (none) | Minimum salary in the chosen unit. |
| `salaryMax` | integer | (none) | Maximum salary in the chosen unit. |
| `daterange` | integer | (none) | Listed within N days. Must be one of `1`, `3`, `7`, `14`, `31`. |
| `sortmode` | string | `ListedDate` | Newest first (`ListedDate`) or most relevant (`KeywordRelevance`). |
| `urls` | array | one sample link per supported shape (11) | SEEK links for URL mode. Used when `mode` is `url`, or `auto` once you edit the list; the search fields are then ignored. Left as shipped and in URL mode, the run scrapes one example of each shape. |
| `includeKeywords` | array | (none) | Post-filter: keep only jobs mentioning at least one of these words (whole words, any case) in the title, company, teaser, bullet points or, when full description is on, the full description. |
| `excludeKeywords` | array | (none) | Post-filter: drop jobs mentioning any of these words, checked against the same text as `includeKeywords`. |
| `keywordMatchFields` | array | all but category | Where the two keyword filters look: `title`, `company`, `description`, `bulletPoints`, `category`. Pick `title` alone to match job titles only. |
| `fromDate` | string | (none) | Post-filter: keep only jobs listed on or after this date or time, e.g. `2026-10-01` or `2026-10-01T09:00:00+10:00`. |
| `toDate` | string | (none) | Post-filter: keep only jobs listed on or before this date or time. A date on its own includes that whole day. |
| `maxAgeMinutes` | integer | (none) | Post-filter: only jobs listed in the last N minutes. |
| `minApplicants` | integer | (none) | Post-filter: keep only jobs with at least this many applicants. Turns on `includeFullDescription` for the run (billed per pushed job as detail enrichment); jobs with no applicant count yet are removed. |
| `maxApplicants` | integer | (none) | Post-filter: keep only jobs with at most this many applicants. Like `minApplicants`, turns on full job details and removes jobs with no applicant count. |
| `requireContact` | string | `off` | Post-filter: `email`, `phone`, `either` or `both`. Turns full job details on. |
| `skipReposts` | boolean | `false` | Drop jobs flagged `isRepost`. |
| `customFilters` | array | (none) | Post-filter rules on output fields, e.g. `[{"field": "salaryMin", "op": "gte", "value": 120000}]`. Ops: `includes`, `notIncludes`, `equals`, `notEquals`, `gt`, `gte`, `lt`, `lte`; a dotted path like `recruiterProfile.rating` works. An unknown field or op fails the run up front. A rule on a field that only comes with the full description (e.g. `companyRating`) turns full job details on. |
| `includeFullDescription` | boolean | `true` | Fetch each job's full detail: description, ad bullet points, contacts and the employer's company profile. |
| `descriptionFormat` | string | `html_text` | `html_text` (HTML + plain text), `all` (adds Markdown), `html`, `text` or `markdown` only. |
| `descriptionMaxLength` | integer | `0` | Cut the plain-text and Markdown description to N characters (`0` = no limit). The HTML copy is never cut. |
| `compact` | boolean | `false` | Return only the core fields an AI agent or spreadsheet needs. |
| `excludeEmptyFields` | boolean | `false` | Leave out fields with no value on a row. |
| `maxItems` | integer | `20` | Stop after this many jobs, across all URLs and pages (`0` = unlimited). |
| `maxTimeSec` | integer | `0` | Global wall clock cap in seconds (`0` = no limit). |
| `resumeFromRunId` | string | (none) | Continue one interrupted run. |
| `incrementalMode` | boolean | `false` | Return only new, updated and reappeared jobs on recurring runs. |
| `stateKey` | string | (none) | Name or share an incremental-mode baseline. |
| `emitUnchanged` | boolean | `false` | Also return (and bill) unchanged jobs. |
| `emitExpired` | boolean | `false` | Also return (and bill) expired jobs. |
| `ignoreFieldsForChanges` | array | `[]` | Incremental mode only: field names (or dotted paths, e.g. `companyProfileRaw.reviewsSummary.overallRating.value`) to exclude from UPDATED change detection, in addition to the built-in handling. The field stays in the output row either way. Applicant numbers, the repost flags and `companyOpenJobs` (a link built from `companyName`) never trigger UPDATED on their own. |
| `proxyConfiguration` | object | Apify Proxy | Connection settings. Uses Apify Proxy by default. |
| `mcpConnectors` | array | (none) | Optional: send a summary of each job to apps you authorized under Integrations. |
| `notionParentPageUrl` | string | (none) | Notion connector only: page under which job pages are created. |
| `maxNotifyListings` | integer | `50` | Cap on items written to each connector per run. |

Post-filters run after a job is found and before it is saved, in both search and URL mode. A job they remove is never pushed and never charged. The run log ends with a count of removed jobs per filter.

### Output Example

> Sample shape: values are illustrative placeholders, not from a live record.

The dataset's **Overview** tab shows one row per job with the key fields above; switch to **Job Detail**, **Company Profile**, **Salary**, **Applicant Insights**, **Recruiter Profile** or **Changes (Incremental mode)** for a focused view of just those fields.

**One job row (full description on):**

```json
{
  "id": "80123456",
  "url": "https://www.seek.com.au/job/80123456",
  "applyLink": "https://www.seek.com.au/job/80123456/apply",
  "title": "Software Engineer",
  "teaser": "Join a growing engineering team building customer-facing products.",
  "companyName": "Sample Company",
  "companyId": "123456",
  "companyUrl": "https://www.seek.com.au/companies/sample-company-123456",
  "advertiserName": "Sample Company",
  "advertiserId": "987654",
  "locationLabel": "Sydney, NSW",
  "classifications": [{ "id": "6281", "label": "Information & Communication Technology", "subId": "6290", "subLabel": "Developers/Programmers" }],
  "workTypes": ["Full time"],
  "workArrangementLabels": ["Hybrid"],
  "salaryLabel": "$120,000 - $140,000 per year + super",
  "salaryMin": 120000,
  "salaryMax": 140000,
  "salaryPeriod": "annual",
  "salaryCurrency": "AUD",
  "listingDate": "2026-04-17T01:53:13Z",
  "listingDateDisplay": "2d ago",
  "expiresAt": "2026-05-14T14:00:00.000Z",
  "isExpired": false,
  "status": "Active",
  "isVerified": true,
  "isFeatured": true,
  "displayType": "promoted",
  "bulletPoints": ["Hybrid working", "Career progression", "Modern tech stack"],
  "companyOverview": "Sample Company builds software for retail and logistics customers across Australia.",
  "companyIndustry": "Information Technology",
  "companySize": "201-500 employees",
  "companyWebsite": "https://www.example-employer.com.au/",
  "companyRating": 3.3,
  "companyReviewCount": 81,
  "companyPerks": ["Flexible hours", "Learning budget"],
  "companyLogo": "https://image-service-cdn.seek.com.au/sample-logo",
  "phoneNumbers": ["0491 570 156"],
  "emails": ["recruiter@example.com"],
  "isLinkOut": false,
  "detailFetched": true,
  "scrapedAt": "2026-04-20T00:40:05.202399+00:00"
}
```

### Plan Requirement

The default proxy setting works without any action on your side: SEEK's current hosts (`au.seek.com`, `nz.seek.com`) answer the actor's datacenter connection with normal content. SEEK's older hosts (`www.seek.com.au`, `seek.com.au`, `m.seek.com.au`, `www.seek.co.nz`) can answer a datacenter connection with a "verify you are human" page instead of job data; the actor treats such a page as a refusal on that connection, never as an empty search, and retries on another connection.

If your account cannot use Apify Proxy, the actor moves to a backup connection and logs this warning:

> The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable. For residential access, upgrade at https://apify.com/pricing or supply your own proxy URLs.

When a page is then served over the backup connection the log says `Served over the backup connection (the default connection was unavailable).` Free plans have no residential proxy, so a free-plan run relies on the backup connection and can read fewer pages on a large run. Setting `apifyProxyGroups` to `["RESIDENTIAL"]` under **Connection & proxy** gives more headroom on plans that include residential proxies.

### FAQ

#### How much does it cost?

Pay per event. Prices per event by Apify plan tier (the rates currently live on the **Pricing** tab):

| Event | Free | Bronze | Silver | Gold |
| --- | --- | --- | --- | --- |
| Actor start (once per run) | $0.08 | $0.07 | $0.06 | $0.05 |
| Result (each job returned) | $0.0015 | $0.0012 | $0.0009 | $0.0007 |
| Job detail enrichment (each job returned with its full description, when **Fetch full job description** is on) | $0.0008 | $0.0007 | $0.0006 | $0.0005 |

Use **Max items to return** to cap the cost of any run, or turn the description off to skip the enrichment charge. Jobs removed by a post-filter, and unchanged jobs in Incremental mode, are not charged.

#### Is it legal to scrape SEEK job listings?

This actor collects only publicly available job listings. You are responsible for how you use it: follow SEEK's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Job facts are generally public, but employer logos, cover images and branding may be subject to third-party rights.

#### Can I get only new or changed jobs on a schedule?

Yes. Schedule the actor from the **Schedules** tab and turn on **Incremental mode**. Each run then returns only new, updated and reappeared jobs, and unchanged ones are not billed unless you turn on `emitUnchanged`.

#### Why does URL mode ignore my filter fields?

URL mode reads its filters from each pasted URL's path and query string, so the keyword, location, classification and other filter fields above are ignored to avoid conflicting instructions. The run log lists exactly what was dropped. To use the filter fields instead, set **Mode** to **Search**.

#### Why do I get about 550 jobs at most from one search?

SEEK itself serves at most 25 pages (about 550 jobs) of any single search, however many jobs match. When a search matches more than that, the run log says so with the match count. To cover everything, split the search: add Locations (`locationsList`), Keywords (`keywordsList`), a classification or sub-classification, a work type or a date range, or paste several URLs. Incremental mode never marks jobs `EXPIRED` after a search that hit this ceiling, because the jobs outside the window were not looked at.

#### Does it cover Singapore, Hong Kong, Malaysia, Indonesia, the Philippines or Thailand?

No. This actor covers SEEK Australia and New Zealand. SEEK's other markets run on the JobStreet and Jobsdb sites; see the JobStreet scraper in the related-scrapers block below.

#### Does it estimate salaries when the ad has none?

No. SEEK publishes the pay an advertiser wrote, and its own salary estimate is only shown to signed-in job seekers, so there is nothing to read for an anonymous visitor. `salaryLabel`, `salaryMin`, `salaryMax`, `salaryPeriod` and `salaryCurrency` hold exactly what the ad states.

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

If nothing could be read because the connection kept failing, rather than SEEK genuinely having no matches, the run fails loudly so "no jobs found" is never confused with "nothing could be read". The message tells you which case it was:

- `The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required: https://apify.com/pricing. If you entered your own proxy URLs, check that their credentials are valid.` The connection was refused outright.
- `No results: residential proxies are unavailable on this run (Apify free plans do not include them), and the backup connection could not load the requested SEEK pages. Upgrade at https://apify.com/pricing or supply your own proxy URLs, then try again.` A free-plan run whose backup connection opened but SEEK never served a usable page.
- `Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later.` Any other run where no page loaded.

If only some searches could be read, you still get what was found. A search that reaches the end of SEEK's own results with zero matches still finishes normally with an empty dataset. If the location you typed is not one SEEK recognises (a typo such as `Sydnee`), the log and the run's status message name it, so check the spelling or use the name as SEEK's own "Where" box shows it.

#### Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable. For agent pipelines, turn on **Compact output** and set **Description format** to Markdown (optionally with **Max description length**) to get small, readable rows.

### 🔗 Want more SEEK data?

Pair this actor with these related scrapers from the same team:

<table>
<tr><td>💼 <a href="https://apify.com/abotapi/seek-companies-reviews-scraper"><b>SEEK Company Reviews</b></a><br>From $1/1K. Scrape SEEK Australia and New Zealand company profiles and employee reviews...</td><td>💼 <a href="https://apify.com/abotapi/monster-com"><b>Monster Jobs Scraper</b></a><br>Scrape Monster.com job listings from search and direct job URLs. Extract full...</td></tr>
<tr><td>💼 <a href="https://apify.com/abotapi/jora-jobs-scraper"><b>Jora Jobs Scraper</b></a><br>Scrape Jora.com job listings across supported countries by keyword, filters, or URL...</td><td>💼 <a href="https://apify.com/abotapi/cwjobs-scraper"><b>Cwjobs UK</b></a><br>From $1/1k. Scrape tech and IT jobs from CWJobs.co.uk into clean, structured data. Search...</td></tr>
<tr><td>💼 <a href="https://apify.com/abotapi/jobstreet-scraper"><b>JobStreet Scraper</b></a><br>From $1/1K. Scrape JobStreet listings across Malaysia, Singapore, Indonesia, and the...</td><td>💼 <a href="https://apify.com/abotapi/simplyhired-com-scraper"><b>SimplyHired</b></a><br>From $1/1K. Pull active SimplyHired jobs across the US, UK, Canada, Australia, Ireland...</td></tr>
</table>

👉 [Browse all abotapi scrapers](https://apify.com/abotapi)

### 💬 Support

- 🐞 **Found a bug or a missing field?** Open a ticket on the [Issues tab](https://apify.com/abotapi/seek-scraper/issues/open). We usually reply within hours.
- 🛠️ **Need another site, extra fields or a private build?** Email <contact@abotapi.com>.
- ⭐ **Enjoying it?** A quick review on the actor page helps other users find it.

# Actor input Schema

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

Auto (default): if you edit the 'SEEK search URLs' list the actor scrapes those links, otherwise it runs the search fields. Search: always use the keyword, location and filter fields; pasted links are ignored. URL: always scrape the links in the list. Left unedited, that list holds one example of each supported link shape.

## `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.

## `keywordsList` (type: `array`):

Run one extra search per entry (e.g. 'registered nurse', 'midwife') on top of Keywords above, with the same filters. Results from every search are merged and de-duplicated by job, and all searches share the one 'Max items to return' cap, filled in order. Leave empty for a single search.

## `companyName` (type: `string`):

Optional. Only jobs advertised by this employer, matched on SEEK's own company filter (exact name, any case), e.g. 'Turner & Townsend' or 'Amplar Health'. Works with Keywords and Location. A name SEEK has no jobs for returns no results. The same filter a SEEK 'jobs at this company' link applies, and the value of the companyOpenJobs output field.

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

Where to search, as a plain place name: a suburb, city, area, state or postcode. AU examples: 'Sydney', 'All Melbourne VIC', 'Parramatta NSW 2150', 'All-Australia', 'Brisbane CBD & Inner Suburbs'. NZ examples: 'Auckland', 'Wellington', 'All-New-Zealand'. The log shows which SEEK location your text matched, and a name SEEK does not recognise is reported by name instead of returning a silent empty run.

## `locationsList` (type: `array`):

Run the search in each of these locations too (e.g. 'Sydney', 'Melbourne VIC'). Combined with More keyword searches, every keyword is searched in every location. If Location above is still on its default 'All-Australia', it is replaced by this list rather than run as an extra country-wide search.

## `radius` (type: `integer`):

Only include jobs within this many kilometres of a suburb or city Location (SEEK's own distance filter). SEEK accepts 1-100 km and uses 50 km when this is empty; it has no effect on state- or country-wide locations.

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

Filter by one or more top-level classifications. Leave empty for all. To narrow further, pick a Subclassification below.

## `subclassification` (type: `array`):

Filter by one or more specific roles inside a classification (e.g. 'Information & Communication Technology › Developers/Programmers'). Works on its own or together with Classification. Leave empty for all. A few government options exist only on SEEK Australia or only on SEEK New Zealand, as marked.

## `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 — or 'Monthly salary' to enter it per month (e.g. 8000 to 12000).

## `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`):

Newest first (SEEK's listed date) or most relevant (SEEK's keyword relevance).

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

SEEK links to scrape. Supported: search pages (any depth: classification, subclassification, keyword, location, work type, work arrangement, up to four path segments, ?advertiserid=, ?where=, ?page=N to start at that page), employer links like /National-Civil-&-Foundations-Pty-Ltd-jobs and /Turner-&-Townsend-jobs/at-this-company (that employer's jobs only), a bare place name like /jobs/in-Wellington (searched as SEEK's whole-area page, All Wellington), locations with a comma, au.seek.com / nz.seek.com and the older www and m. hosts, a single job's /job/<id> or ?jobId= share link (fetched directly, never re-searched), and a company profile /companies/<slug> (resolved to that employer's job search by reading its advertiser id off one of its own current job ads, with a per-link warning if it has none). A job link whose ad has since closed gives a warning for that link and the rest still run. Pages that are not searches (the home page, directories, career advice) are skipped with a warning. See the README's URL-mode table.

## `includeKeywords` (type: `array`):

Keep only jobs that mention at least one of these words in the title, company or advertiser name, teaser, summary, ad bullet points or, when 'Fetch full job description' is on, the full description. Not case-sensitive. Matches whole words, so 'java' does not match 'javascript'.

## `excludeKeywords` (type: `array`):

Drop jobs that mention any of these words, checked against the same text as Include keywords. Not case-sensitive and matches whole words.

## `keywordMatchFields` (type: `array`):

Which parts of each job Include keywords and Exclude keywords are checked against. Leave empty to check the title, company, description (teaser, summary and, when 'Fetch full job description' is on, the full text) and bullet points, the same as before this option existed. Pick 'Title' alone to match job titles only. 'Category' (SEEK classification and sub-classification) is only checked when you pick it. Has no effect unless Include or Exclude keywords is set.

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

Keep only jobs listed at or after this date or time (UTC unless the value includes an offset). Format: 2026-10-01 or 2026-10-01T09:00:00+10:00.

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

Keep only jobs listed at or before this date or time. A date on its own includes that whole day (UTC). Same format as above.

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

Keep only jobs listed in the last N minutes before the run started (e.g. 60 for the past hour). Finer than 'Listed within N days'. Combined with 'Listed on or after', the later of the two cut-offs applies.

## `minApplicants` (type: `integer`):

Keep only jobs with at least this many applicants. Applicant numbers come from each job's full details, so this turns on 'Fetch full job description' for the run (billed per pushed job as detail enrichment). Jobs where SEEK shows no applicant count yet, often ones listed in the last few hours, are removed.

## `maxApplicants` (type: `integer`):

Keep only jobs with at most this many applicants, to find roles with less competition. Like Minimum applicants, this turns on full job details, and jobs with no applicant count are removed.

## `requireContact` (type: `string`):

Keep only jobs that publish contact details (phone or email found in the ad's contact block or description). Turns on full job details for the run (billed per pushed job as detail enrichment).

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

Drop jobs flagged as reposts: the same advertiser re-listing the same title in the same location under a new job ID. With Incremental mode on, jobs are checked against every job the saved search has ever tracked, including expired ones. Without it, only jobs seen in the same run are checked. Every job carries isRepost and repostOfId either way.

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

Advanced: keep only jobs whose OUTPUT fields pass every rule. Each rule is {"field": "salaryMin", "op": "gte", "value": 120000}. Ops: includes, notIncludes (text contains, any case; for lists, any element), equals, notEquals, gt, gte, lt, lte (numbers). A field may be a dotted path such as recruiterProfile.rating. An unknown field or op fails the run up front instead of silently removing every job. Rules on fields that only come with the full description (e.g. companyRating, numApplicants, emails) switch 'Fetch full job description' on. Like the other post-filters, a removed job is never pushed or charged.

## `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.

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

Which copies of the job description each row carries. The default keeps the HTML (content) and plain text (contentText), as before. 'Markdown' returns contentMarkdown only (headings, bold and bullet lists kept), which is the smallest readable form for AI agents and LLM pipelines. 'All' adds contentMarkdown alongside the other two. Only applies when 'Fetch full job description' is on.

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

Cut the plain-text and Markdown description to this many characters, ending with '…'. The HTML copy is never cut (that would break its markup), so pair this with Description format 'Plain text only' or 'Markdown only' for the smallest rows. Each row then carries descriptionTruncated (true when its description was cut). 0 means no limit.

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

Return only the core fields an AI agent or spreadsheet needs: id, links, title, company, location, classification, work type and arrangement, salary, dates, applicant count, contact details, teaser, bullet points, the description in the format chosen above, the search that found the job, and the repost and incremental-mode fields when present. Turn off to get every field.

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

Drop fields that have no value on a row (null, empty text, empty list or empty object), including inside nested objects. false and 0 are kept. Rows get smaller, but different rows can then have different columns.

## `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.

## `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.

## `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. UPDATED means a real change to the job: any output field differs from the saved copy (title, description, salary, location, work type, classification, advertiser, company rating or review count, expiry or status, the listing date itself, ...), and changedFields names which. NOT compared, so they never cause UPDATED on their own: scrapedAt, the relative 'N ago' times (listingDateDisplay, postedTime), detailFetched, the repost flags (isRepost, repostOfId), the applicant numbers (numApplicants, applicantCountLabel, applicantVolumeLabel, resumePercentage, coverLetterPercentage), companyOpenJobs and salaryCurrency (both derived from fields that are compared); add more with Ignore fields below. If the full-description fetch fails for a job on one run, its description and company details are carried over from the saved copy instead of reading as a change. EXPIRED is only reported after a run that scanned every page of every search, so a capped, filtered or page-2-onward run never expires jobs. 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 (plus subclassification, the extra keyword/location lists, radius and any result filter you set) - 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.

## `ignoreFieldsForChanges` (type: `array`):

Optional. Field names to exclude from UPDATED change detection, in addition to the built-in handling (scrapedAt, the 'N ago' display times and the detail-fetch flag, the repost flags and the applicant numbers (numApplicants, applicantCountLabel, applicantVolumeLabel, resumePercentage, coverLetterPercentage, which grow while an ad is live) already never trigger a false UPDATED, and neither do companyOpenJobs, a link built from companyName, and salaryCurrency, a currency read from the pay text). The field stays in the output row either way - this only controls whether a change to it alone counts as a real change. Use a plain name for a top-level field (e.g. 'companyLogo'), or a dotted path to target one nested value inside a raw block without ignoring the whole block (e.g. 'companyProfileRaw.reviewsSummary.overallRating.value').

## `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
{
  "mode": "auto",
  "region": "AU",
  "keywords": "software engineer",
  "keywordsList": [
    "registered nurse",
    "midwife"
  ],
  "companyName": "Amplar Health",
  "location": "Sydney",
  "locationsList": [
    "Sydney",
    "Melbourne VIC"
  ],
  "radius": 10,
  "classification": [],
  "subclassification": [],
  "workType": [],
  "workArrangement": [],
  "salaryType": "annual",
  "salaryMin": 100000,
  "salaryMax": 200000,
  "daterange": 7,
  "sortmode": "ListedDate",
  "urls": [
    {
      "url": "https://au.seek.com/jobs-in-information-communication-technology/engineering-software/in-All-Sydney-NSW"
    },
    {
      "url": "https://au.seek.com/software-engineer-jobs/in-All-Sydney-NSW/full-time"
    },
    {
      "url": "https://nz.seek.com/accountant-jobs-in-accounting/in-All-Auckland"
    },
    {
      "url": "https://au.seek.com/jobs/in-All-Sydney-NSW"
    },
    {
      "url": "https://nz.seek.com/jobs/in-Wellington"
    },
    {
      "url": "https://au.seek.com/jobs?advertiserid=3490876"
    },
    {
      "url": "https://au.seek.com/jobs?where=All-Perth-WA"
    },
    {
      "url": "https://au.seek.com/software-engineer-jobs?page=2"
    },
    {
      "url": "https://au.seek.com/job/95066648"
    },
    {
      "url": "https://au.seek.com/jobs?jobId=95066648"
    },
    {
      "url": "https://www.seek.com.au/companies/seek-432306"
    },
    {
      "url": "https://www.seek.com.au/jobs/in-All-Sydney-NSW"
    },
    {
      "url": "https://seek.com.au/jobs/in-All-Adelaide-SA"
    },
    {
      "url": "https://m.seek.com.au/jobs/in-All-Hobart-TAS"
    },
    {
      "url": "https://www.seek.co.nz/jobs/in-Wellington"
    },
    {
      "url": "https://www.seek.com.au/jobs?jobId=95066648&utm_source=email&utm_campaign=jobalert"
    },
    {
      "url": "https://nz.seek.com/jobs-in-information-communication-technology/engineering-software/in-All-Auckland"
    },
    {
      "url": "https://www.seek.com.au/jobs-in-accounting/accounts-payable/in-All-Melbourne-VIC/full-time"
    },
    {
      "url": "https://www.seek.com.au/jobs/in-All-Melbourne-VIC/full-time/hybrid"
    },
    {
      "url": "https://nz.seek.com/jobs/in-Hutt-Central,-Wellington"
    },
    {
      "url": "https://www.seek.com.au/National-Civil-&-Foundations-Pty-Ltd-jobs"
    },
    {
      "url": "https://www.seek.com.au/Turner-&-Townsend-jobs/at-this-company"
    }
  ],
  "includeKeywords": [
    "python",
    "data"
  ],
  "excludeKeywords": [
    "senior",
    "unpaid"
  ],
  "keywordMatchFields": [
    "title"
  ],
  "fromDate": "2026-10-01",
  "toDate": "2026-10-05",
  "maxAgeMinutes": 60,
  "minApplicants": 10,
  "maxApplicants": 50,
  "requireContact": "off",
  "skipReposts": false,
  "customFilters": [
    {
      "field": "salaryMin",
      "op": "gte",
      "value": 120000
    },
    {
      "field": "workArrangementLabels",
      "op": "includes",
      "value": "Remote"
    }
  ],
  "includeFullDescription": true,
  "descriptionFormat": "html_text",
  "descriptionMaxLength": 2000,
  "compact": false,
  "excludeEmptyFields": false,
  "maxItems": 200,
  "maxTimeSec": 300,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": []
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "ignoreFieldsForChanges": [],
  "maxNotifyListings": 50
}
```

# Actor output Schema

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

Dataset items (one per job)

## `detail` (type: `string`):

No description

## `company` (type: `string`):

No description

## `salary` (type: `string`):

No description

## `applicants` (type: `string`):

No description

## `recruiter` (type: `string`):

No description

## `changes` (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 = {
    "mode": "auto",
    "urls": [
        {
            "url": "https://au.seek.com/jobs-in-information-communication-technology/engineering-software/in-All-Sydney-NSW"
        },
        {
            "url": "https://au.seek.com/software-engineer-jobs/in-All-Sydney-NSW/full-time"
        },
        {
            "url": "https://nz.seek.com/accountant-jobs-in-accounting/in-All-Auckland"
        },
        {
            "url": "https://au.seek.com/jobs/in-All-Sydney-NSW"
        },
        {
            "url": "https://nz.seek.com/jobs/in-Wellington"
        },
        {
            "url": "https://au.seek.com/jobs?advertiserid=3490876"
        },
        {
            "url": "https://au.seek.com/jobs?where=All-Perth-WA"
        },
        {
            "url": "https://au.seek.com/software-engineer-jobs?page=2"
        },
        {
            "url": "https://au.seek.com/job/95066648"
        },
        {
            "url": "https://au.seek.com/jobs?jobId=95066648"
        },
        {
            "url": "https://www.seek.com.au/companies/seek-432306"
        },
        {
            "url": "https://www.seek.com.au/jobs/in-All-Sydney-NSW"
        },
        {
            "url": "https://seek.com.au/jobs/in-All-Adelaide-SA"
        },
        {
            "url": "https://m.seek.com.au/jobs/in-All-Hobart-TAS"
        },
        {
            "url": "https://www.seek.co.nz/jobs/in-Wellington"
        },
        {
            "url": "https://www.seek.com.au/jobs?jobId=95066648&utm_source=email&utm_campaign=jobalert"
        },
        {
            "url": "https://nz.seek.com/jobs-in-information-communication-technology/engineering-software/in-All-Auckland"
        },
        {
            "url": "https://www.seek.com.au/jobs-in-accounting/accounts-payable/in-All-Melbourne-VIC/full-time"
        },
        {
            "url": "https://www.seek.com.au/jobs/in-All-Melbourne-VIC/full-time/hybrid"
        },
        {
            "url": "https://nz.seek.com/jobs/in-Hutt-Central,-Wellington"
        },
        {
            "url": "https://www.seek.com.au/National-Civil-&-Foundations-Pty-Ltd-jobs"
        },
        {
            "url": "https://www.seek.com.au/Turner-&-Townsend-jobs/at-this-company"
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": []
    },
    "ignoreFieldsForChanges": []
};

// 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 = {
    "mode": "auto",
    "urls": [
        { "url": "https://au.seek.com/jobs-in-information-communication-technology/engineering-software/in-All-Sydney-NSW" },
        { "url": "https://au.seek.com/software-engineer-jobs/in-All-Sydney-NSW/full-time" },
        { "url": "https://nz.seek.com/accountant-jobs-in-accounting/in-All-Auckland" },
        { "url": "https://au.seek.com/jobs/in-All-Sydney-NSW" },
        { "url": "https://nz.seek.com/jobs/in-Wellington" },
        { "url": "https://au.seek.com/jobs?advertiserid=3490876" },
        { "url": "https://au.seek.com/jobs?where=All-Perth-WA" },
        { "url": "https://au.seek.com/software-engineer-jobs?page=2" },
        { "url": "https://au.seek.com/job/95066648" },
        { "url": "https://au.seek.com/jobs?jobId=95066648" },
        { "url": "https://www.seek.com.au/companies/seek-432306" },
        { "url": "https://www.seek.com.au/jobs/in-All-Sydney-NSW" },
        { "url": "https://seek.com.au/jobs/in-All-Adelaide-SA" },
        { "url": "https://m.seek.com.au/jobs/in-All-Hobart-TAS" },
        { "url": "https://www.seek.co.nz/jobs/in-Wellington" },
        { "url": "https://www.seek.com.au/jobs?jobId=95066648&utm_source=email&utm_campaign=jobalert" },
        { "url": "https://nz.seek.com/jobs-in-information-communication-technology/engineering-software/in-All-Auckland" },
        { "url": "https://www.seek.com.au/jobs-in-accounting/accounts-payable/in-All-Melbourne-VIC/full-time" },
        { "url": "https://www.seek.com.au/jobs/in-All-Melbourne-VIC/full-time/hybrid" },
        { "url": "https://nz.seek.com/jobs/in-Hutt-Central,-Wellington" },
        { "url": "https://www.seek.com.au/National-Civil-&-Foundations-Pty-Ltd-jobs" },
        { "url": "https://www.seek.com.au/Turner-&-Townsend-jobs/at-this-company" },
    ],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": [],
    },
    "ignoreFieldsForChanges": [],
}

# 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 '{
  "mode": "auto",
  "urls": [
    {
      "url": "https://au.seek.com/jobs-in-information-communication-technology/engineering-software/in-All-Sydney-NSW"
    },
    {
      "url": "https://au.seek.com/software-engineer-jobs/in-All-Sydney-NSW/full-time"
    },
    {
      "url": "https://nz.seek.com/accountant-jobs-in-accounting/in-All-Auckland"
    },
    {
      "url": "https://au.seek.com/jobs/in-All-Sydney-NSW"
    },
    {
      "url": "https://nz.seek.com/jobs/in-Wellington"
    },
    {
      "url": "https://au.seek.com/jobs?advertiserid=3490876"
    },
    {
      "url": "https://au.seek.com/jobs?where=All-Perth-WA"
    },
    {
      "url": "https://au.seek.com/software-engineer-jobs?page=2"
    },
    {
      "url": "https://au.seek.com/job/95066648"
    },
    {
      "url": "https://au.seek.com/jobs?jobId=95066648"
    },
    {
      "url": "https://www.seek.com.au/companies/seek-432306"
    },
    {
      "url": "https://www.seek.com.au/jobs/in-All-Sydney-NSW"
    },
    {
      "url": "https://seek.com.au/jobs/in-All-Adelaide-SA"
    },
    {
      "url": "https://m.seek.com.au/jobs/in-All-Hobart-TAS"
    },
    {
      "url": "https://www.seek.co.nz/jobs/in-Wellington"
    },
    {
      "url": "https://www.seek.com.au/jobs?jobId=95066648&utm_source=email&utm_campaign=jobalert"
    },
    {
      "url": "https://nz.seek.com/jobs-in-information-communication-technology/engineering-software/in-All-Auckland"
    },
    {
      "url": "https://www.seek.com.au/jobs-in-accounting/accounts-payable/in-All-Melbourne-VIC/full-time"
    },
    {
      "url": "https://www.seek.com.au/jobs/in-All-Melbourne-VIC/full-time/hybrid"
    },
    {
      "url": "https://nz.seek.com/jobs/in-Hutt-Central,-Wellington"
    },
    {
      "url": "https://www.seek.com.au/National-Civil-&-Foundations-Pty-Ltd-jobs"
    },
    {
      "url": "https://www.seek.com.au/Turner-&-Townsend-jobs/at-this-company"
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": []
  },
  "ignoreFieldsForChanges": []
}' |
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/ZdobMSxohY6XxO57a/openapi.json
