# Changelog of LinkedIn Jobs Scraper (Pay-Per-Event) (`prodiger/linkedin-jobs-scraper`) Actor

- **URL**: https://apify.com/prodiger/linkedin-jobs-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/prodiger/linkedin-jobs-scraper.md

## Changelog

### 0.1.0 — 2026-07-27

Initial release. Pay-per-event LinkedIn Jobs scraper, a drop-in for `automation-lab/linkedin-jobs-scraper` at identical pricing:

- **Input (drop-in field names):** `searchQuery` (required), `location`, `maxJobs` (1–1000), `jobType` (all/F/P/C/T/I), `experienceLevel` (all/1–6), `workplaceType` (all/1/2/3), `datePosted` (all/r86400/r604800/r2592000), `sortBy` (R/DD), `scrapeJobDetails`, `maxRequestRetries`, `customMapFunction`, `proxyConfiguration`. `searchQuery`/`location` also accept a list (query × location cross-product) when called via API.
- **Output (drop-in field names):** `id`, `title`, `url`, `companyName`, `companyLinkedinUrl`, `companyLogo`, `location`, `postedAt`, `salary`, `applicantsCount`, `workplaceType`, `descriptionHtml`, `descriptionText`, `seniorityLevel`, `employmentType`, `jobFunction`, `industries`, `applyUrl`, `benefits`, `scrapedAt`. Additive enrichments: `postedDate` (machine-readable YYYY-MM-DD), `searchQuery`, `searchLocation`.
- **HTTP-only, no login:** scrapes LinkedIn's public guest API — `…/jobs-guest/jobs/api/seeMoreJobPostings/search` for listings and `…/jobs-guest/jobs/api/jobPosting/{id}` for details — with `got-scraping` (HTTP/1.1 + generated Chrome headers to avoid the blocked HTTP/2 fingerprint) and `cheerio` parsing. No headless browser; runs on 512 MB with datacenter proxy.
- **Filters are server-side:** `jobType`, `experienceLevel`, `workplaceType`, `datePosted` and `sortBy` map 1:1 to LinkedIn guest-search query params (`f_JT`, `f_E`, `f_WT`, `f_TPR`, `sortBy`).
- **Pricing:** matches the reference — `actor_start` $0.005 + `job_scraped` $0.00058 ($0.58/1,000, ~$0.585 per 1,000 jobs). `job_scraped` is charged only after `pushData` succeeds; `actor_start` fires at most once per logical run (migration-safe). Higher Apify tiers get a lower per-job rate automatically.
- **Run-level deduplication** by job ID across seeds — overlapping searches are billed at most once per job. Pagination advances `start` by the raw served-card count (not the deduped count) and stops on a short/empty page or when a full page yields no new IDs.
- **Migration-safe state:** dedup set, per-seed emitted counts, and per-seed search offsets are persisted via `Actor.useState`, so an Apify migration resumes where it left off instead of re-scraping and re-billing already-written rows. A job id reserved for a write that then fails is released so an overlapping seed can retry it.
- **Resilience:** per-request retry with exponential backoff and fresh-proxy rotation; 404/410 treated as permanent; a failed job-detail fetch still emits the listing row; errors recorded to a sidecar key-value store entry so one bad request never aborts the run. `Actor.on('aborting')` flushes state and exits within 1s so user cost ceilings are honored.
