Canada Job Bank Data API: Job Postings, NOC Codes & Salaries
Pricing
from $1.60 / 1,000 job posting returneds
Canada Job Bank Data API: Job Postings, NOC Codes & Salaries
Canada Job Bank data from the official monthly open data (OGL-Canada): Canada job postings with NOC 2021 codes, salary ranges, province, city and vacancies. Filter by month, job title, NOC code, province, city, employment type and wage. Canadian labour-market data as CSV, JSON or Excel.
Pricing
from $1.60 / 1,000 job posting returneds
Rating
0.0
(0)
Developer
Your Evenings
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 hours ago
Last modified
Share

Canada Job Bank data as clean, flat rows: the job postings advertised on Canada's national Job Bank, read from the official monthly open-data files that Employment and Social Development Canada (ESDC) publishes on open.canada.ca. Filter by month, job title, NOC 2021 occupation code, province or territory, city, employment type, who posted it and pay. Every row has the occupation codes, workplace location (city, economic region and postal area), vacancies and posting date. Most rows also have a posted salary range and period (52,358 of 52,368 in September 2026). Postings made on Job Bank by employers add hours, schedule, education, experience, industry and work language. Turn on monitor mode and schedule it to get each new month once.
Use it for Canadian labour-market data: wages by occupation and province, which occupations post the most vacancies, or a monthly feed of Canada jobs data for a dashboard. Export as CSV, JSON or Excel.
Contains information licensed under the Open Government Licence – Canada. This Actor is not operated, sponsored, approved or endorsed by Employment and Social Development Canada, Job Bank or the Government of Canada.
What this data is (and is not)
- Monthly, not live. ESDC publishes one file per month, a few weeks after the month ends. The files start in January 2023. For the newest postings, look on jobbank.gc.ca itself.
- Anonymised. The open data has no employer names, no contact details and no links to apply. Rows describe the job (occupation, place, pay, hours, conditions), not who is hiring. Workplace postal codes are cut to their first three characters (the forward sortation area) in this Actor.
- Two kinds of posting. More than half the postings in recent files (57% in September 2026) are shared to Job Bank from external job boards (
postedVia: "external job board"). In the September 2026 file, 30,098 of the 30,108 external rows had a salary range, but only 3,512 had hours (with no hours period), and none had education, experience, industry, schedule or telework. Postings made on Job Bank by employers had all of these. - Pay and hours as posted. Rows carry the posted pay (
salaryText,salaryMin,salaryMax,salaryPer) and hours (hoursMin,hoursMax,hoursPer) wherever the posting gives them. Thebenefitsfield is reserved for the source's 16 benefit and pay-condition flags (dental, pension, RRSP, bonus and so on) and fills in once ESDC publishes them; the files for September 2025, January 2026, August 2026 and September 2026 mark them allNo(Job Bank postings) orNA(external postings). - English files. The Actor reads the English version of each file. French versions exist, with French column names and values; they are not read yet.
Why use this Canada Job Bank data?
- Official source, open licence. Rows come from the published open-data files (dataset "Job Postings Advertised on Canada's National Job Bank Website"), listed through the open.canada.ca data API. No page scraping, no login, no key.
- Every month in one shape. The monthly files change format (UTF-16 tab-separated in most months, UTF-8 comma-separated in some 2024 months, columns added over time). The Actor reads them all by column name and gives the same row shape.
- Filters run before you pay. Postings removed by your filters are never charged. A run stops reading the file as soon as it has
maxResultsrows. - Free status rows say when nothing matched, when a month was already read in monitor mode, when the limit stopped the read, when the input has a mistake, or when the source failed.
How do I get Canada Job Bank postings? Quick start
- Leave Months as
latest, or enter months like2026-09, orlatest-3for the newest three. - Add filters: Job title contains (for example
nurse), NOC 2021 codes, Provinces, Cities, or a Minimum salary with its Salary period. - Run. Results appear in the Postings view; download as JSON, CSV or Excel, or read them by API.
Or just press Start: the form comes prefilled to return up to 100 postings with "nurse" in the title from the newest month.
A narrower example, for postings in Ontario paying at least $25 an hour:
{"months": ["latest"],"provinces": ["ON"],"salaryPer": "Hour","minSalary": 25,"maxResults": 100}
Data source
| What | Where it comes from |
|---|---|
| List of monthly files | open.canada.ca data API, package_show?id=ea639e28-c0fc-48bf-b5dd-b8899bd43072 |
| Postings | The English monthly CSV file for each month, downloaded from the link in that record |
Publisher: Employment and Social Development Canada. Licence: Open Government Licence – Canada, which allows copying, adapting and commercial use with attribution. Every row carries the attribution statement and the link to the official file it came from. open.canada.ca asks automated clients to wait 20 seconds between requests; the Actor does, so each extra month in a run adds about 20 seconds.
Who it's for
- Labour-market analysts, economists and workforce boards looking at vacancies and posted wages by occupation and region.
- Immigration and settlement advisers and researchers who track which occupations and provinces post the most jobs.
- HR and compensation teams comparing posted pay ranges for an occupation across provinces.
- Job boards and data teams that want a clean monthly Canadian postings dataset next to other sources.
How do I filter job postings by NOC code or province?
Put NOC 2021 codes, or their first digits, in nocCodes (31301 is registered nurses; 72 keeps every code starting with 72). Put provinces or territories in provinces, as names or two-letter codes (ON, QC, BC …). Filters can be combined, and postings removed by your filters are never charged.
{ "months": ["latest-3"], "nocCodes": ["31301"], "provinces": ["BC"], "maxResults": 500 }
That returns registered nurses (NOC 31301) in British Columbia from the newest three months. More examples follow below.
Input examples: Canada job postings by NOC code, province and salary
Registered nurses (NOC 31301) in British Columbia, last three months
{ "months": ["latest-3"], "nocCodes": ["31301"], "provinces": ["BC"], "maxResults": 500 }
Truck drivers in Alberta and Saskatchewan, full time
{ "months": ["latest"], "keywords": ["truck driver"], "provinces": ["AB", "SK"], "employmentTypes": ["Full time"], "maxResults": 200 }
Software engineers and developers in Toronto paying $90,000 a year or more
{ "months": ["latest"], "nocCodes": ["21231", "21232"], "cities": ["Toronto"], "salaryPer": "Year", "minSalary": 90000, "maxResults": 100 }
How do I get salaries by occupation?
Put NOC 2021 codes, or their first digits, in nocCodes, add provinces if you like, and read salaryMin, salaryMax and salaryPer on each row. To keep only postings above a pay level, set salaryPer (Hour, Day, Week, Bi-weekly, Month or Year) and minSalary, for example 25 per Hour or 60000 per Year. Most rows have a posted salary range (52,358 of 52,368 in September 2026).
What Canada Job Bank data do I get?
One row per posting (rowType: "posting"): postingId, month, jobTitle, originalJobTitle, noc2021Code, noc2021Name, noc2016Code, noc2016Name, postedVia, firstPostingDate, vacancies, province, city, postalArea, economicRegion, industry, employmentType, employmentTerm, termStartDate, termEndDate, schedule, telework, salaryText, salaryPer, salaryMin, salaryMax, benefits, hoursPer, hoursMin, hoursMax, educationLevel, experienceLevel, workLanguage, governmentEmployer, placementAgency, sourceFile, licence, retrievedAt. Missing values (NA in the files) are null.
Free status rows (rowType: "status"): no_matches, already_reported, max_results, time_limit, invalid_input, source_error, budget_reached. If the input has a mistake (for example an unknown province or a month that isn't published), the run still finishes successfully with one free invalid_input row that says what to fix, and no rows are charged. A SUMMARY record in the key-value store lists the months read, rows checked and returned, filters and request counts.
What does the output look like?
Five rows from our test run on 31 October 2026 (postings with "nurse" in the job title from the September 2026 file, stopped at a limit of 5 rows), shortened:
| Month | Job title | NOC 2021 | Province | City | Posted via | Salary | Hours | Vacancies |
|---|---|---|---|---|---|---|---|---|
| 2026-09 | registered nurse - telehealth | 31301 | Ontario | – | Job Bank (employer account) | $38–40.50 per hour | 37.5–40 per week | 10 |
| 2026-09 | nurse practitioner | 31302 | Ontario | Fort Erie | external job board | $42–75 per hour | – | 1 |
| 2026-09 | registered nurse (R.N.) | 31301 | Ontario | Lindsay | Job Bank (employer account) | $1,562.72–2,240.04 per week | 40 per week | 10 |
| 2026-09 | RN (registered nurse) | 31301 | Ontario | Perth | external job board | $55–60 per hour | – | 1 |
| 2026-09 | nurse | 31301 | Ontario | Shelburne | external job board | $65,000–75,000 per year | – | 1 |
The run ended with a free status row: "Stopped at your limit of 5 rows while reading 2026-09; the rest of that month was not read."
Input: how do I filter Canada job postings?
Every field is optional. With no filters, a run returns up to 100 postings from the newest month.
Months (months)
YYYY-MM, latest or latest-N. Up to 12 months per run. Each month takes about 20 to 25 seconds to read, because the source asks for a 20-second gap between requests. In testing, 12 months finished in about 4 minutes, inside the default 5-minute timeout. If the run nears its time limit it stops cleanly, keeps the rows already returned and adds a free time_limit row naming the months not read. Default latest. The files start in January 2023.
Job title contains (keywords)
Job title contains any of these (accents and case ignored).
NOC 2021 codes (nocCodes)
NOC 2021 codes or their first digits, e.g. 31301 or 72.
Provinces and territories (provinces)
Names or two-letter codes (ON, QC, BC …).
Cities (cities)
City names as written in the data (accents and case ignored).
Employment types (employmentTypes)
Full time, Part time, Part time leading to full time.
Posted via (postedVia)
all, jobBank (posted on Job Bank by employers) or external (shared from other job boards).
Salary period (salaryPer)
Hour, Day, Week, Bi-weekly, Month or Year. Keep postings that state pay for that period. Needed when you set a minimum salary.
Minimum salary (CAD) (minSalary)
With salaryPer: keep postings whose minimum pay for that period is at least this, e.g. 25 per Hour or 60000 per Year.
Telework only (teleworkOnly)
Keep postings flagged for telework (recent files flag very few).
Max results (maxResults)
Stop after this many postings. Default 100. A full month has roughly 50,000 to 110,000 postings.
Monitor mode (monitorMode)
Remember months already returned and skip them on later runs. See How do I get each new month of Job Bank data? below.
Return current months on the first monitor run (emitBaselineOnFirstRun)
Default on. See How do I get each new month of Job Bank data? below.
Monitor state store (stateStoreName)
Named key-value store that remembers months already returned. Use a different name for each saved search. See How do I get each new month of Job Bank data? below.
How do I get each new month of Job Bank data?
Turn on Monitor mode and schedule the Actor (weekly is plenty). Keep Months as latest. The first run returns the newest month (or, with Return current months on the first monitor run off, just remembers it). Later runs skip months already read and return rows only when a new month is published. If maxResults stops a month early, that month still counts as read, so set maxResults high enough for your filters. Use a different Monitor state store name for each saved search. A run with nothing new pays only Apify's start event.
How much does it cost?
Pay per event. You pay only for what is delivered. Prices on the Actor's Pricing tab are authoritative.
| Event | Price |
|---|---|
| Job posting returned | $0.002 per posting |
| Monitor run with a new month | $0.01 per run, only on monitor runs that return at least one posting |
| Actor start (once per run, per GB of memory; the default 1 GB run counts as one) | $0.00005 |
Status rows, the SUMMARY record, postings removed by your filters and months already read in monitor mode are free. If a run reaches your maximum charge it stops cleanly with a free budget_reached row.
Use Canada Job Bank data from code or an AI agent
Call it with the Apify API, the Apify client for JavaScript or Python, or through Apify's MCP server for AI agents. The input is plain JSON and every field is described in the input schema.
The examples below return at most 10 postings (plus any free status rows) and set a maximum cost of $0.05 for the run, so trying them costs a few cents at most. Read your API token from an environment variable (APIFY_TOKEN) rather than pasting it into code.
JavaScript (Node.js)
// npm install apify-clientimport { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('yourevenings/canada-job-bank-data').call({"months": ["latest"],"keywords": ["nurse"],"maxResults": 10},{ maxTotalChargeUsd: 0.05 },);const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items);
Python
# pip install "apify-client>=3"import osfrom decimal import Decimalfrom apify_client import ApifyClientclient = ApifyClient(os.environ["APIFY_TOKEN"])run = client.actor("yourevenings/canada-job-bank-data").call(run_input={"months": ["latest"],"keywords": ["nurse"],"maxResults": 10},max_total_charge_usd=Decimal("0.05"),)for item in client.dataset(run.default_dataset_id).iterate_items():print(item)
HTTP API (cURL)
curl -X POST "https://api.apify.com/v2/acts/yourevenings~canada-job-bank-data/run-sync-get-dataset-items?maxTotalChargeUsd=0.05" \-H "Authorization: Bearer $APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"months": ["latest"], "keywords": ["nurse"], "maxResults": 10}'
AI agents (MCP)
Add Apify's MCP server with just this Actor as a tool. On first connection your browser opens so you can sign in to Apify and approve access.
{"mcpServers": {"apify": {"url": "https://mcp.apify.com?tools=yourevenings/canada-job-bank-data"}}}
FAQ
Why are there no company names or apply links?
The official open data does not include them. It's built for job-market data: occupations, locations, pay and posting dates.
How fresh is it?
Monthly. A new file usually appears a few weeks after the month ends.
Why do some rows have no hours, education or experience?
Postings shared from external job boards rarely carry them: in September 2026, 3,512 of 30,108 external rows had hours and none had education or experience, although 30,098 had a salary range. Set postedVia to jobBank for rows with full details.
Why is benefits always empty?
The source files currently mark every benefit column No or NA, so there is nothing to report. The field will fill in if ESDC starts publishing these flags.
Can I use the data commercially?
The Open Government Licence – Canada allows it, with attribution. Keep the attribution statement from the licence field with the data.
Do I need an API key or login for Canada Job Bank data?
No. The Actor reads the official monthly open data files listed through the open.canada.ca data API. No page scraping, no login, no key.
How do I export Canada job postings to CSV or Excel?
Each run saves its rows to an Apify dataset. Download it as JSON, CSV, Excel, XML or HTML from the run's Output or Storage tab, or fetch it through the Apify API. Integrations can also send each run's results to Google Sheets, Make, Zapier or webhooks.
Feedback
Found a problem or want a field added? Open an issue on the Actor's Issues tab.