# SEEK Scraper — Jobs, Salaries & Companies (AU/NZ) (`tortuga/seek-scraper`) Actor

Returns SEEK.com.au and SEEK.co.nz jobs by keyword, location, filters or URL: title, company, suburb, classification, salary text and range, listing date; optional full description and company rating.

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

## Pricing

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

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 — Jobs, Salaries & Companies (AU/NZ)

Scrape job ads from **SEEK**, the largest job site in Australia (seek.com.au) and New Zealand (seek.co.nz), by
keyword and location, with SEEK's own filters (classification, work type, work arrangement, salary range, date
listed), or from any SEEK search URL. For every job you get the title, company and advertiser, location split into
suburb / region / state / postcode, classification and sub-classification, work type, on-site / hybrid / remote,
the salary text **and** a parsed min / max / period, the listing date, teaser, bullet points and logo. Optionally it
also returns the **full job description**, the screening questions and the **company rating** with review count,
industry, size and website.

No SEEK account, no cookies, no browser. Fast: 100 jobs per request. Export to JSON, CSV, Excel or use the API.

### What data does the SEEK Scraper return?

| Field | Example | Notes |
|---|---|---|
| `jobId`, `url` | `94604943`, `https://www.seek.com.au/job/94604943` | |
| `title` | `Software Developer` | |
| `company`, `advertiserName`, `advertiserId` | `Francom Group`, `Francom Group`, `47019260` | for agency ads the advertiser is the recruitment agency |
| `companyProfileUrl` | `https://au.seek.com/companies/francom-group-175428435415234` | when the employer has a SEEK company profile |
| `recruiterName` | `Kiara Beesley` | recruiter shown on agency ads, when SEEK shows one |
| `location`, `suburb`, `region`, `state`, `postcode`, `countryCode` | `Parramatta, Sydney NSW`, `Parramatta`, `Sydney`, `NSW`, `2150`, `AU` | NZ ads have no state / postcode |
| `classification`, `subClassification` (+ `...Id`) | `Information & Communication Technology`, `Developers/Programmers` | |
| `workType` | `Full time` | Full time, Part time, Contract/Temp, Casual/Vacation |
| `workArrangement`, `isRemote` | `Hybrid`, `false` | On-site, Hybrid, Remote |
| `salaryText` | `$120k - $180k + Super` | exactly as the advertiser wrote it; many ads show none |
| `salaryMin`, `salaryMax`, `salaryPeriod`, `salaryCurrency` | `120000`, `180000`, `year`, `AUD` | parsed from the text: hour, day, week, fortnight, month, year |
| `listedAt`, `listedAgo` | `2026-09-14T02:25:42Z`, `25d ago` | |
| `teaser`, `bulletPoints` | `Join Francom as a Software Developer...`, `["Full-Time", ...]` | |
| `logoUrl`, `badges`, `isFeatured`, `roleId` | `["Expiring soon"]`, `true`, `software-developer` | badges: Expiring soon, Be an early applicant, Immediate start, Urgent |
| `searchKeyword`, `searchLocation`, `searchUrl`, `site`, `scrapedAt`, `detailsFetched` | | where and when the job was found |
| `description`, `descriptionHtml` | `About Francom ...` | with **Include full job description** |
| `applicationQuestions` | `["How many years' experience do you have as a software developer?", ...]` | employer's screening questions, with details |
| `area`, `expiresAt`, `status`, `isExpired` | `Parramatta & Western Suburbs`, `2026-10-14T01:25:00.000Z`, `Active` | with details |
| `companyRating`, `companyReviewCount` | `3.4`, `24` | SEEK company reviews, with details, when the company has them |
| `companyIndustry`, `companySize`, `companyWebsite`, `companyOverview`, `companyPerks` | `Business Support Services`, `101-1,000 employees` | with details, from the SEEK company profile |
| `isVerifiedAdvertiser`, `isPrivateAdvertiser`, `advertiserRegisteredAt`, `applyOnExternalSite`, `applicationRestriction` | | with details |

### How to scrape SEEK jobs by keyword and location

1. Enter one or more **Keywords** (job title, skill or company) and a **Location** such as `All Sydney NSW`,
   `Melbourne`, `Brisbane QLD 4000` or `Auckland`, and pick the **Country** (Australia or New Zealand).
