# Eluta.ca Jobs Scraper (`parsebird/eluta-jobs-scraper`) Actor

Scrape Eluta.ca job listings: titles, salaries, employer profiles, NAICS codes, Top Employer badges, and resolved ATS apply links. Monitor new postings daily.

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

## Pricing

from $1.30 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

### Eluta.ca Jobs Scraper

Scrape job listings from [Eluta.ca](https://www.eluta.ca), Canada's job search engine and the official search partner behind the Canada's Top 100 Employers project. This Eluta scraper extracts titles, salaries, employer profiles, NAICS industry codes, Top Employer badges, and resolved apply links from any Eluta search, employer page, or job posting.

<table><tr>
<td style="border-left:4px solid #1C1917;padding:12px 16px;font-weight:600">
Search by keyword and Canadian city, or feed in any Eluta.ca URL — get full job descriptions, employer headquarters data, salary breakdowns, and the real ATS apply link instead of Eluta's redirect.
</td>
</tr></table>

##### Copy to your AI assistant

Copy this block into ChatGPT, Claude, Cursor, or any LLM to start using this actor.

```
Apify Actor: parsebird/eluta-jobs-scraper. Scrapes job listings from Eluta.ca, Canada's job search engine. Call via ApifyClient: client.actor("parsebird/eluta-jobs-scraper").call(run_input={"query": ["software engineer"], "location": ["Toronto"], "sortBy": "relevance", "includeDetails": true, "resolveApplyUrls": true, "maxItems": 100}). Returns per job: jobId, title, companyName, companyWebsite, companyDomain, naicsCode, companyHeadquarters, location, salaryText, salaryMin, salaryMax, salaryCurrency, salaryType, employmentType, industry, postedDate, closingDate, descriptionText, descriptionHtml, applyUrl, applyUrlResolved, sourceDomain, atsJobId, topEmployer, elutaUrl. Full API spec: https://apify.com/parsebird/eluta-jobs-scraper/api. Get your token: https://console.apify.com/settings/integrations.
```

### What does Eluta.ca Jobs Scraper do?

This Eluta.ca scraper automates job search on [Eluta.ca](https://www.eluta.ca) and turns results into structured, analysis-ready data. Eluta indexes postings directly from employer career sites and ranks them using its own relevance and Top Employer signals, so its data differs from job boards that rely on employer self-submission — it's a strong source for Canadian labour-market research and recruiting pipelines.

- 🔎 **Flexible search** — combine keywords with Canadian cities, or use Eluta's own in-query qualifiers (e.g. `nurse sort:date`) for advanced filtering
- 🔗 **Any Eluta URL as input** — search result pages, SEO landing pages (`/Nurse-jobs-in-Toronto-ON`), employer pages (`/jobs-at-...`), or a single job page (`/spl/...`)
- 📄 **Full detail pages** — job description (HTML + plain text), posted/closing dates, employment type, industry, and salary breakdown
- 🏢 **Employer metadata** — legal name, website, domain, NAICS industry code, logo, and headquarters address with coordinates
- 🏆 **Top Employer detection** — flags postings from Canada's Top 100 Employers and related regional competitions
- 🔗 **Resolved apply links** — follows Eluta's outbound redirect (or reads the employer's own structured data when available) so `applyUrl` points at the real ATS page, not Eluta's redirector
- 📧 **Optional employer email discovery** — opt-in scan of the employer's website for a public contact address
- 📡 **Monitoring feed mode** — pair with a daily Apify schedule and only new postings since the last run are returned

### What data can you extract from Eluta.ca?

| Field | Description |
|-------|-------------|
| `title` | Job title |
| `companyName` / `companyLegalName` | Employer display name and registered legal name |
| `companyWebsite` / `companyDomain` | Employer's own website and its domain |
| `naicsCode` | Employer's NAICS industry classification code |
| `companyHeadquarters` | Street address, city, region, postal code, and lat/lng (when published) |
| `location` | Job location (city, province) |
| `salaryText` / `salaryMin` / `salaryMax` / `salaryCurrency` / `salaryType` | Salary as displayed, plus parsed min/max, currency, and YEAR/HOUR unit |
| `employmentType` | e.g. `FULL_TIME`, `PART_TIME` |
| `industry` | Eluta's industry/category classification |
| `postedDate` / `closingDate` | ISO-format posting and application-deadline dates |
| `descriptionText` / `descriptionHtml` | Full job description, plain text and original HTML |
| `topEmployer` / `topEmployerReviewUrl` | Canada's Top 100 Employers badge and link to the review |
| `applyUrl` / `applyUrlResolved` / `sourceDomain` / `atsJobId` | Resolved employer apply link, whether resolution succeeded, its domain, and the ATS's own job ID when detectable |
| `elutaUrl` | The canonical Eluta.ca job page |

### Input parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `query` | array | No\* | `["software engineer"]` | Keywords to search. Each keyword runs as its own search. Eluta in-query qualifiers (e.g. `nurse sort:date`) are allowed |
| `location` | array | No | `["Toronto"]` | Canadian cities/regions combined with every keyword. Empty searches all of Canada |
| `sortBy` | string | No | `relevance` | `relevance`, `date` (newest first — best for monitoring), or `popularity` |
| `startUrls` | array | No\* | `[]` | Any Eluta.ca URL: search results, SEO landing pages, employer pages, or a direct job page. Runs in addition to `query` |
| `includeDetails` | boolean | No | `true` | Fetch each job's own page for full description, dates, employer metadata, and salary breakdown |
| `resolveApplyUrls` | boolean | No | `true` | Resolve the outbound redirect to the employer's real ATS URL |
| `enrichEmails` | boolean | No | `false` | Scan the employer's website for a public contact email (requires `includeDetails`, billed per email found) |
| `monitoringMode` | boolean | No | `false` | Only return jobs not already delivered by a previous run — pair with a daily schedule |
| `maxItems` | integer | No | `100` | Hard cap on jobs returned across all searches and start URLs |
| `maxPagesPerSearch` | integer | No | `20` | Stop paginating a single search after this many result pages (~10 jobs/page) |
| `maxConcurrency` | integer | No | `10` | Parallel job detail/apply/email requests |

\* At least one of `query` or `startUrls` is required.

### How to scrape Eluta.ca jobs with this actor

1. Open the [Eluta.ca Jobs Scraper](https://apify.com/parsebird/eluta-jobs-scraper) page and click **Try for free**.
2. Enter one or more **Search Queries** (e.g. `registered nurse`) and **Locations** (e.g. `Toronto`, `Vancouver`) — or paste Eluta.ca URLs directly into **Start URLs**.
3. Choose a **Sort By** order — pick `date` if you're building a feed of newest postings.
4. Leave **Fetch job detail pages** and **Resolve apply URLs** on for full records, or turn them off for a fast, search-results-only run.
5. Set **Max Items** to control run size and cost, then click **Start**.
6. Download results as JSON, CSV, or Excel from the Dataset tab, or pull them via the [Apify API](https://docs.apify.com/api/v2).

### Output example

```json
{
    "type": "job",
    "jobId": "28ef5f4360c0f9f0a6eb37c0bcd1dbb9",
    "title": "Software Development Engineer 2, Amazon Kids, Amazon Kids",
    "companyName": "Amazon Canada",
    "companyLegalName": "Amazon Canada",
    "companyWebsite": "http://www.amazon.ca/",
    "companyDomain": "amazon.ca",
    "companySlug": "amazon-canada",
    "naicsCode": "454111",
    "companyHeadquarters": {
        "streetAddress": "14-510 Georgia",
        "addressLocality": "Vancouver",
        "addressRegion": "British Columbia",
        "postalCode": "V6B 0M3",
        "addressCountry": "Canada",
        "latitude": 49.2786,
        "longitude": -123.112
    },
    "location": "Toronto, ON",
    "salaryText": "$114,800-$191,800",
    "salaryMin": 114800.0,
    "salaryMax": 191800.0,
    "salaryCurrency": "CAD",
    "salaryType": "YEAR",
    "employmentType": "FULL_TIME",
    "industry": "Computing - Software & Web Development",
    "postedDate": "2026-08-11T04:51:32",
    "closingDate": "2026-09-15T00:00:00",
    "topEmployer": false,
    "topEmployerReviewUrl": null,
    "applyUrl": "https://www.amazon.jobs/en/jobs/10498176/software-development-engineer-2-amazon-kids-amazon-kids",
    "applyUrlResolved": true,
    "sourceDomain": "www.amazon.jobs",
    "atsJobId": "10498176",
    "elutaUrl": "https://www.eluta.ca/spl/software-development-engineer-2-amazon-kids-amazon-kids-28ef5f4360c0f9f0a6eb37c0bcd1dbb9",
    "searchQuery": "software engineer",
    "detailFetched": true,
    "scrapedAt": "2026-08-11T10:12:48.247Z"
}
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("parsebird/eluta-jobs-scraper").call(run_input={
    "query": ["registered nurse", "software engineer"],
    "location": ["Toronto", "Vancouver"],
    "sortBy": "date",
    "maxItems": 200,
})

for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["title"], "-", job["companyName"])
```

#### JavaScript

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

const client = new ApifyClient({ token: "<YOUR_API_TOKEN>" });
const run = await client.actor("parsebird/eluta-jobs-scraper").call({
    query: ["registered nurse", "software engineer"],
    location: ["Toronto", "Vancouver"],
    sortBy: "date",
    maxItems: 200,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Use cases

- **Canadian talent sourcing** — Build recruiting pipelines around Eluta's Top Employer and NAICS-classified listings.
- **New-postings monitoring** — Schedule daily runs with `monitoringMode` to catch newly listed roles the moment they're indexed.
- **Salary benchmarking** — Aggregate `salaryMin`/`salaryMax` across roles and cities to benchmark Canadian compensation.
- **Employer research** — Pull headquarters address, NAICS code, and website for every company hiring in a given sector.
- **ATS/apply-link auditing** — Use `sourceDomain` to see which ATS platforms (iCIMS, Workday, Greenhouse, etc.) Canadian employers rely on.
- **Labour market research** — Track posting volume, industries, and employment types by city over time.

### How it works

1. **Search** — For each keyword × location combination (or each Start URL you provide), the actor requests Eluta's search, SEO landing, or employer page and parses the job cards on it.
2. **Pagination** — It walks result pages (~10 jobs each) until `maxPagesPerSearch` is hit, the site reports no more results, or `maxItems` is reached.
3. **Detail fetch** — When `includeDetails` is on, each job's own page is fetched and parsed from its structured data (JSON-LD or schema.org microdata, whichever the posting exposes) for the full description, dates, salary, and employer profile.
4. **Apply link resolution** — When `resolveApplyUrls` is on, the actor follows Eluta's outbound redirect (or reads the employer's own identifier field when the posting already publishes it) to capture the real ATS URL and its domain.
5. **Monitoring dedup** — In `monitoringMode`, job IDs already delivered by a previous run of the same task are filtered out before detail fetching, so scheduled runs only spend budget on new postings.
6. **Output** — Every job is pushed to the Apify dataset as it's processed, downloadable as JSON, CSV, or Excel, or accessible instantly via the [Apify API](https://docs.apify.com/api/v2) and [integrations](https://apify.com/integrations) (Zapier, Make, Google Sheets, and more).

### How much does it cost to scrape Eluta.ca jobs?

Eluta.ca Jobs Scraper uses Apify's [pay-per-event](https://docs.apify.com/platform/actors/publishing/monetize#pay-per-event-pricing) model — you pay only for jobs actually delivered, not for compute time.

| Event | Free plan | Bronze | Silver | Gold |
|-------|-----------|--------|--------|------|
| `job-scraped` (per 1,000) | $1.60 | $1.50 | $1.40 | $1.30 |
| `email-found` (per 1,000, opt-in) | $8.00 | $8.00 | $8.00 | $8.00 |

Every job pushed to the dataset counts as one `job-scraped` event, regardless of `includeDetails`. The optional `enrichEmails` feature additionally charges `email-found` only when an employer contact email is actually located. A 500-job run on the Free plan costs about $0.80; running with `includeDetails` on doesn't cost more per job, since detail fetching is part of the same event. Apify's [free trial](https://apify.com/pricing) covers your first runs at no cost.

### Is it legal to scrape Eluta.ca?

Yes. Eluta.ca Jobs Scraper only collects data that is already public on Eluta.ca — job postings that employers have chosen to make visible for recruitment. The actor does not bypass logins, CAPTCHAs, or paywalls, and does not access private accounts or personal data. See Apify's [blog post on the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/) for a general overview. You are responsible for using the collected data in compliance with applicable laws and Eluta.ca's [Terms of Service](https://www.eluta.ca).

### Related Actors

- [Workopolis Job Scraper](https://apify.com/parsebird/workopolis-job-scraper) — another major Canadian job board
- [Hiring.cafe Jobs Scraper](https://apify.com/parsebird/hiring-cafe-scraper) — 2.8M+ aggregated postings across 46 ATS platforms
- [Dice Jobs Scraper](https://apify.com/parsebird/dice-jobs-scraper) — tech-focused listings from Dice.com
- [BuiltIn Jobs Scraper](https://apify.com/parsebird/builtin-jobs-scraper) — startup and tech-company listings from BuiltIn.com

### FAQ

**Does this need a proxy?** Eluta.ca is not aggressively protected, but its search endpoint does rate-limit repeated requests from the same IP. Apify Proxy is enabled by default in the input and is strongly recommended for anything beyond small test runs.

**What happens if `applyUrl` can't be resolved?** Eluta occasionally rate-limits its own redirect endpoint. When that happens, `applyUrlResolved` is `false` and `applyUrl` falls back to Eluta's own redirect link (which still works in a browser) instead of a guessed or incorrect URL.

**Can I use Eluta's own search qualifiers?** Yes — anything you'd normally type into Eluta's search box, including qualifiers like `sort:date` or `radius:25`, works inside a `query` entry.

**How does monitoring mode know what's "new"?** It stores delivered job IDs in a per-Actor state store and filters them out of future runs. Run it via an Apify [Task](https://docs.apify.com/platform/actors/running/tasks) with a daily [Schedule](https://docs.apify.com/platform/schedules) for a clean new-postings feed.

**Why is `companyName` sometimes empty on employer-page searches?** Eluta omits the repeated employer name on its own `/jobs-at-...` pages. Turn on `includeDetails` and the actor backfills it from the job's own page.

**Can I search a specific employer or SEO landing page?** Yes — paste any `/jobs-at-...` employer page or `/{Title}-jobs-in-{City}-{Province}` SEO page into `startUrls`; it's parsed the same way as a search results page.

Found a bug or have a feature request? Open an issue on the Actor's Issues tab — feedback shapes what gets built next.

# Actor input Schema

## `query` (type: `array`):

Keywords to search on Eluta.ca (e.g. "software engineer"). Each keyword runs as its own search. Eluta in-query qualifiers (e.g. "nurse sort:date") are allowed. Leave empty if you only use Start URLs.

## `location` (type: `array`):

Cities or regions to combine with every keyword (e.g. "Toronto", "Vancouver"). Leave empty to search all of Canada.

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

Result order for keyword searches. "Date" surfaces the newest postings first and is best for monitoring feeds.

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

Any Eluta.ca URL: search results (/search?q=...), SEO landing pages (/Nurse-jobs-in-Toronto-ON), employer pages (/jobs-at-...), or a direct job page (/spl/...). Runs in addition to Search Queries above.

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

Visit each job's own page to collect the full description, posted/closing dates, employer metadata, and salary breakdown. Turn off for fast, search-results-only rows.

## `resolveApplyUrls` (type: `boolean`):

Follow Eluta's outbound redirect so applyUrl points at the employer's real ATS page instead of Eluta's own redirector link.

## `enrichEmails` (type: `boolean`):

Scan each employer's website for a public contact email. Opt-in — requires "Fetch job detail pages" to be on and is billed per email found.

## `monitoringMode` (type: `boolean`):

Only return jobs not already delivered by a previous run of this Actor (matched on task). Use with a daily schedule to build a new-postings feed.

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

Hard cap on jobs returned across all searches and Start URLs combined.

## `maxPagesPerSearch` (type: `integer`):

Stop paginating a single search/Start URL after this many result pages (~10 jobs per page).

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

Number of job detail/apply/email requests to run in parallel.

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

Eluta.ca is not aggressively protected, but Apify Proxy is recommended for larger monitoring runs.

## Actor input object example

```json
{
  "query": [
    "software engineer"
  ],
  "location": [
    "Toronto"
  ],
  "sortBy": "relevance",
  "startUrls": [],
  "includeDetails": true,
  "resolveApplyUrls": true,
  "enrichEmails": false,
  "monitoringMode": false,
  "maxItems": 100,
  "maxPagesPerSearch": 5,
  "maxConcurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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 = {
    "query": [
        "software engineer"
    ],
    "location": [
        "Toronto"
    ],
    "sortBy": "relevance",
    "maxItems": 100,
    "maxPagesPerSearch": 5,
    "maxConcurrency": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("parsebird/eluta-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 = {
    "query": ["software engineer"],
    "location": ["Toronto"],
    "sortBy": "relevance",
    "maxItems": 100,
    "maxPagesPerSearch": 5,
    "maxConcurrency": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("parsebird/eluta-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 '{
  "query": [
    "software engineer"
  ],
  "location": [
    "Toronto"
  ],
  "sortBy": "relevance",
  "maxItems": 100,
  "maxPagesPerSearch": 5,
  "maxConcurrency": 10
}' |
apify call parsebird/eluta-jobs-scraper --silent --output-dataset

```

## MCP server setup

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