# Changelog of LinkedIn Jobs Scraper: Salary, Remote & New-Job Alerts (`humble-echidna/linkedin-jobs`) Actor

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

## Changelog

Versions follow MAJOR.MINOR.PATCH (`src/version.py`); Apify shows MAJOR.MINOR from `.actor/actor.json`.
Every run logs its version and records it in the `RUN_STATS` key-value record.

### 0.1.2 (2026-10-16)

- A run that returns nothing (every input bad, private, blocked or unreachable, or an empty input) now ends
  SUCCEEDED with an empty dataset and the reason as its status message and in the log, instead of FAILED. Only an
  unexpected error still fails the run. `RUN_STATS` keeps the reason as before.
- No change to output fields or price.

### 0.1.1 (2026-10-15)

- Faster with a workplace, experience or job type filter: postings load in a steady window across search pages instead
  of page by page, and near the result limit the run no longer checks one posting per page. A 50-remote-jobs run took
  12 minutes before.
- An attempt LinkedIn holds is retried from another IP after 5 s (was 10 s).

### 0.1.0 (2026-10-14)

First release.

- LinkedIn job search by keyword lines × location lines, date posted, companies (exact name, company URL or id,
  resolved through LinkedIn's company lookup), sort, or pasted linkedin.com/jobs/search URLs; up to the ~1,000 jobs
  LinkedIn lists per search, paged 10 at a time.
- Each job's posting read for description (text and HTML), salary (LinkedIn's pay box, else the description), seniority,
  employment type, industries, job function, applicants, Easy Apply vs external, and whether it still takes
  applications. The job poster's name and profile are never read.
- Workplace (remote, hybrid, on-site), experience and job type filters applied from each posting, since LinkedIn's
  signed-out search ignores its own (checked 2026-10-14). Jobs they leave out are not charged.
- "Only jobs new since my last run", remembered per search in the user's account; newest first, a run stops after two
  pages of jobs it already returned.
- A job found by several searches in a run is returned once.
- Requests go through Apify's datacenter proxy with a fresh IP per request (10 s per attempt, 3 retries); a request
  refused there is tried from a residential IP.
- Charged per job returned, through Apify's standard `apify-default-dataset-item` event; "Max jobs per run", "Max jobs
  per search" and the maximum cost per run are honoured before postings are opened.
- Failure isolation: a posting that fails or was taken down only affects itself; a search that fails only affects
  itself.

#### Source and terms (ACTOR-CHECKLIST section 6)

- **Source:** LinkedIn's signed-out job pages, the ones linkedin.com/jobs/search loads for visitors:
  `/jobs-guest/jobs/api/seeMoreJobPostings/search` (search cards), `/jobs-guest/jobs/api/jobPosting/<id>` (posting),
  `/jobs-guest/api/typeaheadHits?typeaheadType=COMPANY` (company lookup). They are not a published API.
- **robots.txt:** linkedin.com disallows every crawler (`User-agent: *` / `Disallow: /`). Read anyway under Michael's
  platform robots.txt exception of 2026-10-14 (PLAN.md "Exclusions lifted"; `make_client(robots_exempt_hosts= ["www.linkedin.com"])`), logged out only, our own User-Agent, polite rates.
- **Terms:** LinkedIn's User Agreement (https://www.linkedin.com/legal/user-agreement, read 2026-10-14): section 8.2
  ("Don'ts") forbids to "Develop, support or use software, devices, scripts, robots or any other means or processes
  (such as crawlers ..." to scrape the Services, and to "Use bots or other unauthorized automated methods to access the
  Services"; section 1.2: "This Contract applies to Members and Visitors". Michael lifted the LinkedIn exclusion
  knowing this (2026-10-14); the README says so plainly and offers takedown on request.
