# JobBank Scraper - Canada Jobs, Salaries & Employers (`memo23/jobbank-scraper`) Actor

Scrape jobs from Canada's Job Bank (jobbank.gc.ca), the federal government job board. Get job title, employer, location, salary (min/max/unit), employment type, posting date and full description. Search by keyword + location, or paste job URLs. No proxy setup needed. JSON or CSV, pay per result.

- **URL**: https://apify.com/memo23/jobbank-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (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 $0.99 / 1,000 results

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?

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

## JobBank Scraper — Canada Jobs, Salaries, Employers & LMIA Leads

Scrape Canada's federal **Job Bank** (`jobbank.gc.ca`) by keyword and location, or from pasted job/search URLs. Get structured job title, employer, location, salary (min/max/unit), employment type, posting dates and full description — plus two things the raw site never gives you in one place: an **LMIA filter** for immigration and foreign-worker leads, and optional **employer contact-email discovery**.

Built for recruiters, immigration consultants, RCICs, lead-generation teams and labour-market analysts who need Job Bank data as clean rows instead of paging through the government site by hand.

### Why use this scraper

- **LMIA filter that the search UI buries.** Keep only jobs tied to a Labour Market Impact Assessment — the strongest public signal that an employer will sponsor a temporary foreign worker. Filter to *LMIA requested* or *Approved LMIA* with one dropdown.
- **Real salary structure, not a string.** Salaries come back parsed into `min`, `max`, `currency` and `unit` (hourly / yearly), so you can sort and filter numerically.
- **Optional employer contact emails.** Turn on enrichment and each row gains a best-effort `contactEmail`, `contactWebsite` and a social-profile block, discovered from the employer's own web presence.
- **Keyword + location or direct URLs.** Search `nurse` in `Toronto`, or paste any Job Bank search or `/jobposting/{id}` URL — both are auto-routed.
- **Fast and clean.** Job Bank is a low-friction government site; the actor streams pages concurrently and returns tidy, deduplicated rows.

### Overview

Job Bank is the Government of Canada's official job board. This actor reads its public search results and job postings, parses the structured (RDFa) job data on each posting, and returns one row per job. It handles pagination, direct URL input, sorting, the LMIA immigration facet, and opt-in contact-email enrichment.

### Supported inputs

| Input | What it does |
|---|---|
| `searchTerms` | Keywords to search, e.g. `developer`, `nurse`, `truck driver`. |
| `location` | City, province or region, e.g. `Toronto`, `British Columbia`. Empty = all of Canada. |
| `startUrls` | Paste Job Bank search-result or `/jobposting/{id}` URLs — each is auto-routed. |
| `sort` | Result order: most recent, distance, or salary. |
| `lmia` | Immigration facet: *Any*, *LMIA requested*, or *Approved LMIA*. |
| `enrichEmails` | Opt-in employer contact-email discovery (billed only when an email is found). |
| `maxItems` | Hard cap on jobs collected and billed. |
| `maxConcurrency` | Parallel requests (Job Bank is fast; this can be high). |
| `proxy` | Optional proxy override. The actor already routes through residential proxy at no extra cost. |

### Use cases

- **Immigration & foreign-worker sourcing.** Filter to LMIA-tied postings to build a list of employers actively hiring — and likely to sponsor — temporary foreign workers.
- **Recruitment & staffing.** Pull live vacancies by trade, region and salary band for candidate matching and market mapping.
- **Lead generation.** Enable email enrichment to turn LMIA and hiring signals into contactable employer leads.
- **Labour-market research.** Track posting volumes, salary ranges and employment types across provinces over time.

### How it works

1. Each keyword + location becomes a Job Bank search URL (with your sort and LMIA facet applied server-side); pasted URLs are classified as search or job pages.
2. Search pages are streamed and their job links fanned out concurrently.
3. Each job posting is fetched and parsed from its on-page structured data into a normalized row.
4. If enrichment is on, the employer name and location are used to discover a website and contact email, which are attached to the row.
5. Rows are pushed to the dataset, deduplicated by job.

### Output sample

```json
{
  "type": "job",
  "source": "jobbank.gc.ca",
  "jobId": "40123456",
  "url": "https://www.jobbank.gc.ca/jobsearch/jobposting/40123456",
  "title": "Registered Nurse (R.N.)",
  "employer": "Wolfville Nursing Homes Ltd.",
  "location": "Wolfville, NS",
  "locality": "Wolfville",
  "region": "NS",
  "postalCode": "B4P",
  "salary": { "value": "$38.00 hourly", "min": 38, "max": 42, "currency": "CAD", "unit": "hour", "raw": "$38.00 to $42.00 hourly" },
  "employmentType": ["Permanent", "Full time"],
  "datePosted": "2026-09-05",
  "description": "…",
  "contactEmail": "hr@example.com",
  "contactWebsite": "https://example.com",
  "scrapedAt": "2026-09-07T09:36:00.000Z"
}
```