2. Optionally set filters: classification, work type, work arrangement (on-site / hybrid / remote), minimum and
   maximum salary (annual, monthly or hourly), listed in the last 1-31 days, sort by date.
3. Set **Max jobs** and run.

```json
{
  "keywords": ["data analyst", "business analyst"],
  "location": "All Melbourne VIC",
  "country": "AU",
  "workArrangements": ["2", "3"],
  "salaryMin": 100000,
  "salaryType": "annual",
  "datePosted": "7",
  "maxItems": 500
}
```

You can also paste SEEK URLs into **Start URLs**: search pages with any filters you set on the site (from
seek.com.au, seek.co.nz, au.seek.com or nz.seek.com), and single job pages, which are returned with full details:

```json
{
  "startUrls": [
    { "url": "https://www.seek.com.au/jobs-in-information-communication-technology/developers-programmers/in-All-Sydney-NSW?daterange=3" },
    { "url": "https://www.seek.co.nz/nurse-jobs/in-Auckland?worktype=243" },
    { "url": "https://www.seek.com.au/job/94604943" }
  ],
  "maxItems": 300
}
```

#### Output example

```json
{
  "jobId": "95181302",
  "url": "https://www.seek.com.au/job/95181302",
  "title": "Registered Nurse- Mental Health",
  "company": "Healthcare Australia",
  "advertiserName": "Healthcare Australia - Nursing VIC",
  "location": "Melbourne VIC",
  "region": "Melbourne",
  "state": "VIC",
  "countryCode": "AU",
  "classification": "Healthcare & Medical",
  "subClassification": "Nursing - Psych, Forensic & Correctional Health",
  "workType": "Casual/Vacation",
  "salaryText": "$46 - $146 per hour",
  "salaryMin": 46,
  "salaryMax": 146,
  "salaryPeriod": "hour",
  "salaryCurrency": "AUD",
  "listedAt": "2026-10-09T23:30:24Z",
  "bulletPoints": ["Earn up to $146/hr with weekly pay", "Flexible agency shifts and contracts across Melbourne"],
  "detailsFetched": true,
  "description": "Healthcare Australia (HCA) is seeking experienced Mental Health Registered Nurses...",
  "area": "CBD & Inner Suburbs",
  "expiresAt": "2026-11-09T00:00:00.000Z",
  "companyRating": 3.4,
  "companyReviewCount": 24,
  "companyIndustry": "Employment Services"
}
```

### How many jobs can I get per search?

SEEK shows at most **550 jobs for any one search**, also on its website. With **Get more than SEEK's 550 results per
search** (on by default) the actor splits a bigger search into narrower ones that together cover it: by
classification, then sub-classification, work type and work arrangement, and reads a slice that is still too big in
both sort orders. Duplicates are removed. In a test, "registered nurse" in All Melbourne VIC (SEEK reported 1,328
matches) returned **1,216 distinct jobs** from 67 requests in under a minute. For whole-country pulls, combine several
keywords or locations in one run.

### Can I get the full job description and the company rating?

Yes. Turn on **Include full job description**. For each job the actor reads SEEK's job details: the description
(plain text and HTML), the employer's screening questions, the area, expiry date, whether the advertiser is verified,
and the SEEK company profile (rating, number of reviews, industry, size, website, overview, perks). Search results
themselves do not carry the company rating. It is one extra small request per job. Single job URLs in Start URLs
always come with details.

### Does it work without login? Is a proxy needed?

It works without any login or cookies. It uses the same public JSON endpoints SEEK's own website calls, and
Apify's datacenter proxy (the default) works; no residential proxy is needed.

### Monitor changes on a schedule

Turn on **Only new or changed items** to watch a search: each run remembers what earlier runs returned and outputs
only jobs that are new or whose title or salary text changed. Unchanged jobs are dropped before any job details are
opened, so they are not charged. **Max jobs** then sets how many jobs are checked per run; sort by date so the newest
jobs land in that window. Save the input as a task and add a Schedule in Apify (for example daily); give each watch
its own **Monitoring key** if several schedules use the same search. Every output item has `changeType` (`new` or
`changed`), and changed jobs have `previousValues` with the old values, e.g. `{"salaryText": "$90,000 - $100,000"}`.

