# SEEK Jobs Scraper 🇦🇺 (every live Australian job) (`tagadanar/seek-jobs-scraper`) Actor

Every live job on SEEK, Australia's biggest job board, in clean JSON. Search by title, location, classification, work type, arrangement and pay range. Get company, suburb, salary, work type, listing date and the apply link, with the full ad text on request. No login, no API key.

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

## Pricing

from $1.40 / 1,000 job scrapeds

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

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

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

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## SEEK Jobs Scraper (Australia)

Every live job on SEEK, Australia's biggest job board, as clean JSON you can drop straight into a spreadsheet, a CRM or a job board of your own. Search the way you would on the site itself: a job title, a suburb or state, one of SEEK's 30 classifications, full time or casual, on-site or remote, a pay range. Turn on descriptions and every row also carries the complete ad text.

No login. No cookies to paste. No API key. One flat price per job, platform usage included, so the number you see is the number you pay.

### What it costs

| Event | Price, all-in |
| --- | --- |
| Each job returned | $2.00 per 1,000 |
| Full ad text, when you ask for descriptions | $1.00 per 1,000 |
| Run start | $0.001 |

Platform usage (compute, proxies) is included in those prices — SEEK's public
search API answers without a proxy, and that saving is already in the number.
A search that matches nothing is never billed beyond the start fee, and a job
whose description cannot be fetched is not charged for the description.

### SEEK job data without the subscription

| | This actor | SEEK's own site | A job-data subscription |
| --- | --- | --- | --- |
| Get the data as JSON/CSV | yes, every run | copy and paste | yes |
| Full job description | optional extra per job | one page at a time | yes |
| Salary, work type, classification, work arrangement | yes, on every row | yes, on screen | varies |
| Filter by pay range and listing age | yes | yes | yes |
| Cost | a few cents per hundred jobs | free but manual | hundreds per month |
| Setup | paste a keyword, press start | none | contracts, onboarding |
| Login or API key | none | none | account required |

Most people land here after trying to keep a spreadsheet of Australian roles up to date by hand. That is the job this replaces.

### What you get

One record per job listing:

| Field | Description |
| --- | --- |
| `jobId` | SEEK's listing ID |
| `title` | Job title as advertised |
| `companyName` | Hiring company or recruiter |
| `companyUrl` | The company's SEEK profile, when it has one |
| `advertiserId` | SEEK's advertiser ID, stable across that advertiser's ads |
| `location` | Suburb and city as SEEK shows it, e.g. `Bondi Junction, Sydney NSW` |
| `locationRegion` | The state the listing rolls up to |
| `allLocations` | Every location on the listing, when it names more than one |
| `countryCode` | `AU` |
| `salary` | Pay exactly as the advertiser wrote it, e.g. `$43.19 to $55.40 per hour` |
| `workType` | Full time, Part time, Contract/Temp or Casual/Vacation |
| `workTypes` | All work types on the listing |
| `workArrangement` | Remote, Hybrid or On-site, when SEEK labels it |
| `classification` | One of SEEK's 30 categories, e.g. `Healthcare & Medical` |
| `subClassification` | The category below it, e.g. `Nursing - General Medical & Surgical` |
| `classificationId` | SEEK's numeric classification ID |
| `listedAt` | When it was listed, ISO timestamp |
| `listedDate` | The same date as `YYYY-MM-DD` |
| `listedAtDisplay` | Listing age in SEEK's own words, e.g. `4d ago` |
| `isFeatured` | Whether the advertiser paid to feature it |
| `teaser` | The one-line summary on the search card |
| `bulletPoints` | The selling points on the card |
| `roleId` | SEEK's normalised role, e.g. `registered-nurse` |
| `companyLogoUrl` | Company logo, when the ad has branding |
| `jobUrl` | Direct link to the listing |
| `searchKeyword` | Which of your keywords found this row |
| `searchLocation` | The location you searched |
| `source` | `seek.com.au` |
| `scrapedAt` | When the row was collected |

Switch on **Add the full job description** and every row also gets:

| Field | Description |
| --- | --- |
| `description` | The complete ad text, plain text with its list and paragraph breaks kept |
| `descriptionHtml` | The same text with the advertiser's original formatting |
| `expiresAt` | When the listing comes down |
| `isExpired` | Whether it has already closed |
| `isExternalApply` | Whether applications go to the company's own site instead of SEEK |

Descriptions are billed as a small extra, and only when a description actually comes back. A listing with nothing to return costs you nothing beyond the base row.

### Who uses this

- **Recruiters and staffing agencies.** Watch what your competitors are advertising, in which suburbs, at what pay, and spot the roles a client is filling without you.
- **Sales and lead-gen teams in Australia.** A company advertising fifteen new roles is a company with a budget. `companyName` plus `classification` and `location` is a buying signal you can act on the same day.
- **Job boards and aggregators.** A clean, deduplicated feed of Australian listings with descriptions, refreshed as often as you schedule it.
- **Salary and labour-market research.** `salary`, `workType`, `workArrangement` and `classification` across thousands of live ads is a much better read on the market than a survey from last year.
- **Job seekers and career coaches.** Set the listing age to Today, schedule it daily, and get every new posting in your field before the pile builds up.

