# SEEK Job Scraper: Australia & NZ Jobs with Full Descriptions (`datagleaner/seek-jobs-scraper`) Actor

SEEK job scraper for Australia and New Zealand: search by keyword, location, role family, work type, remote, salary and date and get salary, company, full description and applicant count. No login. $1.50 per 1,000 jobs.

- **URL**: https://apify.com/datagleaner/seek-jobs-scraper.md
- **Developed by:** [Data Gleaner](https://apify.com/datagleaner) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 2 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

## SEEK Job Scraper: Australia and New Zealand jobs with salary and full descriptions

**Scrape SEEK jobs from seek.com.au and seek.co.nz by keyword, location, role family, work type, salary and date, and get each ad with salary, company, full description and applicant count as JSON or CSV.** No SEEK account, no API key, no browser.

**Price: $1.50 per 1,000 jobs** ($0.0015 per job, full description, applicant count and recruiter contacts included). 100 jobs cost 15 cents.

### Why use this one

- **Filters run on SEEK itself.** Role family (`classification`, `subClassification`), work type, remote/hybrid/on-site, salary range and date window are applied by SEEK's own search, so results match what you see on the site. You can also paste a SEEK search URL.
- **Full ad in one pass.** Description (HTML and text), parsed `salaryMin`/`salaryMax`, advertiser, suburb/city/state/postcode, screening questions and applicant count, at the same price as the short version.
- **Pay only for jobs you keep.** `includeKeywords` and `excludeKeywords` drop jobs before they are charged; `maxJobsPerSearch` caps each search.
- **Checked from Apify's own servers.** The sample below comes from a run on the Apify platform, not from a home connection.
- **Honest limit:** SEEK serves about 500 results per search. To go wider, use several `locations` or `subClassification` values or run daily with a "last 24 hours" filter.

### Minimal input

```json
{"keywords": ["registered nurse"], "country": "AU", "location": "All Sydney NSW", "dateRange": "7", "maxJobsPerSearch": 100}
```

### Sample output row (real platform run, long text shortened)

```json
{
  "jobId": "95148315",
  "url": "https://www.seek.com.au/job/95148315",
  "title": "Registered Nurse - Dermatology & Cosmetic Clinic",
  "companyName": "PT Health Care",
  "advertiserId": "62860350",
  "advertiserName": "PT Health Care",
  "employerId": "3354031",
  "location": "Bondi Junction, Sydney NSW",
  "suburb": "Bondi Junction",
  "city": "Sydney",
  "state": "NSW",
  "postcode": "2022",
  "countryCode": "AU",
  "classification": "Healthcare & Medical",
  "classificationId": "1211",
  "subClassification": "Nursing - General Medical & Surgical",
  "subClassificationId": "6342",
  "workType": "Full time",
  "workTypes": [
    "Full time"
  ],
  "workArrangement": "onSite",
  "workArrangements": [
    "onSite"
  ],
  "salaryLabel": "$85,000 – $95,000 per year + performance bonuses",
  "salaryMin": 85000,
  "salaryMax": 95000,
  "salaryPeriod": "year",
  "currency": "AUD",
  "listedAt": "2026-10-08T11:02:27Z",
  "expiresAt": "2026-11-07T12:59:59.999Z",
  "isExpired": false,
  "roleId": "Dermatology-Registered-Nurse",
  "jobAdType": "SPONSORED",
  "bulletPoints": [
    "Be part of a company that’s transforming healthcare",
    "Work with a supportive and forward-thinking team in a modern workspace",
    "Make an impact on patients’ lives while advancing your career opportunities"
  ],
  "teaser": "Join our friendly Bondi Junction team. Grow your skills in dermatology, skin cancer & cosmetic medicine with t...",
  "isFeatured": true,
  "isPromoted": true,
  "logoUrl": "https://bx-branding-gateway.cloud.seek.com.au/8568abca-3f50-4e11-a3db-2fa4fcfd9dba.1/jdpLogo",
  "advertiserVerified": true,
  "applicantCount": 29,
  "applicantVolumeLabel": "Medium application volume",
  "applicantsWithResumePercent": 100,
  "applicantsWithCoverLetterPercent": 66,
  "descriptionHtml": "<h2>Are you passionate about delivering <em>exceptional patient care</em> utilising the latest medical advance...",
  "descriptionText": "Are you passionate about delivering exceptional patient care utilising the latest medical advances in skin hea...",
  "applicationQuestions": [
    "Which of the following statements best describes your right to work in Australia?",
    "How many years' experience do you have as a Dermatology Registered Nurse?",
    "How much notice are you required to give your current employer?"
  ],
  "extractedEmails": [],
  "extractedPhones": [],
  "extractedUrls": [],
  "searchKeywords": "registered nurse",
  "searchLocation": "All Sydney NSW",
  "country": "AU",
  "position": 1,
  "scrapedAt": "2026-10-11T06:37:28+00:00",
  "input": "registered nurse | All Sydney NSW | AU"
}
```

Fields SEEK does not publish for an ad (salary on many ads) are `null`.

### What you get

- Job title, company, advertiser, location split into suburb, city, state and postcode
- Category and sub-category, work type (full time, part time, contract, casual), on-site/hybrid/remote
- The salary text as advertised, plus `salaryMin`, `salaryMax` and `salaryPeriod` when the text is unambiguous
- Listing date and expiry date, bullet points and teaser
- Full job description as HTML and plain text, and the employer's screening questions
- Applicant count (`applicantCount`, `applicantVolumeLabel`) and the share of applicants who attached a resume or cover letter (`applicantsWithResumePercent`, `applicantsWithCoverLetterPercent`), when SEEK shows them
- Emails, phone numbers and links written into the ad (`extractedEmails`, `extractedPhones`, `extractedUrls`)
- `roleId`, `jobAdType` and the SEEK sub-category
- Duplicates removed across all your searches
- About 100 jobs with full descriptions in 25 seconds at the default pacing

### Use cases

- Labour-market and salary research by role, city or industry
- Job boards and aggregators that need fresh Australian and New Zealand listings
- Recruiters and sales teams tracking which companies are hiring for which roles
- Monitoring demand for skills over time (schedule the Actor daily with a "last 24 hours" filter)
- Feeding job data to AI agents and analytics

### Input

```json
{
  "keywords": ["nurse", "data analyst"],
  "country": "AU",
  "location": "Sydney NSW",
  "workType": ["fullTime"],
  "dateRange": "7",
  "maxJobsPerSearch": 250,
  "includeDetails": true
}
```

| Field | Meaning |
|---|---|
| `keywords` | One search per keyword. Empty with no `startUrls`: runs a small example, 5 "software engineer" jobs. |
| `country`, `location` | `AU` or `NZ`; a place written as SEEK writes it ("All Sydney NSW", "Melbourne VIC 3000", "Auckland", "Remote"). Default: whole country. |
| `locations` | Several places in one run: one search per keyword and location. Overrides `location` when set, e.g. `["Sydney NSW", "Melbourne VIC", "Brisbane QLD"]`. |
| `startUrls` | SEEK search URLs. Keyword, location, category, work type, remote, date range and sort are read from the URL. |
| `workType`, `workArrangement`, `classification`, `subClassification`, `dateRange`, `salaryMin`/`salaryMax`/`salaryType`, `sortBy` | Filters, applied by SEEK. The salary filter is SEEK's own and also keeps ads that show no salary. |
| `maxJobsPerSearch` | Cost cap per keyword or URL, default 100, maximum 500. |
| `includeKeywords`, `excludeKeywords` | Case-insensitive match on title, company, teaser and description. A job is kept when it matches any `includeKeywords` term and no `excludeKeywords` term; dropped jobs are not charged. The description is matched only when `includeDetails` is on. |
| `includeDetails` | Full description, expiry date, screening questions, applicant insights and extracted contacts (default on, same price off; off is faster). |
| `descriptionFormat` | `both` (default), `text` or `html`. `text` gives smaller items for AI agents. |
| `excludeEmptyFields` | Default off. When on, null and empty values are omitted from each item. |
| `requestDelaySeconds`, `maxConcurrency`, `proxyConfiguration` | Pacing and optional Apify Proxy. |

### Output

```json
{
  "jobId": "95047618",
  "url": "https://www.seek.com.au/job/95047618",
  "title": "Registered Nurse, Sleep Disorders Unit",
  "companyName": "Example Hospital Group",
  "advertiserId": "12345678",
  "advertiserName": "Example Hospital Group",
  "location": "Kogarah, Sydney NSW",
  "suburb": "Kogarah",
  "city": "Sydney",
  "state": "NSW",
  "postcode": "2217",
  "countryCode": "AU",
  "classification": "Healthcare & Medical",
  "subClassification": "Nursing - General Medical & Surgical",
  "workType": "Part time",
  "workArrangement": "onSite",
  "workArrangements": ["onSite"],
  "salaryLabel": "$45 – $50 per hour",
  "salaryMin": 45,
  "salaryMax": 50,
  "salaryPeriod": "hour",
  "currency": "AUD",
  "listedAt": "2026-10-08T23:07:29Z",
  "expiresAt": "2026-11-08T12:59:59.999Z",
  "bulletPoints": ["Flexible roster", "Career growth"],
  "teaser": "Part-time role with career growth.",
  "isFeatured": true,
  "isPromoted": true,
  "descriptionHtml": "<p><strong>About the role</strong></p>...",
  "descriptionText": "About the role\n...",
  "applicationQuestions": ["How many years' experience do you have as a nurse?"],
  "applicantCount": 3,
  "applicantVolumeLabel": "Low application volume",
  "applicantsWithResumePercent": 90,
  "applicantsWithCoverLetterPercent": 40,
  "extractedEmails": ["recruiter@example.com"],
  "extractedPhones": ["02 9123 4567"],
  "extractedUrls": ["https://example.com/careers"],
  "roleId": "registered-nurse",
  "jobAdType": null,
  "searchKeywords": "nurse",
  "searchLocation": "Sydney NSW",
  "country": "AU",
  "position": 1,
  "scrapedAt": "2026-10-09T05:00:00+00:00",
  "input": "nurse | Sydney NSW | AU"
}
```

`workArrangement` is `onSite`, `hybrid` or `remote`, the same words as the input filter; `workArrangements` lists every arrangement the ad gives. Applicant, description and contact fields are filled only when `includeDetails` is on and SEEK returns the details. The example is illustrative. Fields SEEK does not publish for a job (for example salary on many ads, or the company name on private advertisers) are `null`. `salaryMin`/`salaryMax` are filled only when the text holds exactly one amount or range ("Competitive" or "$30/hour or $60,000/year" give null).

### Pricing

Pay per result: **$0.0015 per job** ($1.50 per 1,000), full description included. Example: 5 keywords x 100 jobs = 500 jobs = $0.75, the same as one full 500-job search. You are charged only for jobs returned, and a run stops cleanly when your maximum charge is reached.

### Limits

- SEEK serves at most about **500 results per search** (5 pages of 100). To collect more, use one run with several `locations` or `subClassification` values, or split by category, work type or date range, or run daily with "last 24 hours".
- Jobs are deduplicated per run; ads removed from SEEK before the run are not returned.
- A SEEK location it does not recognise returns no jobs.
- If a description cannot be fetched, the job is still returned with `descriptionHtml: null`; the run log reports how many.

### Use with Python

```python
## pip install apify-client
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("datagleaner/seek-jobs-scraper").call(run_input={
    "keywords": ["data analyst"],
    "country": "AU",
    "location": "All Sydney NSW",
    "maxJobsPerSearch": 10,
})
if run is None:
    raise SystemExit("The Actor run did not return.")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item["title"], "|", item["companyName"], "|", item["salaryLabel"])
```

10 jobs cost 1.5 cents.

### Use with JavaScript / Node.js

```js
// npm install apify-client
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('datagleaner/seek-jobs-scraper').call({
    keywords: ['registered nurse'],
    country: 'NZ',
    location: 'Auckland',
    maxJobsPerSearch: 10,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const job of items) console.log(job.title, '|', job.companyName, '|', job.location);
```

### Use it from n8n, Make, Zapier or an AI agent

Actor ID: `datagleaner/seek-jobs-scraper`

Minimal input:

```
{"keywords": ["data analyst"], "country": "AU", "maxJobsPerSearch": 10}
```

Each tool below runs this Actor with your own Apify API token.

- **n8n:** add the **Apify** node (`@apify/n8n-nodes-apify`). On n8n Cloud you install it from the community node registry. Choose **Run an Actor and get dataset**, set Actor to `datagleaner/seek-jobs-scraper` and paste the input above.
- **Make:** use the Apify app's **Run an Actor** module, then **Get Dataset Items** to read the results. **Watch Actor Runs** can trigger a scenario when a run finishes.
- **Zapier:** use the Apify action **Run Actor**, then the search **Fetch dataset items**. The trigger **Finished Actor run** starts a Zap when a run ends.
- **AI agents (MCP):** connect to `https://mcp.apify.com?tools=datagleaner/seek-jobs-scraper`. The Actor then shows up as the tool `datagleaner--seek-jobs-scraper`. In Claude Code:

  ```
  claude mcp add --transport http apify "https://mcp.apify.com?tools=datagleaner/seek-jobs-scraper"
  ```

  Then run `/mcp` to sign in to Apify in your browser. Example prompt: "Find data analyst jobs in Melbourne posted on SEEK in the last 7 days, at most 50, and give me a table of title, company, salary and suburb, plus the three most common skills in the descriptions."
- **LangChain (Python):**

```python
## pip install langchain-apify, then set APIFY_TOKEN in your environment
import json
from langchain_apify import ApifyActorsTool
tool = ApifyActorsTool("datagleaner/seek-jobs-scraper")
result = tool.invoke({"run_input": json.loads('{"keywords": ["data analyst"], "country": "AU", "maxJobsPerSearch": 10}')})
```

### FAQ

**Do I need a SEEK API key or account?** No. This Actor works without a SEEK account or API key: it reads the same public search data SEEK's website uses. You only need an Apify account.

**How much does it cost to scrape SEEK?** $1.50 per 1,000 jobs, full descriptions included. You are charged only for jobs returned, and `maxJobsPerSearch` caps each search.

**Does it work for SEEK New Zealand?** Yes. Set `country` to `NZ` to search seek.co.nz, or paste a seek.co.nz search URL in `startUrls`.

**How do I get more than 500 jobs?** SEEK serves about 500 results per search. Put several places in `locations`, narrow with `subClassification`, or split by category, work type or date range, or schedule a daily run with "last 24 hours".

**Can I use a SEEK search URL?** Yes. Put it in `startUrls`, for example `https://www.seek.com.au/software-engineer-jobs/in-All-Sydney-NSW`. Unrecognised parts of a URL are skipped with a warning in the log.

**Can I get applicant counts?** Yes, with `includeDetails` on: `applicantCount` and `applicantVolumeLabel`, plus the resume and cover-letter percentages, when SEEK shows them for the ad. Apply links are not included; the job `url` opens the ad.

### Responsible use

This Actor collects publicly available job advertisements. You are responsible for using the data lawfully, including any personal data it may contain (for example recruiter names in a description) under the privacy law that applies to you, and for respecting SEEK's terms. Keep request volumes reasonable.

# Actor input Schema

## `keywords` (type: `array`):

Job titles or skills to search for, one search per keyword, for example nurse or data analyst. If you give neither keywords nor start URLs, a small example run (5 jobs for 'software engineer') is returned.

## `country` (type: `string`):

Which SEEK site to search: Australia (seek.com.au) or New Zealand (seek.co.nz).

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

A place as SEEK writes it, for example All Sydney NSW, Melbourne VIC 3000, Brisbane QLD, Auckland or Remote. Default is the whole country. A place SEEK does not know returns no jobs.

## `locations` (type: `array`):

One search per keyword and location. Overrides Location when set, e.g. Sydney NSW, Melbourne VIC, Brisbane QLD.

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

Search result URLs copied from seek.com.au or seek.co.nz, for example https://www.seek.com.au/software-engineer-jobs/in-All-Sydney-NSW. Keyword, location, category and the filters in the URL are used; the filter fields below are ignored for these.

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

Upper bound on jobs returned for each keyword or URL. Each returned job is billed, so this is also your cost cap. SEEK serves at most about 500 results per search; split by location, category or date range to reach more.

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

Fetch the full job description (HTML and plain text), expiry date and screening questions for each job. Same price either way; turn it off for a faster run.

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

Case-insensitive match on title, company, teaser and description. Jobs that do not match are dropped and not charged.

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

Same fields. Jobs that match are dropped and not charged.

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

Text only gives smaller items for AI agents.

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

Omit null and empty values from each item.

## `onlyNew` (type: `boolean`):

For scheduled monitoring: remember the jobs already returned for this search and return only jobs not seen before. Seen jobs are skipped before their details are fetched and are not charged. The first run returns everything.

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

Name of the memory used by 'Only new jobs'. Leave empty to use one memory per distinct search. Reuse the same name to share memory between runs with different settings.

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

Only these work types. Empty means all.

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

Only on-site, hybrid or remote jobs. Empty means all.

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

Only these SEEK job categories. Empty means all.

## `subClassification` (type: `array`):

Only these SEEK sub-categories, for example Nursing - Aged Care. Narrower searches reach past SEEK's limit of about 500 results per search. Empty means all.

## `dateRange` (type: `string`):

Only jobs listed in the last N days.

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

Lower salary bound for SEEK's salary filter; needs Salary type. SEEK's filter also keeps ads that show no salary.

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

Upper salary bound for SEEK's salary filter; needs Salary type.

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

Whether the salary bounds are per year, month or hour.

## `sortBy` (type: `string`):

Relevance to the keyword, or newest first.

## `requestDelaySeconds` (type: `number`):

Base pause between requests; the actual pause is randomised up to 1.5x. Raise it if SEEK throttles you.

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

How many job description requests run at once.

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

Optional. Works without a proxy; enable Apify Proxy if SEEK blocks your IP.

## Actor input object example

```json
{
  "keywords": [
    "software engineer"
  ],
  "country": "AU",
  "location": "All Australia",
  "maxJobsPerSearch": 100,
  "includeDetails": true,
  "descriptionFormat": "both",
  "excludeEmptyFields": false,
  "onlyNew": false,
  "dateRange": "",
  "salaryType": "annual",
  "sortBy": "relevance",
  "requestDelaySeconds": 0.5,
  "maxConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (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 = {
    "keywords": [
        "software engineer"
    ],
    "location": "All Australia",
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("datagleaner/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 = {
    "keywords": ["software engineer"],
    "location": "All Australia",
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("datagleaner/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 '{
  "keywords": [
    "software engineer"
  ],
  "location": "All Australia",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call datagleaner/seek-jobs-scraper --silent --output-dataset

```

## MCP server setup

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