### Pricing

Pay per job: **$0.0012 per job** ($1.20 per 1,000). With **Include full job description** (or for a job URL) each
job adds a **$0.0004 detail** event, so $1.60 per 1,000 jobs with descriptions and company ratings. No start fee and
no subscription.

### Proxy note and cost

The actor runs on Apify's datacenter proxy by default. A search request returns up to 100 jobs and is about 0.17 MB;
a job details request is about 8 KB. Measured platform usage (compute, storage, proxy) is about **$0.005-0.007 per 1,000
jobs** without details and about $0.02 per 1,000 with details, on top of the per-job price. Requests that fail or come back blocked are retried
automatically on a new IP.

### Is it legal to scrape SEEK?

The actor reads only public job ads that anyone can open on SEEK without an account: what employers and agencies
publish, company names, ratings and pay information. It does not log in and does not collect job seekers' data.
Ads sometimes name a recruiter or contact person; that is part of the public ad. Phone numbers that SEEK hides behind
a "show" button are not collected. You are responsible for using the data in line with SEEK's terms and the privacy
laws that apply to you (for example the Australian Privacy Act or GDPR when you process personal data from ads).

# Actor input Schema

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

One search per keyword, e.g. "software engineer", "registered nurse", "electrician". Leave empty to list every job matching the location and filters.

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

Where, as you would type it on SEEK: a city or region ("All Sydney NSW", "Melbourne", "Auckland"), a suburb or a postcode ("2000"). Leave empty for the whole country.

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

seek.com.au (Australia) or seek.co.nz (New Zealand). Start URLs pick their site from the URL.

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

Optional: SEEK search URLs with any filters set on the site, e.g. https://www.seek.com.au/software-engineer-jobs/in-All-Sydney-NSW?daterange=7, or single job URLs (https://www.seek.com.au/job/94604943), which are returned with full details.

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

Only jobs in these SEEK classifications (role families). Several = jobs in any of them. Sub-classifications: paste a SEEK URL into Start URLs.

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

Only these work types. Several = any of them.

## `workArrangements` (type: `array`):

Only on-site, hybrid or remote jobs. Several = any of them.

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

SEEK's pay filter, lower bound, in AUD / NZD per the salary type below (e.g. 100000 per year or 40 per hour). SEEK also matches the pay range advertisers set without showing it.

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

SEEK's pay filter, upper bound (same unit as the minimum). Leave empty for no upper limit.

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

Unit of the minimum / maximum salary.

## `datePosted` (type: `string`):

Only jobs listed within this many days.

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

Relevance (SEEK's default) or newest first.

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

Stop after this many jobs in total (you pay per job saved).

## `maxItemsPerSearch` (type: `integer`):

Optional cap for each keyword / start URL, so one search does not use the whole Max jobs budget.

## `splitLargeSearches` (type: `boolean`):

SEEK shows at most 550 jobs for any search. With this on, a bigger search is split by classification, sub-classification, work type and work arrangement (and read in both sort orders when a slice is still too big), so you get far more of its jobs. Each extra page is one small request.

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

Open each job for the full description (text and HTML), screening questions, area, expiry date and the company profile (rating, review count, industry, size, website, perks). One extra request and one 'detail' event per job.

## `onlyNewOrChanged` (type: `boolean`):

Remember what earlier runs of this search returned and output only new jobs or jobs whose title or salary text changed. Use with a Schedule; unchanged jobs are not charged. With this on, Max jobs is the number of jobs checked per run; sort by date to watch the newest jobs.

## `monitoringKey` (type: `string`):

Name for this watch, so several schedules on the same search stay separate; defaults to a key derived from the search input

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

Apify datacenter proxy (the default) works: SEEK's search API does not block it. A page of 100 jobs is about 0.17 MB; job details about 8 KB each.

## Actor input object example

```json
{
  "keywords": [
    "software engineer"
  ],
  "location": "All Sydney NSW",
  "country": "AU",
  "salaryType": "annual",
  "datePosted": "",
  "sortBy": "relevance",
  "maxItems": 100,
  "splitLargeSearches": true,
  "includeDetails": false,
  "onlyNewOrChanged": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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 Sydney NSW",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

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

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

```

## MCP server setup

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