Jobindex.dk Scraper avatar

Jobindex.dk Scraper

Pricing

from $1.99 / 1,000 results

Go to Apify Store
Jobindex.dk Scraper

Jobindex.dk Scraper

Turn jobindex.dk — Denmark's largest job board — into clean, structured job data. Filter by keyword, location, employment type and category, monitor for new postings, and get alerts on Slack, Telegram, Discord or webhook. Company info, salaries and apply links included.

Pricing

from $1.99 / 1,000 results

Rating

0.0

(0)

Developer

Corvuslab

Corvuslab

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

Extract job listings from jobindex.dk — Denmark's largest job portal — by keyword and location. Get clean, structured job data: titles, companies, locations (with coordinates), posting dates, application deadlines and apply links — ready to export as JSON, CSV or Excel, or pull straight into your app via the API.

Fast and reliable: this scraper reads the structured data jobindex already embeds in each search page, so it doesn't depend on a headless browser.

What does Jobindex.dk Scraper do?

Give it a search keyword (e.g. python, sygeplejerske, data scientist) and, optionally, a location, and it returns every matching job as a structured record. For each job you get the title, company and its profile/metadata, a normalised location with latitude/longitude, posting and deadline dates, and the direct application URL. Turn on Fetch job details to also pull the job summary and full description text.

New to Apify? You can sign up for free and use the included monthly platform credit to try this Actor.

Key features

  • 🔍 Keyword & location search of jobindex.dk, with pagination handled for you
  • 🧱 Structured output — clean fields, no messy HTML to post-process
  • 🏢 Company metadata included for free: name, profile URL, homepage, career page, reviews link, follower count, logo
  • 📍 Geocoded locations — city, postal code, full address, latitude & longitude
  • 📝 Optional full descriptions & salary — enable Fetch job details for the summary, full description and any stated salary (DKK)
  • 🔁 Batch searches — run several keywords in one go, automatically deduplicated
  • ♻️ Incremental mode — recurring runs return only what changed (new / updated / expired jobs)
  • 🔔 Notifications — send a run summary to Telegram, Slack, Discord or any webhook
  • 🗓️ Dates & deadlines — posted date, last-seen date, application deadline
  • ⏱️ Recency control — sort by newest first and/or limit to jobs from the last N days
  • 🌍 Remote flag — see which jobs allow working from home
  • 🤖 Compact & Markdown modes — lean, LLM-friendly output when you need it
  • 💸 Pay per result — only pay for what you actually scrape

How to use Jobindex.dk Scraper (no code)

  1. Click Try for free / open the Actor in Apify Console.
  2. Enter a keyword in the Search query field (e.g. python).
  3. (Optional) Add a Location such as København or Aarhus.
  4. Set Max results per query (default 25).
  5. (Optional) Enable Fetch job details to include full descriptions.
  6. Click Start. When the run finishes, preview the results and export them as JSON, CSV or Excel from the Output tab.

You can also run it on a schedule (e.g. every morning) using Apify Schedules, or connect it to Google Sheets, Zapier, Make and others via Apify integrations.

Input

FieldTypeDefaultDescription
querystringA search query (e.g. python, sygeplejerske). Supports search operators — see below.
queriesarrayRun several separate searches in one run. Results are deduplicated by job ID.
locationstringOptional city/area filter (e.g. København, Aarhus).
employmentTypearrayFilter by employment type (multi-select). See Advanced filters.
workPlacearrayFilter by workplace: onsite, remote, hybrid.
workHoursarrayFilter by fulltime / parttime.
subCategoriesarrayFilter by one or more job categories. See Advanced filters.
maxResultsinteger25Max jobs per query. 0 = unlimited (hard-capped at 5000).
sortBystringrelevanceOrder results by relevance or by date (newest first).
maxAgeDaysintegerOnly include jobs posted within the last N days.
fetchJobDetailbooleanfalseAlso open each job's page for a summary and full description text.
descriptionFormatstringallWhich description formats to include: all, text, html, markdown.
descriptionMaxLengthinteger0Truncate description/summary to N characters (0 = no limit).
compactbooleanfalseReturn only core fields — handy for AI/agent workflows.
excludeEmptyFieldsbooleanfalseRemove null/empty fields from each record.
incrementalModebooleanfalseOn recurring runs, only return jobs that changed. See Incremental mode.
emitUnchangedbooleanfalseIn incremental mode, also return jobs with no changes (UNCHANGED).
emitExpiredbooleanfalseIn incremental mode, also return jobs that disappeared (EXPIRED).
skipRepostsbooleanfalseIn incremental mode, suppress re-posted ads (a new listing matching an expired one).
stateKeystringautoIdentifier for incremental state. Blank = derived from your search settings.
telegramToken / telegramChatIdstringSend a run summary to Telegram. See Notifications.
slackWebhookUrlstringPost a run summary to a Slack channel.
discordWebhookUrlstringPost a run summary to a Discord channel.
webhookUrlstringPOST {metadata, items} to any URL after each run.
webhookHeadersobjectCustom HTTP headers for the generic webhook.
notificationLimitinteger10Max jobs listed per chat message (1–20).
notifyOnlyChangesbooleanfalseWith incremental mode, only notify about new/updated jobs.