### How the search works

The inputs are SEEK's own search boxes, in SEEK's own words.

**What** takes one or more keywords. Each is run as its own search and the results are merged and de-duplicated on the listing ID, so searching `registered nurse` and `enrolled nurse` together never gives you the same ad twice.

**Where** takes a place written the way SEEK writes it: `Sydney`, `Melbourne VIC`, `Bondi Junction NSW 2022`, `Western Australia`, or `All Australia`. If SEEK does not recognise the name, the run tells you so by name instead of quietly reporting zero jobs.

**Classifications**, **work type** and **work arrangement** are SEEK's own filters. Leave them empty for everything.

**Salary type** plus **paying at least / at most** filters on the pay range the advertiser entered, which is not always the same as the salary text shown on the ad. Some Australian advertisers enter a range but hide it, so a pay filter can exclude ads whose `salary` field looks empty.

**Listed in the last** is the new-postings filter. Set it to Today and schedule the actor daily to build a feed of nothing but fresh listings.

One thing worth knowing before you set a big **maximum jobs**: SEEK itself serves at most 550 results for any single search, no matter how many hits it reports. Past that it stops returning rows. To go wider, split the work: several keywords, or one classification per run, or state by state. The run status always tells you when a search hit that ceiling, so you never mistake it for "there were no more jobs".

### Input examples

Copy any of these into the input tab, or use the visual form.

**Nursing jobs in Sydney, with descriptions:**

```json
{
  "keywords": ["registered nurse"],
  "location": "Sydney",
  "includeDescriptions": true,
  "maxResults": 100
}
```

**Everything posted in Australian tech today, newest first, as a daily feed:**

```json
{
  "classifications": ["information-communication-technology"],
  "location": "All Australia",
  "postedSince": "1",
  "sortBy": "date",
  "maxResults": 300
}
```

**Remote and hybrid roles paying over $120k a year:**

```json
{
  "keywords": ["product manager", "project manager"],
  "location": "All Australia",
  "workArrangement": ["remote", "hybrid"],
  "workTypes": ["full-time"],
  "salaryType": "annual",
  "minSalary": 120000,
  "maxResults": 200
}
```

**Trades in Perth, part time or casual:**

```json
{
  "classifications": ["trades-services"],
  "location": "Perth WA",
  "workTypes": ["part-time", "casual-vacation"],
  "maxResults": 150
}
```

### Output sample

```json
{
  "jobId": "94168228",
  "title": "Registered Nurse",
  "companyName": "Mosh",
  "companyUrl": "https://au.seek.com/companies/mosh-167590669593178",
  "advertiserId": "47362215",
  "location": "Sydney NSW",
  "locationRegion": "New South Wales NSW",
  "allLocations": ["Sydney NSW"],
  "countryCode": "AU",
  "salary": null,
  "workType": "Full time",
  "workTypes": ["Full time"],
  "workArrangement": "Remote",
  "classification": "Healthcare & Medical",
  "subClassification": "Nursing - General Medical & Surgical",
  "classificationId": "1211",
  "listedAt": "2026-08-24T07:06:19.501Z",
  "listedDate": "2026-08-24",
  "listedAtDisplay": "1d ago",
  "isFeatured": false,
  "teaser": "Join Mosh & Moshy as a full-time Telehealth Registered Nurse.",
  "bulletPoints": [
    "Impactful and rewarding role helping improve mens and womens health",
    "Flexible, fully remote role",
    "Join a supportive, multidisciplinary team"
  ],
  "roleId": "registered-nurse",
  "companyLogoUrl": null,
  "jobUrl": "https://www.seek.com.au/job/94168228",
  "description": "G'day, we're Mosh & Moshy...",
  "expiresAt": "2026-09-23T13:59:59.999Z",
  "isExpired": false,
  "isExternalApply": true,
  "searchKeyword": "registered nurse",
  "searchLocation": "Sydney",
  "source": "seek.com.au",
  "scrapedAt": "2026-08-25T22:01:57.265Z"
}
```

### Other job boards in this collection

Same output shape, so you can run several boards into one dataset and keep one mapping:

- [LinkedIn Jobs Scraper](https://apify.com/tagadanar/linkedin-jobs-scraper): keyword and location search across LinkedIn, no login.
- [LinkedIn Company Jobs Scraper](https://apify.com/tagadanar/linkedin-company-jobs): every open role at one named company.
- [Naukri Scraper](https://apify.com/tagadanar/naukri-scraper): India's largest job board, with salary, experience and skills.
- [Wellfound Jobs Scraper](https://apify.com/tagadanar/wellfound-scraper): startup roles with salary and equity ranges.
- [ATS Jobs Aggregator](https://apify.com/tagadanar/ats-jobs-aggregator): jobs straight from employers' own Greenhouse, Lever and Workable boards.

### Questions people ask

**Do I need a SEEK account or an API key?**
No. This reads public listings the same way an ordinary visitor's browser does, with no sign-in of any kind.

**How many jobs can I get in one run?**
As many as you set, but SEEK serves at most 550 results per individual search. Several keywords, or one classification per run, or one state per run, all multiply that. The run status says when a search hit the ceiling.

**Can I get the full job description?**
Yes, switch on **Add the full job description**. You get both a plain-text version that keeps the ad's list and paragraph structure, and the original HTML. It costs a small extra per job, charged only when a description is actually returned.

**Does it cover New Zealand, or SEEK's Asian sites?**
This one covers seek.com.au, the Australian site. New Zealand and the Asian boards run on separate SEEK sites.

**Why is `salary` empty on some rows?**
Because the advertiser chose not to publish a pay figure, which is common in Australia. The pay filter still works on those ads when the advertiser entered a range privately, which is why a salary filter sometimes returns rows whose `salary` field is empty.

**Can I run it as a daily alert for new jobs?**
Yes. Set **Listed in the last** to Today, schedule the actor daily, and you get only that day's listings. Add an integration to push them into Slack, a Google Sheet or your own webhook.

**How do I search a whole state or all of Australia?**
Put `Western Australia`, `Queensland` or `All Australia` in **Where**. State and national searches hit the 550-per-search ceiling quickly, so pair them with a classification or a specific keyword.

**Is scraping SEEK legal?**
This collects public job advertisements: company, role, location, pay and the ad text. It collects nothing about individual people, no applicants and no profiles. Use the data in line with SEEK's terms and your own local rules.

**What happens if SEEK blocks the run?**
The run stops fetching after two refused requests rather than spending your money retrying against a block, keeps everything it already collected, and says exactly what happened in the run status.

***

SEEK scraper, SEEK jobs API, Australian jobs data, seek.com.au scraper, Australia job listings, job board scraper, recruitment data Australia, salary data Australia, remote jobs Australia, nursing jobs, trades jobs, IT jobs Australia, job feed, hiring signals, ATS feed, jobs JSON export.

# Actor input Schema

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

One entry per search, exactly what you would type in SEEK's "What" box: a job title, a skill, or a company name. Each entry runs as its own search and the results are merged and de-duplicated. Leave empty to browse a location or a classification instead.

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

SEEK's "Where" box: a city (<code>Sydney</code>), a suburb with its postcode (<code>Bondi Junction NSW 2022</code>), a state (<code>Western Australia</code>), or <code>All Australia</code>. Write it the way SEEK writes it; a name SEEK does not know returns nothing and the run says so.

## `classifications` (type: `array`):

SEEK's own job categories. Leave empty for every category.

## `workTypes` (type: `array`):

Leave empty for every work type.

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

On-site, hybrid or remote, as SEEK labels it on the listing. Leave empty for all of them.

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

Pick Annual or Hourly to switch on the pay range below. SEEK matches the range against the pay the advertiser entered, which is not always the same as the salary text shown on the ad.

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

Lower end of the pay range, in AUD, matching the salary type above (for example 120000 per year, or 45 per hour). Ignored unless a salary type is picked.

## `maxSalary` (type: `integer`):

Upper end of the pay range, in AUD. Leave empty for no upper limit. Ignored unless a salary type is picked.

## `postedSince` (type: `string`):

Only jobs listed recently. Set it to Today and schedule this actor daily to get a feed of new Australian postings and nothing else.

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

Relevance is SEEK's default. Choose Newest first when you cap the results and want the most recent listings rather than the best-matching ones.

## `includeDescriptions` (type: `boolean`):

Open every listing to also collect its complete description (plain text and original HTML), the advertiser, the listing's expiry date and whether applications go to an external site. Slower, and billed as a small extra only for listings where a description actually comes back.

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

Stop after this many jobs across all searches. You are only charged for jobs actually delivered. SEEK itself serves at most 550 results per search, so ask for more than that by splitting the search across several keywords, locations or classifications.

## Actor input object example

```json
{
  "keywords": [
    "registered nurse"
  ],
  "location": "Sydney",
  "salaryType": "any",
  "postedSince": "any",
  "sortBy": "relevance",
  "includeDescriptions": true,
  "maxResults": 20
}
```

# Actor output Schema

## `jobs` (type: `string`):

One item per job in the default dataset.

# 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": [
        "registered nurse"
    ],
    "location": "Sydney",
    "includeDescriptions": true,
    "maxResults": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("tagadanar/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": ["registered nurse"],
    "location": "Sydney",
    "includeDescriptions": True,
    "maxResults": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("tagadanar/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": [
    "registered nurse"
  ],
  "location": "Sydney",
  "includeDescriptions": true,
  "maxResults": 20
}' |
apify call tagadanar/seek-jobs-scraper --silent --output-dataset

```

## MCP server setup

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