# Sweden Jobs Aggregator (`mrdoe/sweden-jobs-aggregator`) Actor

Aggregate Swedish job listings from Platsbanken, Academic Work, JobbSafari, Randstad, StudentConsulting, Jobbland, Ledigajobb, TNG, Lernia, Poolia, Manpower, Experis, and Jefferson Wells. Extract job details, companies, locations, salaries, applications, and public recruiter contacts.

- **URL**: https://apify.com/mrdoe/sweden-jobs-aggregator.md
- **Developed by:** [MrDoe](https://apify.com/mrdoe) (community)
- **Categories:** Jobs, Lead generation, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 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

## Sweden Jobs Aggregator

Scrape and normalize Swedish job listings from multiple job boards/recruiters into one unified schema - job details, company info, location, salary when available, application URLs, and publicly available recruitment contact information.

### Supported sources

| Source | Domain / access |
| --- | --- |
| Platsbanken (Arbetsförmedlingen) | Public JobTech API (`jobsearch.api.jobtechdev.se`) |
| Academic Work | academicwork.se |
| JobbSafari | jobbsafari.se |
| Randstad | randstad.se |
| StudentConsulting | studentconsulting.com |
| Jobbland | jobbland.se |
| Ledigajobb.se | ledigajobb.se |
| TNG | tng.se |
| Lernia | lernia.se |
| Poolia | Public WordPress API (`poolia.se/wp-json/custom/v1/poolia/all_jobs`) |
| Manpower | Public search API (`manpower.se/api/services/Jobs/searchjobs`) |
| Experis | Same ManpowerGroup API, on experis.se |
| Jefferson Wells | Same ManpowerGroup API, on jeffersonwells.se |

The source is auto-detected from each start URL's domain. Each of the original five sources reuses the extraction approach of its dedicated single-source Actor (platsbanken-scraper, academicwork-scraper, jobbsafari-scraper, randstad-scraper, studentconsulting-scraper).

**Platsbanken, Poolia, Manpower, Experis, and Jefferson Wells work differently**: instead of crawling HTML, these talk to a public JSON API directly. For Platsbanken, the start URL should be a JobTech API search URL, e.g. `https://jobsearch.api.jobtechdev.se/search?q=utvecklare` or `...&municipality=0180` (Arbetsförmedlingen's official open-data endpoint). For the other four, pass their normal human-facing listing page (e.g. `https://www.manpower.se/sv/lediga-jobb`) - the module derives the API host from it and paginates the API itself, no HTML rendering involved. Because these run before the HTML crawler and consume the shared `maxItems` budget first, a small `maxItems` combined with any of these five URLs will use up the budget before other sources get a turn.

**Evaluated and skipped**:

- **Adecco** (adecco.se → adecco.com/sv-se): `robots.txt` explicitly disallows `/jobs/`, `/job-apply/`, `/job-results/`, and `/en-us/job/`; independent of that, the job search itself is served entirely by a heavily code-split client-side SPA (`candidate.adecco.com`) with no discoverable public REST/GraphQL endpoint from static inspection - skipped.
- **Metrojobb** (metrojobb.se): the entire site is a "coming soon" placeholder page with zero functional content - nothing to scrape.
- **LinkedIn** (linkedin.com/jobs): the public guest search page renders real listings for page 1 (~25 results) without login, and individual job posting pages load too, but requesting page 2 (`start=` param) silently redirects back to page 1 - pagination beyond the first page requires signing in, so it isn't reliably scrapable at any meaningful scale.
- **Indeed** (se.indeed.com): the first search request returns 200 with real job cards, but the very next request gets redirected to `secure.indeed.com/auth`, a Cloudflare-fronted login wall - confirmed login-wall gate on the second request.
- **Glassdoor** (glassdoor.com): a direct request returns HTTP 403 immediately - confirmed bot-challenge/block, not investigated further.

Not affiliated with or endorsed by any of the above. Only publicly visible data is collected - no login, CAPTCHA bypass, or access-control circumvention is used.

### Input

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `startUrls` | array | `https://jobsearch.api.jobtechdev.se/search?q=utvecklare` | Listing/search URLs from any supported source. |
| `maxItems` | integer | `10` | Maximum jobs across **all** start URLs combined. `0` = unlimited. |
| `proxyConfiguration` | object | `{ "useApifyProxy": true }` | Apify Proxy configuration. |

Note: API-based sources (Platsbanken, Poolia, Manpower, Experis, Jefferson Wells) are processed first, sequentially, since each is a direct paginated API call rather than a crawl - see "Supported sources" above for how that affects a small `maxItems`.

### Output

**Job**: `jobId`, `title`, `description`, `employmentType`, `jobType`, `seniority`, `category`, `skills`, `requirements`

**Company**: `companyName`, `companyDescription`, `companyUrl`, `companyLogo`

**Location**: `location`, `city`, `municipality`, `county`, `country`, `remote`, `hybrid`

**Compensation**: `salary`, `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod` - only populated when a real, source-published figure exists. Several sources show a market-rate *estimate* instead of an actually-posted salary (JobbSafari's "salary" field, Jobbland's "Lön" box explicitly labelled as an estimate, Ledigajobb's `baseSalary` which is always an empty currency shell with no value) - `salary` is intentionally left `null` for those rather than presenting an estimate as a real figure.

**Application**: `url`, `applicationUrl`, `deadline`, `postedDate`, `updatedAt`

**Recruitment lead**: `recruiterName`, `recruiterTitle`, `recruiterEmail`, `recruiterPhone`, `recruiterUrl` - only publicly displayed professional recruitment contact info (e.g. Platsbanken's `application_contacts`, Academic Work's listed consultant manager), never private personal information

**Source**: `source`, `sourceUrl`, `scrapedAt`

Fields are `null` (or `[]` for arrays) when the source doesn't publish that value - nothing is guessed or fabricated. Coverage varies significantly by source: Platsbanken (a government open-data feed) publishes the richest structured data including named application contacts; the others expose company name, location, and posting dates reliably, with recruiter contact details only when the employer chose to publish them.

Export results as JSON, CSV, Excel, XML, or via the [Apify API](https://docs.apify.com/api/v2) once a run finishes.

### FAQ

**Is this legal?** Only publicly available job listing data is collected. Not affiliated with or endorsed by any of the supported sites. Respect each site's Terms of Service and GDPR.

**Does every listing have salary or recruiter contact info?** No - both are only populated when the source publicly publishes them.

**Can I add more job boards?** Not yet - this Actor currently supports the sources listed above. Unsupported start URLs are skipped with a warning rather than failing the run.

Found a bug or have a feature request? Use the Issues tab on this Actor's Apify Store page.

# Actor input Schema

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

Listing/search page URLs from Academic Work, JobbSafari, Randstad, StudentConsulting, Jobbland, Ledigajobb.se, TNG, Lernia, Poolia, Manpower, Experis, or Jefferson Wells, or a JobTech API search URL for Platsbanken (e.g. https://jobsearch.api.jobtechdev.se/search?q=utvecklare). The source is auto-detected from each URL's domain.

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

Maximum number of job listings to scrape across all start URLs combined. Set to 0 for unlimited.

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

Proxy settings for the run.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://jobsearch.api.jobtechdev.se/search?q=utvecklare"
    }
  ],
  "maxItems": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `overview` (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 = {
    "startUrls": [
        {
            "url": "https://jobsearch.api.jobtechdev.se/search?q=utvecklare"
        }
    ],
    "maxItems": 10,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("mrdoe/sweden-jobs-aggregator").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 = {
    "startUrls": [{ "url": "https://jobsearch.api.jobtechdev.se/search?q=utvecklare" }],
    "maxItems": 10,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("mrdoe/sweden-jobs-aggregator").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 '{
  "startUrls": [
    {
      "url": "https://jobsearch.api.jobtechdev.se/search?q=utvecklare"
    }
  ],
  "maxItems": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call mrdoe/sweden-jobs-aggregator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mrdoe/sweden-jobs-aggregator"
        }
    }
}

```

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/d4T9ybKX9dsUSZoyc/builds/yiXspzT76wEMEH96L/openapi.json