Example input

{
"query": "python",
"location": "København",
"maxResults": 50,
"fetchJobDetail": true
}

Batch search across several keywords:

{
"queries": ["data scientist", "machine learning", "data engineer"],
"maxResults": 100
}

Search operators

The query (and each entry in queries) supports jobindex's search operators:

OperatorExampleMeaning
spacepython aiMatch any of the words (broad)
++python +aiRequire every + word (AND) — only jobs matching both
-python -seniorExclude jobs containing the word
"...""python developer"Match the exact phrase

Tip: prefix every term with + to require all of them. python ai is an "either" search; +python +ai returns only jobs that mention both.

query vs queries: queries runs each entry as its own search and merges the results (a union). To require several words in one search, use the + operator in a single query, e.g. +python +ai.

Advanced filters

All filters are multi-select — pick one or more values; leaving a filter empty means "any". Within a filter, multiple values broaden the search (OR).

FilterAccepted values
employmentTypepermanent, temporary, student, apprentice, graduate, internship, flexJob, volunteer, youth, freelance, hourly
workPlaceonsite, remote, hybrid — fully remote jobs are uncommon on jobindex; hybrid is much more frequent
workHoursfulltime, parttime
subCategories80+ job categories, e.g. Software development & programming, IT operations & support, Retail, Nurse & midwife, Marketing, Finance & accounting, Research, Construction & civil works — see the dropdown in the Console for the full list
{
"query": "developer",
"location": "København",
"employmentType": ["permanent", "graduate"],
"workPlace": ["hybrid"],
"workHours": ["fulltime"],
"subCategories": ["Software development & programming"]
}

Incremental mode (change tracking)

Turn a one-off scrape into a job monitor. Enable incrementalMode and the Actor remembers what it saw on previous runs, so each recurring run returns only the jobs that changed — perfect for scheduled runs and alerts.

Every record gets a changeType field:

changeTypeMeaningReturned by default?
NEWSeen for the first time✅ Yes
UPDATEDContent changed since last run (title, deadline, location…)✅ Yes
REAPPEAREDWas gone, now back on the board✅ Yes
UNCHANGEDNo change since last runOnly if emitUnchanged
EXPIREDDisappeared since last runOnly if emitExpired

How it works:

  • First run builds a baseline — every job is NEW and the state is saved. Subsequent runs emit only the differences.
  • State is remembered between runs and keyed by stateKey. Leave it blank to derive one automatically from your search settings, or set a fixed value to keep one monitor's state stable even if you tweak the query. Use distinct keys to run several independent monitors.
  • Reposts: a brand-new listing whose content matches a previously expired job is flagged with isRepost, repostOfId and repostDetectedAt. Set skipReposts to drop them.
  • Expiry needs a complete scrape. To reliably detect EXPIRED jobs, set Max results to 0 (unlimited). If maxResults cuts the results short, the jobs beyond the cut-off can't be told apart from vanished ones, so expiry detection is safely skipped for that run.
{
"query": "python developer",
"location": "København",
"incrementalMode": true,
"emitExpired": true,
"maxResults": 0
}

Pair this with Apify Schedules (e.g. run every morning) and notifications (below) to get alerted only about new and changed jobs.

Notifications

Get a summary of each run pushed straight to your channels — great with incremental mode and a schedule. All channels are optional; configure any combination.

ChannelWhat you provideWhere it posts
TelegramtelegramToken (from @BotFather) + telegramChatIdYour chat/channel
SlackslackWebhookUrl (an incoming webhook)That webhook's channel
DiscorddiscordWebhookUrl (a channel webhook)That channel
WebhookwebhookUrl (+ optional webhookHeaders)A JSON POST to your URL
  • Chat channels (Telegram/Slack/Discord) receive a readable digest of up to notificationLimit jobs (1–20), each tagged with its changeType in incremental mode. They only fire when there's something to report.
  • The generic webhook receives a JSON { "metadata": {…}, "items": [...] } body after every run (even zero results), so you can wire the Actor into any tool. Add webhookHeaders (e.g. an Authorization header) if your endpoint needs them.
  • notifyOnlyChanges (with incremental mode) limits alerts to NEW and UPDATED jobs — no pings for unchanged listings.

Tokens and webhook URLs are stored as secret inputs (encrypted, hidden in the UI and logs). WhatsApp isn't supported out of the box — bridge to it via the generic webhook if you need it.

{
"query": "python developer",
"incrementalMode": true,
"notifyOnlyChanges": true,
"maxResults": 0,
"slackWebhookUrl": "https://hooks.slack.com/services/…"
}

Output

Each item in the dataset is one job. Every record includes the core job fields (title, url, applyUrl, ids and status flags), company metadata (name, profile URL, homepage, career page, reviews link, followers, logo), a geocoded location (city, postal code, address, latitude/longitude), and dates & deadlines. Ads with a recruitment video add a few video fields, and enabling Fetch job details adds the job summary, full description (as text, HTML and/or Markdown) and any stated salary (salaryMin / salaryMax / salaryPeriod in DKK — often empty, since Danish ads rarely list pay). In incremental mode each record also carries a changeType (and repost fields). The exact field list and types are in the Console's Output tab; here's a full example record:

{
"jobId": "h1674866",
"title": "Python Software Developer",
"company": "Minerva Imaging ApS",
"companyId": 58277,
"companyUrl": "https://www.jobindex.dk/virksomhed/58277/minerva-imaging-aps",
"companyHomepage": "https://www.minervaimaging.com",
"companyFollowers": 103,
"companyLogo": "https://www.jobindex.dk/img/logo/MinervaImaging_logo.png",
"companyCareerUrl": "https://www.minervaimaging.com/careers",
"companyRatingUrl": "https://www.jobindex.dk/virksomhed/58277/minerva-imaging-aps#evalueringer",
"location": "Ølstykke",
"city": "Ølstykke",
"zipCode": "3650",
"address": "Lyshøjvej 21, 3650 Ølstykke",
"latitude": 55.7683518,
"longitude": 12.1414453,
"isRemote": false,
"url": "https://www.jobindex.dk/vis-job/h1674866",
"applyUrl": "https://minervaimaging.career.emply.com/apply/python-software-developer/kjb2r6/en",
"quickApplyAvailable": false,
"postedDate": "2026-06-16",
"lastSeenDate": "2026-07-13",
"deadline": "2026-07-31T21:59:59Z",
"deadlineAsap": false,
"hasVideo": true,
"videoThumbnail": "https://www.jobindex.dk/img/logo/MinervaImaging_logo.png",
"videoUrl": "https://www.jobindex.dk/c?t=h1674866&ctx=w&...",
"searchQuery": "python",
"scrapedAt": "2026-06-18T20:37:58Z",
"summary": "Are you passionate about robust software design …",
"description": "Full job description text … (only with Fetch job details enabled)",
"salaryMin": 40000,
"salaryMax": 48000,
"salaryPeriod": "monthly",
"salaryCurrency": "DKK"
}

Notes

  • Some jobs are hosted on external career sites, so the full description may be empty — applyUrl always links to the live ad.
  • With compact enabled, each record is reduced to: jobId, title, company, location, isRemote, postedDate, deadline, url, applyUrl, searchQuery.
  • With excludeEmptyFields enabled, null/empty fields are omitted entirely.

Using the API

You can run this Actor from your own code. Example with the Apify Python client:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_API_TOKEN>")
run_input = {
"query": "software engineer",
"location": "København",
"maxResults": 25,
}
run = client.actor("corvuslab/jobindex-scraper").call(run_input=run_input)
print("Results: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item)

The Actor also works with the JavaScript/TypeScript client, the Apify CLI and the REST API.

Pricing

This Actor uses the pay-per-event pricing model:

EventPrice
Run start$0.01
Per job result$0.002

Example costs:

ResultsCost
10$0.03
25$0.06
100$0.21
500$1.01

You only pay for what you scrape, and runs respect your account's charging limit.

Use cases

  • Job market research — track demand for roles, skills or industries in Denmark.
  • Recruitment & sourcing — monitor new openings and competitor hiring.
  • Job board aggregation — feed listings into your own site, ATS or CRM.
  • AI / LLM pipelines — supply clean, structured job data to your models or agents.
  • Location-based alerts — watch for jobs in a specific city or area.
  • Company analysis — follow which companies are actively hiring.

FAQ

How many results can I get? Up to 5000 per query. Set maxResults to 0 for "as many as available" (capped at 5000).

Can I search several keywords at once? Yes — use the queries list. Results are deduplicated across all queries.

Can I get full job descriptions? Yes — enable Fetch job details. Note that ads hosted on external career sites may not expose full text.

Does it extract salary? When Fetch job details is on, the Actor pulls any salary stated in the ad (salaryMin, salaryMax, salaryPeriod in DKK). Most Danish listings don't publish a salary, so these fields are often empty — that's normal.

Can I run it automatically? Yes — use Apify Schedules to run it on a recurring basis, and Apify integrations (Google Sheets, Zapier, Make, webhooks) to deliver the results. Combine this with incremental mode so each scheduled run only returns new and changed jobs.

How do I get only new jobs on each run? Enable incrementalMode. The first run saves a baseline; after that, runs return only NEW, UPDATED and REAPPEARED jobs. Set maxResults to 0 and emitExpired to also track jobs that disappear.

Can it notify me when new jobs appear? Yes — add a Telegram, Slack, Discord or generic webhook target under Notifications, and combine with incremental mode + notifyOnlyChanges so you only get pinged about new and updated jobs. WhatsApp isn't built in; use the generic webhook to bridge to it.

Is scraping jobindex.dk legal? This Actor collects publicly available listing data. You are responsible for using it in line with jobindex.dk's terms and applicable laws (including GDPR). Scrape responsibly.

Found a bug or need a feature? Open an issue on the Actor's page — feedback is welcome.