Arbeidsplassen NAV Job Scraper — Norway Job Leads avatar

Arbeidsplassen NAV Job Scraper — Norway Job Leads

Pricing

from $1.20 / 1,000 per job ad returneds

Go to Apify Store
Arbeidsplassen NAV Job Scraper — Norway Job Leads

Arbeidsplassen NAV Job Scraper — Norway Job Leads

Scrape Norway's national NAV job board arbeidsplassen.nav.no: title, employer, county, occupation, dates and NAV's own AI summary, plus org number, apply link, ATS vendor and named contact e-mail/phone from the ad page. 12,400+ live ads, ~550 new per day. No login.

Pricing

from $1.20 / 1,000 per job ad returneds

Rating

0.0

(0)

Developer

Scrapers Delight

Scrapers Delight

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

🇳🇴 Arbeidsplassen (NAV) Job Scraper — Norway's national vacancy board

Scrape arbeidsplassen.nav.no, the public job board run by NAV (the Norwegian Labour and Welfare Administration) — the one register where Norwegian vacancies from FINN, from every major applicant-tracking system, and from employers typing straight into NAV all land in the same place.

One row per ad, up to 76 fields: employer, Norwegian organisation number, county and municipality, occupation, employment type, dates — plus, from the ad page, the apply link, the ATS vendor behind it, and the named contact person with their direct e-mail and phone.

What does this actor do?

  • 📋 Sweeps the whole live board13,475 live ads measured 2026-09-04 08:10 UTC (12,471 six hours earlier the same day — the board moves), and it is a flow, not a stock: 4,385 ads published in the last 7 days (~626/day, ~19,000/month).
  • 🏢 Puts an org number on the row — the join key to Brreg, Norway's company register, so every lead can be enriched with revenue, employee count and directors.
  • 🔌 Names the ATS — derived from the apply-link hostname: webcruiter, visma-talent, jobbnorge, teamtailor, recman, easycruit, finn.no… This is the competitive-displacement list, and onlyDirectPosted gives you the opposite: employers hiring with no recruiting software at all.
  • ☎️ Named contact, not a careers inbox — NAV's ads carry a real person: name, job title, direct phone, direct e-mail.
  • 🤖 Free AI enrichment — NAV runs its own model over every ad and publishes the result: a one-paragraph short_summary and a skill-tag list. Both come back at ~100% fill, at no extra cost.
  • 🧭 63 input options, and every filter that NAV's own API silently ignores (municipality, occupation sub-category, summer job, city, postal code) is applied over the rows here instead of pretending to work.
  • 🔁 Incremental monitoring — give a run a stateKey and it remembers every ad UUID it has delivered, so the next run only returns (and only bills) genuinely new vacancies.

Who buys this data

BuyerThe row they pay for
ATS / recruiting-software vendors (Webcruiter, Visma, Teamtailor, Jobbnorge, ReachMee)ats_vendor = the competitor's install base, with a named contact and a live hiring need. onlyDirectPosted: true = the greenfield list.
Staffing & recruitment agenciesAn employer who is hiring right now, filtered to their county and occupation, with the deadline and the person to ring.
B2B sellers into growing companies (payroll, onboarding, insurance, workwear, IT, office)A new vacancy is a growth signal; org_number makes it a CRM-ready account.
Labour-market analysts and salary benchmarksSTYRK08 / ESCO / JANZZ occupation codes, county, sector, extent and education requirements on 12,000+ live ads.
International recruiters / relocationworkLanguage: ["Engelsk"] — 2,717 live ads where Norwegian is not required.

Quick start

Every nurse vacancy in Oslo and Viken, with the org number and the contact person:

{
"occupationCategories": ["Helse og sosial"],
"occupationSubCategories": ["Sykepleier"],
"counties": ["OSLO", "AKERSHUS"],
"fetchDetails": true,
"requireOrgnr": true,
"maxItems": 500
}

Competitive displacement — everyone in Norway running Webcruiter:

{ "fetchDetails": true, "atsVendorInclude": ["webcruiter"], "maxItems": 1000 }

The greenfield list — employers hiring with no third-party ATS at all:

{ "fetchDetails": true, "onlyDirectPosted": true, "requireContactEmail": true, "maxItems": 500 }

A daily monitor that only ever bills you for new ads:

{ "counties": ["VESTLAND"], "publishedWithin": "now-3d", "stateKey": "vestland-daily", "maxItems": 0 }

Or just paste a search URL out of NAV's own site — including the municipality and occupation filters their API ignores:

{ "startUrls": ["https://arbeidsplassen.nav.no/stillinger?county=VESTLAND&municipal=VESTLAND.BERGEN&q=utvikler"] }

