# Seek Jobs Scraper (Australia & New Zealand) (`mina_safwat/seek-jobs-scraper`) Actor

Scrapes job ads from SEEK Australia and New Zealand. Paste any SEEK search link and every filter in it is kept, or paste job links. Gets title, company, location, salary range, work type and arrangement, classification, listing date and the full description.

- **URL**: https://apify.com/mina_safwat/seek-jobs-scraper.md
- **Developed by:** [Mina](https://apify.com/mina_safwat) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.50 / 1,000 jobs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

### What does Seek Jobs Scraper do?

**Seek Jobs Scraper** collects **job ads from SEEK**, the leading job board in **Australia** ([seek.com.au](https://www.seek.com.au)) and **New Zealand** ([seek.co.nz](https://www.seek.co.nz)). Search on SEEK as you normally would, paste the link, and get every job as a clean row: **title, company, suburb, area, state and postcode, classification, work type, on-site / hybrid / remote, the salary as advertised plus parsed minimum, maximum, period and currency, listing date, selling points and the full job description**.

**Every filter in your link is kept**: keywords, location and distance, classification and sub-classification, work type, work arrangement, pay range and pay type, listing date and sort order. Company job lists and single job ads work too.

Try it with the prefilled search: open the Actor, click **Start**, and 20 Sydney software engineer jobs are ready in a few seconds. Running on the Apify platform also gives you API access, scheduled runs, integrations (Google Sheets, Make, Zapier, Slack, webhooks) and run monitoring.

### Why scrape SEEK?

- **Salary benchmarking.** SEEK's pay text ("$80,000 – $90,000 per year + Super", "$45 p/h") is turned into numbers you can sort, chart and average, with the original text kept alongside.
- **Labour market research.** Track demand by classification, region and work arrangement across Australia and New Zealand.
- **Recruitment and sales leads.** See which companies are hiring, for what, and where.
- **Job aggregation.** Feed a niche job board, newsletter or internal tool with fresh, structured ads.
- **Monitoring.** Schedule a daily run on a newest-first search and keep only the job IDs you have not seen.

### How to scrape SEEK jobs

1. Open [seek.com.au](https://www.seek.com.au) or [seek.co.nz](https://www.seek.co.nz) and search: type the job title and location, then pick any filters (classification, work type, remote options, pay, listing time, sort order).
2. Copy the address from your browser's address bar, for example `https://www.seek.com.au/software-engineer-jobs/in-All-Sydney-NSW?daterange=7&worktype=242`.
3. Paste it into **SEEK search or job links**. Add as many links as you like, one per line; Australian and New Zealand links can be mixed.
4. Set **Max jobs per search link** and choose whether to include full descriptions.
5. Click **Start**, then download the results as JSON, CSV, Excel or HTML.

### Input

Everything is set on the Input tab. In JSON, the input looks like this:

```json
{
    "startUrls": [
        "https://www.seek.com.au/software-engineer-jobs/in-All-Sydney-NSW?daterange=7&worktype=242",
        "seek.co.nz/jobs-in-information-communication-technology/developers-programmers/in-All-Auckland",
        "https://www.seek.com.au/job/94673763"
    ],
    "maxJobsPerSearch": 100,
    "includeDescription": true
}
```

| Field | What it does |
|---|---|
| `startUrls` | SEEK links, one per line: a search results page, a company's job list (`…-jobs/at-this-company`), or a single job ad (`seek.com.au/job/12345678`, or just the number). `https://` is optional. API callers can also send `{"url": "…"}` objects. |
| `maxJobsPerSearch` | Stops after this many jobs from each search link. Default: 100. |
| `includeDescription` | Adds the full description as plain text and HTML. Default: on. |
| `proxyConfiguration` | Leave empty. SEEK answers the Actor directly; when SEEK refuses a request, or its limit on job lookups from one address is reached, the Actor switches to Apify's proxies on its own. Choosing a proxy sends every request through it, which makes big runs with descriptions slower. |

#### Which filters are read from the link?

| On SEEK | In the link | Example |
|---|---|---|
| Keywords | path or `keywords=` | `/data-analyst-jobs` |
| Location | path or `where=` | `/in-All-Brisbane-QLD`, `/in-Parramatta-NSW-2150` |
| Distance from the location | `distance=` | `distance=10` |
| Classification and sub-classification | path or `classification=` / `subclassification=` | `/jobs-in-healthcare-medical/nursing-aged-care` |
| Work type | path or `worktype=` | `/full-time`, `/contract-temp` |
| Remote options | path or `workarrangement=` | `/remote`, `/hybrid`, `/on-site` |
| Pay range and pay type | `salaryrange=` and `salarytype=` | `salaryrange=100000-&salarytype=annual` |
| Listing time | `daterange=` | `daterange=1` (today, since midnight Sydney time), `3`, `7`, `14` or `31` days |
| Sort order | `sortmode=` | `sortmode=ListedDate` (newest first) |
| One advertiser | `advertiserid=` or a company job list | `/Lindt-&-Sprungli-jobs/at-this-company` |

The page number in a link is ignored: every search starts from its first page.

### Output

Each job becomes one row. Here is a real one, with the description shortened:

```json
{
    "jobId": "95081016",
    "url": "https://au.seek.com/job/95081016",
    "title": "SOFTWARE ENGINEER",
    "company": "Partech, Inc",
    "advertiserId": "62025965",
    "advertiserName": "Partech, Inc.",
    "location": "Mona Vale, Sydney NSW",
    "suburb": "Mona Vale",
    "area": "Sydney",
    "state": "NSW",
    "postcode": "2103",
    "country": "AU",
    "classification": "Information & Communication Technology",
    "subClassification": "Engineering - Software",
    "workType": "Full time",
    "workArrangement": "On-site",
    "salary": "$80,000 – $90,000 per year + Super",
    "salaryMin": 80000,
    "salaryMax": 90000,
    "salaryPeriod": "year",
    "salaryCurrency": "AUD",
    "listedAt": "2026-10-06T04:15:12Z",
    "teaser": "Skilled Software Engineer to design, develop, and maintain software applications and systems.",
    "bulletPoints": [],
    "tags": [],
    "logoUrl": null,
    "isFeatured": false,
    "isExpired": false,
    "description": "About the role\n\nTASK Retail is seeking a skilled and motivated Software Engineer to join our team...",
    "descriptionHtml": "<p><strong>About the role</strong></p><p>TASK Retail is seeking a skilled and motivated Software Engineer...",
    "sourceUrl": "https://www.seek.com.au/software-engineer-jobs/in-All-Sydney-NSW?daterange=7&worktype=242",
    "scrapedAt": "2026-10-08T13:01:11Z"
}
```

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel. The Output tab has two views: **Jobs** (the main columns) and **Full details**.

### Data fields

| Field | Description |
|---|---|
| `jobId` | SEEK's job number. |
| `url` | Link to the job ad. |
| `title` | Job title. |
| `company` | The company name SEEK shows on the ad. |
| `advertiserId`, `advertiserName` | The advertiser's SEEK account number and registered name. Private advertisers have no number. |
| `location` | The location exactly as SEEK shows it, for example "Mona Vale, Sydney NSW". |
| `suburb` | The suburb, when the ad names one. |
| `area` | The city or region SEEK files the job under, such as "Sydney" or "Newcastle, Maitland & Hunter". |
| `state` | Australian state or territory code (NSW, VIC, QLD, WA, SA, TAS, ACT, NT). Empty for New Zealand. |
| `postcode` | The suburb's postcode, when the ad names a suburb in Australia. |
| `country` | `AU` or `NZ`. |
| `classification`, `subClassification` | SEEK's job category, such as "Healthcare & Medical" / "Nursing - Aged Care". |
| `workType` | Full time, Part time, Contract/Temp or Casual/Vacation. |
| `workArrangement` | On-site, Hybrid or Remote, when the ad says. |
| `salary` | The pay exactly as the advertiser wrote it. |
| `salaryMin`, `salaryMax` | The pay range read from that text. "Up to $X" fills only the maximum, "From $X" or "$X+" only the minimum, and a single figure fills both. Empty when the text states no amount (for example "Competitive salary"). |
| `salaryPeriod` | `hour`, `day`, `week`, `month` or `year`. Taken from the text; when the text gives none, amounts of 15,000 or more are read as yearly and amounts up to 200 as hourly. |
| `salaryCurrency` | `AUD` or `NZD` for a plain "$", or the currency the text names. |
| `listedAt` | When the ad was listed, in UTC. |
| `teaser` | The short summary shown in search results. |
| `bulletPoints` | The advertiser's selling points, when the ad has them. |
| `tags` | SEEK's badges on search results, such as "Immediate start", "Expiring soon" or "Be an early applicant". |
| `logoUrl` | The company logo, when the ad shows one. |
| `isFeatured` | `true` when SEEK showed the job as a featured ad in your search. Empty for single job links. |
| `isExpired` | `true` for a job link whose ad has closed. Search results only list open ads. |
| `description`, `descriptionHtml` | The full job description as plain text and as SEEK's HTML (when **Include full job descriptions** is on). |
| `sourceUrl` | The link you pasted that found this job. |
| `scrapedAt` | When the job was collected, in UTC. |

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

The Actor uses **pay-per-event** pricing: you pay a small fixed price for each job saved, and the exact price is on the **Pricing** tab. Full descriptions are included at no extra charge, because SEEK serves descriptions for a whole page of jobs in a single request.

You are never charged for links that return nothing: a search with no jobs, a removed job ad or a link that is not from SEEK is listed in the run's `FAILED_INPUTS` record instead. If you set a maximum cost for a run, the Actor stops as soon as it is reached.

### Tips for scraping SEEK

- **Let SEEK filter for you.** Narrow the search on SEEK before copying the link. The filters are applied by SEEK itself, so you only collect (and pay for) matching jobs.
- **Monitor new jobs.** Sort by date and choose "Listed in the last 3 days" (`sortmode=ListedDate&daterange=3`), schedule the Actor to run daily, and drop job IDs you already have. SEEK's "today" filter (`daterange=1`) starts at midnight Sydney time, so a daily run on it misses jobs listed the evening before.
- **Big searches.** SEEK lists at most 550 jobs for one search, however many match. Set **Max jobs per search link** above that, and when a search matches more, the Actor reads it as narrower searches (by classification, then sub-classification, then work type) to get past the limit. The first page comes in SEEK's own order; after that, jobs arrive grouped by category. When you ask for fewer jobs than match, they are shared out between categories in proportion to their size.
- **Each job is saved once per run**, even when several of your links find it.
- **Turn off descriptions** for smaller rows when titles, companies and pay are all you need.

### FAQ, disclaimers and support

**Which SEEK links work?** Search results pages from seek.com.au and seek.co.nz (including the newer au.seek.com and nz.seek.com addresses), company job lists, and single job ads. The SEEK home page, company profile pages and career-advice articles are not job lists; they are listed in `FAILED_INPUTS` with the reason.

**Why do some jobs have no salary numbers?** Many advertisers hide pay or write text such as "Competitive salary". The Actor only fills `salaryMin` and `salaryMax` when the text states an amount, and never estimates one; the original text is always in `salary`.

**What are featured jobs?** SEEK places up to two featured ads at the top of every results page. They match your search filters, so they are included, marked with `isFeatured: true`, and saved only once even when they appear again further down.

**What happens to links that return nothing?** They are not saved as rows, so you are not charged for them. Each is listed with its reason in the `FAILED_INPUTS` record of the run's key-value store, and the run's status message gives the counts. A run fails only when SEEK could not be reached for any of your links.

**Is it legal to scrape SEEK?** This Actor collects job ads that employers publish publicly so that people can find and apply for them. It does not log in, and it collects no personal data: the recruiter names and photos SEEK attaches to some ads are deliberately left out. Job ads can still contain contact details written by the advertiser, and their text is the advertiser's. You are responsible for making sure your use complies with SEEK's terms and with the laws that apply to you, such as privacy and copyright rules for republishing ads. If in doubt, ask a lawyer.

**Found a problem or need something custom?** Open an issue on the **Issues** tab and we will look into it. Custom scrapers and job data feeds are available on request.

# Actor input Schema

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

One link per line. Search on seek.com.au or seek.co.nz with any filters you like, then copy the address bar: keywords, location, classification and sub-classification, work type, remote/hybrid/on-site, pay range and type, listing date, distance and sort order are all kept. A company's job list (…-jobs/at-this-company) and single job ads (seek.com.au/job/12345678, or just the number) work too. Links without https:// are fine.

## `maxJobsPerSearch` (type: `integer`):

Stops after this many jobs from each search link. SEEK lists at most 550 jobs for one search; when you ask for more and the search matches more, the Actor reads it as narrower searches (by classification, then sub-classification, then work type) to get past that limit.

## `includeDescription` (type: `boolean`):

Adds each job's full description as plain text and HTML. It costs no extra: descriptions for a whole page of results come in one request. Turn it off for smaller rows.

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

Leave this empty. SEEK answers the Actor directly; when SEEK refuses a request, or its limit on job lookups from one address is reached, the Actor switches to Apify's proxies on its own. Choose a proxy here only to send every request through it, which makes big runs with descriptions slower.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.seek.com.au/software-engineer-jobs/in-All-Sydney-NSW?daterange=7&worktype=242"
  ],
  "maxJobsPerSearch": 20,
  "includeDescription": true,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

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

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        "https://www.seek.com.au/software-engineer-jobs/in-All-Sydney-NSW?daterange=7&worktype=242"
    ],
    "maxJobsPerSearch": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("mina_safwat/seek-jobs-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "startUrls": ["https://www.seek.com.au/software-engineer-jobs/in-All-Sydney-NSW?daterange=7&worktype=242"],
    "maxJobsPerSearch": 20,
}

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

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

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

```

## CLI example

```bash
echo '{
  "startUrls": [
    "https://www.seek.com.au/software-engineer-jobs/in-All-Sydney-NSW?daterange=7&worktype=242"
  ],
  "maxJobsPerSearch": 20
}' |
apify call mina_safwat/seek-jobs-scraper --silent --output-dataset

```

## MCP server setup

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