`contactEmail`, `contactWebsite` and the `emailEnrichment` block are present only when `enrichEmails` is enabled and a match is found.

### Key output fields

`title`, `employer`, `location` / `locality` / `region` / `postalCode`, `salary` (`min` / `max` / `currency` / `unit`), `employmentType`, `datePosted`, `description`, `url`, `jobId`, `scrapedAt`, and — with enrichment — `contactEmail`, `contactWebsite`, `emailEnrichment`.

### Pricing

Pay-per-event:

- **$0.99 per 1,000 results** (one event per job returned).
- **$0.05 per contact email found** — charged only on rows where enrichment actually returns an email; costs nothing when `enrichEmails` is off.
- A small per-run start fee based on memory, as standard on Apify.

### FAQ

**Do I need a proxy?** No. The actor routes through residential proxy by default at no extra cost. You can supply your own under the proxy input if you prefer.

**How current is the data?** It reads Job Bank live at run time, so results reflect what is on the site when the run starts.

**What is the LMIA filter for?** LMIA-tied postings signal employers open to hiring temporary foreign workers — the highest-value segment for immigration and cross-border recruitment work.

**Will every row have a contact email?** No. Email discovery is best-effort and only succeeds for employers with a findable web presence. You are billed only when an email is found.

### For AI agents & LLM apps

Every row is flat, typed JSON with numeric salary fields and a stable schema, ready to feed a retrieval pipeline, an agent tool call, or a spreadsheet without post-processing. Point an MCP-enabled agent at this actor to pull live Canadian labour-market data on demand.

### Disclaimer

This actor collects only publicly available information from `jobbank.gc.ca`. Use the data in compliance with applicable laws and the source site's terms. It is your responsibility to ensure your use of scraped data, including any personal data such as contact emails, complies with GDPR, PIPEDA and other applicable regulations.

### SEO keywords

Canada Job Bank scraper, jobbank.gc.ca scraper, Canadian jobs API, LMIA jobs scraper, LMIA employer list, foreign worker jobs Canada, Canada job postings data, employer contact emails Canada, Canadian salary data, immigration job leads, Job Bank Canada export, recruitment data Canada.

# Actor input Schema

## `searchTerms` (type: `array`):

Keywords to search, e.g. `developer`, `nurse`, `truck driver`.

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

City, province or region, e.g. `Toronto`, `British Columbia`. Leave empty for all of Canada.

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

Paste JobBank search-result URLs or direct `/jobposting/{id}` URLs — each is auto-routed. Scraped in addition to any keywords.

## `sort` (type: `string`):

How JobBank sorts results.

## `lmia` (type: `string`):

Keep only jobs tied to a Labour Market Impact Assessment — Job Bank's own facet, the strongest signal an employer will sponsor a temporary foreign worker. 'Requested' = LMIA applied for; 'Approved' = LMIA granted. 'Any' applies no filter.

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

Discover each employer's website and read its contact/about pages to find a contact email. Adds contactEmail + contactWebsite plus an emailEnrichment object. Best-effort, billed only when an email is found.

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

Hard cap on jobs collected (and billed).

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

Parallel requests. JobBank is a fast government site, so this can be high.

## `proxy` (type: `object`):

Leave empty — the actor already routes through its own residential proxy at no extra cost. Only set this to use your own proxies.

## Actor input object example

```json
{
  "searchTerms": [
    "developer"
  ],
  "location": "Toronto",
  "startUrls": [],
  "sort": "M",
  "lmia": "any",
  "enrichEmails": false,
  "maxItems": 1000,
  "maxConcurrency": 10
}
```

# Actor output Schema

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

One row per Job Bank vacancy with title, employer, parsed salary (min/max/unit/currency), location, employment type, dates, description and optional employer contact email.

# 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 = {
    "searchTerms": [
        "developer"
    ],
    "location": "Toronto",
    "startUrls": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/jobbank-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 = {
    "searchTerms": ["developer"],
    "location": "Toronto",
    "startUrls": [],
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/jobbank-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 '{
  "searchTerms": [
    "developer"
  ],
  "location": "Toronto",
  "startUrls": []
}' |
apify call memo23/jobbank-scraper --silent --output-dataset

```

## MCP server setup

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