Output

{
"uuid": "07823086-c85c-4c8e-b73f-1b0dedbd772a",
"ad_url": "https://arbeidsplassen.nav.no/stillinger/stilling/07823086-c85c-4c8e-b73f-1b0dedbd772a",
"title": "Mulighetsrom til å påvirke veksten til Payments.",
"job_title": "Junior Sales Executive Payments",
"employer_name": "SVEA FINANS AS",
"org_number": "980130169",
"employer_sector": "Privat",
"employer_homepage": "https://www.svea.com/no/nb/start/",
"county": "OSLO", "municipal": "OSLO", "city": "OSLO",
"postal_code": "0663", "address": "Innspurten 15", "country": "NORGE",
"occupation_level1": "Salg og service",
"occupation_level2": "Salg, butikk- og varehandel",
"category_styrk08": "Salgs- og markedssjefer",
"engagement_type": "Fast", "extent": "Heltid", "position_count": 1,
"published": "2026-09-04T07:48:21+02:00",
"expires": "2026-09-12T00:00:00+02:00",
"application_due": "2026-09-12", "application_due_asap": false,
"apply_url": "https://www.finn.no/job-apply/475024396/apply",
"apply_host": "finn.no", "ats_vendor": "finn.no", "is_direct_posted": false,
"contact_name": "Morten Leknes",
"contact_title": "Avdelingsleder",
"contact_email": "morten.leknes@example.no",
"contact_phone": "(+47) 90920664",
"short_summary": "Stillingen innebærer løsningsorientert salg, prospektering, og kundekontakt…",
"ai_tags": "Betalingsløsninger; Forretningsutvikling; Kundeservice; SMB; Salg",
"ad_text": "…the full ad body, HTML stripped…",
"detail_fetched": true
}

Measured field fill

Validated offline against live bytes on 2026-09-04. These are the numbers from the actual runs, not estimates.

Listing sweep — 1,950 ads, 1,950 unique, no ad-page enrichment:

FieldFill
uuid, ad_url, title, employer_name, business_name100%
status, source, medium, reference, published, expires100%
county, country, locations, locations_count100%
occupation_level1, occupation_level2, occupations100%
short_summary (NAV's AI summary), ai_tags, ai_under18_reason100%
experience, need_drivers_license, under18100%
categories, category_styrk08, education99.9%
search_tags99.8%
application_due_raw98.3%
municipal97.3%
work_language97.2%
city, postal_code93.2%
job_title80.1%
address77.3%
application_due (a parsed date)72.0%
keywords53.7%
remote (on the listing; the ad page fills it to 100%)26.1%

Of those 1,950 ads, 26% carry no fixed deadline at all — NAV's deadline field says Snarest ("as soon as possible"), which this actor exposes as application_due_asap: true rather than throwing away. Source mix on the same sample: IMPORTAPI (pushed by an ATS) 60%, FINN 24%, Stillingsregistrering (typed straight into NAV by the employer) 16%, AMEDIA 0.4%.

With fetchDetails: true — two independent 150-ad runs, ad page fetched for each, 75 fields on the row. Column A is the offline validation run; column B is a run on the Apify platform the same day against a different slice of the board. Both are shown because the ad-page fields genuinely vary with which ads you pull — quote the lower number when you plan a campaign, not the higher one.

FieldA (offline)B (platform)Note
detail_fetched100%100%the ad page parsed on 150/150 in both runs
ad_text, position_count, engagement_type, extent, updated, remote100%100%all six are absent from the search API
ai_is_summer_job, ai_work_experience100%100%NAV's own classification
categories, category_styrk08100%99.3%
org_number100%90.0%the Brreg join key
employer_sector98.7%97.3%
is_direct_posted96.0%97.3%null only when the ad has no apply route at all
apply_url, apply_host, ats_vendor89.3%93.3%the rest apply by e-mail or have no link
search_tags100%90.7%
job_title86.0%
application_due (a parsed date)71.3%76.0%the remainder are "Snarest" → application_due_asap
employer_homepage71.3%72.7%
contacts_count / contact_name65.3% / 63.3%67.3% / 64.7%not every ad names a person
employer_description59.3%57.3%
contact_phone54.0%58.0%
contact_title53.3%56.7%
contact_email34.0%25.3%plan on one ad in four, not one in three
source_url36.0%34.0%link to the original posting off-NAV
start_date26.0%26.0%
work_hours / work_days21.3% / 18.7%17.3% / 13.3%
has_superrask_soknad10.7%6.7%the flag is simply absent on most ads
apply_email6.7%4.0%
employer_facebook / employer_linkedin6.7% / 1.3%3.3% / 0.7%employers rarely fill these in
employer_twitter, job_percentage0%0%the fields exist on NAV's object and are essentially never populated — reported honestly rather than quietly dropped

Be honest with yourself about the contact fields. About two thirds of NAV's ads name a person, a bit over half publish a direct phone, and a quarter to a third publish an e-mail (34.0% and 25.3% on the two 150-ad samples above). If your workflow needs one on every row, set requireContactEmail: true and pay only for the rows that have it — the actor drops the rest before billing.

Reliability, measured

TestResult
Transport ladder (all through Apify proxies)direct 200 · datacenter 200 · residential-NO 200 · residential-US 200 · residential-any 200 — the cheapest rung works, and it is not geo-blocked
Sustained search (varied filters and page offsets)56 / 57 usable = 98.2%
Sustained ad-page fetch20 / 20 = 100%
Contiguous paging, crawled the way the actor crawls20 pages × 100 from from=0 to 19002,000 fetched, 2,000 unique, 0 duplicates, 0.00% loss
Dedupe proof (offline)the same search fed twice → 714 rows / 714 unique; with deduplicate:false → 1,428 rows / 714 unique
Dedupe proof (on Apify, billing checked)the same NAV search URL passed twice → 9 rows delivered, job-scraped charged 9; the same run with deduplicate:false → 18 delivered, 18 charged. A duplicate ad is never billed twice unless you explicitly ask for it
Two different inputs → two different result setscounty=TROMS vs county=ROGALAND: 60 + 60 rows, overlap 0; sykepleier vs elektriker: overlap 0
Ad-page parse over a 150-ad enrichment run150 / 150 parsed
Live platform runs19 runs, 19 SUCCEEDED, 0 failed and 0 timed out (13 on build 0.1.1, 6 on 0.1.2), worst wall-clock 123.9 s against Apify's 300 s limit; chargedEventCounts equals the delivered row count on every single one
Offline validation suite48 checks, 48 pass — every filter asserted against the rows it returned, plus dedupe, incremental state, the empty-input badge preflight and the zero-match clean exit

The only residual failure mode is not NAV: the Apify proxy tunnel answers 595 on roughly 2-3% of calls. Every request is wrapped in a retry with a fresh proxy session, which converts it to ~100%.

The three things about NAV's API that break naive scrapers

They are all in the code with the measurement next to them, and they are worth knowing if you are evaluating other actors on this site:

  1. size is honoured at 100 and nowhere else. 1, 5, 10, 20, 25, 30, 40, 50, 75, 99, 101 and 200 all silently return 25 rows. A pagination loop written as from += size with size=50 therefore skips every other page — it loses half the corpus and still finishes green.
  2. The result window is from + size ≤ 10000. from=9900 is fine; from=9901 returns HTTP 400 "Pagination depth exceeds maximum allowed window". The board runs ~12,500–13,500 ads (12,471 and 13,475 measured six hours apart on 2026-09-04), so a full sweep is impossible in one query. This actor slices by county (largest slice: OSLO, 2,185) and then by occupation if a slice is still too deep, sweeps the ads located abroad through the country facet (measured today: 35 ads across 16 countries, DANMARK 5 / SVERIGE 6 / ISLAND 6 / SVEITS 4 / …) — they have no Norwegian county and would otherwise vanish — and deduplicates on ad UUID, because NAV counts a multi-county ad once per county (the county slices sum to 13,008 against a 12,460 corpus).
  3. Five filter parameters are accepted and silently ignored. municipal / municipals / municipality / kommune, occupationLevel2, summerJob, postcode and city never move the hit count, in any value shape. This actor does not pretend otherwise: those are applied over the rows after fetching, including when they appear in a startUrls link pasted from NAV's own UI.

Server-side vs client-side filters

Applied by NAV (cheap, narrows the fetch): keyword, counties, countries, occupation categories, published-within (only today / 3 days / 7 days exist), sort, employment type, full/part-time, sector, education, experience, working language, remote, driving licence, under-18, quick-apply.

Applied by this actor over the rows: municipalities, occupation sub-categories, cities, postal codes and prefixes, exact published/expiry/deadline date ranges, title include/exclude, ad-text keywords, employer include/exclude, staffing-agency blocklist, ad source, ATS vendor, direct-posted-only, summer jobs, position count, and the lead-quality gates (requireOrgnr, requireContactEmail, requireContactPhone, requireApplyLink).

Filters that can only be decided from the ad page refuse to run without fetchDetails rather than silently doing nothing.

Pricing

Pay-per-event, no subscription, no platform-usage surcharge.

EventPriceWhen it fires
job-scraped$1.20 / 1,000 adsonce per unique ad delivered — after deduplication and after your filters, so you never pay for a row you did not receive
job-detail-enriched$2.50 / 1,000 adsonly with fetchDetails: true, and only for rows that really came back enriched

A full sweep of the live board with everything on is 13,475 × $0.0037 ≈ $50; keeping it fresh on new ads only (~19,000 ads/month at the measured 4,385-per-week rate) is about $70/month. Listing-only, the whole board is $16.

Rows are charged through Apify's budget-aware push, so if you cap a run's spend you receive exactly the rows you paid for — never more delivered than billed, and never a duplicate billed twice.

Input reference — the options that matter

InputWhat it does
queryfree-text keyword, Norwegian (sykepleier, utvikler, elektriker)
counties / municipalitiescounty is server-side and cheap; municipality is client-side because NAV's API ignores it
occupationCategories / occupationSubCategoriesNAV's two-level occupation taxonomy
startUrlspaste searches straight from NAV's website; municipal= and occupationLevel2= are translated
adUrlsskip the search, fetch named ads by URL or UUID
fetchDetailsthe second surface: org number, apply link, ATS vendor, contact person, ad text
requireOrgnr / requireContactEmail / requireContactPhone / requireApplyLinklead-quality gates — filtered rows are never billed
atsVendorInclude / atsVendorExclude / onlyDirectPostedthe recruiting-stack angle
excludeStaffingAgenciesdrops bemanning / vikarbyrå / rekruttering employers
stateKeyincremental monitoring in a named key-value store
maxItemsthe hard cap on rows delivered and billed; 0 = the whole board
flattenOutputflat CRM-ready rows (default) vs nested arrays
includeRawSourceattaches NAV's untouched _source and adData objects

FAQ

Is this the same as scraping FINN.no? No. FINN is Norway's commercial classifieds site; arbeidsplassen.nav.no is the state board. A large share of NAV's ads are syndicated from FINN (source: "FINN"), but NAV also carries ads pushed by ATS vendors and ads typed directly into NAV by small employers who never advertise anywhere else. sourceExclude: ["FINN"] gives you the non-FINN half.

Do I need a NAV API token? No. This actor reads the site's own public search endpoint and its public ad pages. NAV also offers a registered, token-gated ad feed for high-volume integrators; if you have one, it is a different product and this actor does not use it.

How fresh is the data? NAV publishes continuously — 98 ads on the morning this was measured, 2,109 in the previous 3 days. publishedWithin: "now/d" plus a stateKey gives you a same-day feed.

Why does the ad page cost extra? Because it is a second HTTP request per ad. The search API simply does not contain the org number, the apply link or the contact person — measured 0.0% fill on all of them across 402 listing rows. If you only need the vacancy itself, leave fetchDetails off and pay the listing rate.

Will it return every ad on the board? Yes, with maxItems: 0 and autoSliceCorpus: true (the default). The run log prints NAV's own reported total next to the delivered-unique count and flags the delta, so you can see the coverage rather than trust it.

What happens if my filters match nothing? The run finishes successfully with zero rows and a log line telling you so. It only fails when it genuinely could not read NAV — a broken run and an empty one must not look the same.

Can I get the raw NAV objects? includeRawSource: true attaches raw_source (the Elasticsearch _source) and raw_detail (NAV's own adData). includeEmbeddingVector: true adds the 256-float compositeAdVector NAV publishes for semantic matching.

Can it run on a schedule? Yes — set a stateKey, schedule it, and each run delivers and bills only ads it has never delivered before.

  • https://arbeidsplassen.nav.no/robots.txt is User-agent: * / Disallow: — an explicit allow-all, plus a sitemap. This actor reads only public pages and the site's own unauthenticated search endpoint. No login, no token, no signature, no CAPTCHA, and nothing that circumvents an access control.
  • Requests are proxied, retried politely and rate-limited by requestDelayMs and maxConcurrency. Leave the defaults unless you have a reason.
  • Personal data. contact_name, contact_email and contact_phone are real individuals' work contact details, published by their employer in a job ad. Norway is in the EEA, so the GDPR applies: you need a lawful basis to process them, and the obligations around information, retention and erasure are yours, not this actor's. If you do not need them, leave fetchDetails off or drop the columns.
  • Fair use, respect NAV's terms, and check your own compliance position before you build a marketing list on top of this.

Built and measured 2026-09-04 against the live site. Every number on this page came from a run, not from a guess.