# Changelog of LinkedIn Hiring Signals — Company Hiring Intent & Velocity (`foxlabs/linkedin-hiring-signals`) Actor

- **URL**: https://apify.com/foxlabs/linkedin-hiring-signals/changelog.md
- **Full Actor documentation**: https://apify.com/foxlabs/linkedin-hiring-signals.md

## Changelog

### 0.1.19 — 2026-09-24 — jobs counted worldwide (were United States only)

- **Hiring signals now cover the company's jobs worldwide.** The job search was sent without a location, and LinkedIn then returns a company's United States jobs only, whatever the proxy's country (Stripe: 625 US jobs vs 942 worldwide, 2026-09-24). Every count — `openJobCount`, `postedLast7d` / `postedLast30d` / `postedLast90d`, `hiringMomentum`, `topDepartments`, `topLocations` and the `jobs` list — therefore described US hiring only. It now covers all of the company's public jobs: Stripe reads 942 roles, the same as LinkedIn's own count.
- **New optional input `location`** counts only one city, region or country — "United States" gives the previous scope. `sources.hiringSignals` names the location used.
- Counts rise for companies that hire outside the US; with the default `maxJobsPerCompany` of 200, big employers reach the cap (`openJobCountIsCapped`) sooner.
- No pricing change.
- Build 0.1.20 changed only the README (a fresh worldwide sample). Build 0.1.21 removes four stray log files that 0.1.20 accidentally included in the source; no code, output or pricing change.

### 0.1.17 — 2026-09-10 — failed lookups become free (per-record billing) + README corrected

- **From 25 September 2026 you pay only for complete company signals.** From that date the Actor charges a new `company-signal` event for each complete company row instead of the per-dataset-item event, at the same price ($0.03). Every row that carries an `error` field — the company page could not be loaded, the URL was malformed, the company id was missing, or LinkedIn refused the job search — is pushed without a charge.
- **Timing:** Apify applies pricing changes after a 14-day notice. The code for the switch ships in this version and detects the new pricing by itself; until 25 September 2026 billing is exactly as before.
- **Fix — proxy sessions.** The session-id cleanup had lost a backslash (`[^w.~]` instead of `[^\w.~]`), so every request of a run shared one residential session (`_`). Each company now gets its own Apify Proxy session (`c_<slug>_<hash>_<n>`) for its page, job search and legal pages. When LinkedIn refuses a request (HTTP 403, 999, a 429 that survives one back-off, or an empty page), the session is retired and the request is retried from a fresh one — at most 3 sessions per company and 10 new sessions per run; every rotation is logged and the run's last log line counts them. A 403 from the company's own website is no longer retried.
- **Fix — job functions.** Title keywords now match word stems, so "Product Designer" counts as Design, "Product Marketing Manager" as Marketing, "Recruiter" as People & HR, "Data Scientist" as Data & AI and "Cybersecurity" as Security. A function word right before "engineer…" or "architect…" decides the department: pre-sales titles ("Sales Engineer", "Sales Engineering", "Solutions Engineer / Architect", "Pre-sales Engineer") count as Sales, "Marketing Engineer" as Marketing, "Support Engineer" as Customer, "Data / ML / AI Engineer" as Data & AI and "Security Engineer" as Security; any other "…Engineer" is Engineering. On the same 400 real titles, `Other` fell from 84 to 54 (Stripe) and from 59 to 37 (Datadog), all 21 of Stripe's marketing titles now count as Marketing (before: 1), and Datadog's Sales count rose from 38 to 71.
- **Fix — a refused job search is no longer a zero.** When LinkedIn refuses a job-search page after 4 attempts, the row gets `hiringSignalsCollected: false`, `openJobCount`, `isHiring`, `hiringMomentum`, `postedLast7d`, `postedLast30d` and `postedLast90d` as `null`, no job list, and an `error`; it is not charged. Before, refused pages were skipped, which reported fewer roles, 0 roles or "not-hiring". Every refused page is logged with its last HTTP status.
- **Fix — malformed URLs.** A company URL with a broken %-escape used to stop the whole run ("URI malformed"). It now becomes one row with `companyInput` and `error: "malformed company URL (broken %-escape)"`, is not charged, and the other companies still run.
- **Fix — rows without a company id.** When the LinkedIn company id cannot be read from the page, the job search cannot be queried: the row (`hiringSignalsCollected: false` and a `note`) now also carries `error` and is not charged.
- **Output changes:** new field `companyInput`; `error` now also marks incomplete rows; the hiring counts of a refused job search are `null` instead of numbers; `topDepartments` values shift as described above. No field was renamed or removed.
- **README corrected.** The 2026-09-07 README documented inputs this Actor does not have (`queries`, `maxResultsPerQuery`, `maxConcurrency`, `includeRaw`) and used a placeholder example with an undefined value, while the real inputs (`maxJobsPerCompany`, `maxResults`, `includeJobs`, `enrichCompany`, `includeOwnership`) were missing. It also claimed name or registry-ID search (the Actor takes LinkedIn slugs or company URLs), a "registry" source with "formation / status monitoring" (the source is public LinkedIn pages), a `query` field on every row (there is none), "Primary industry (NACE)" (it is LinkedIn's industry label), status, legal form, formation date and registry contact fields (not in the output), that individual roles need another Actor (this one returns them in `jobs`), troubleshooting built on name matching and `maxResultsPerQuery`, and "failed lookups are never billed" (they were billed as dataset items; they are free from 25 September 2026). The README now lists the real inputs, fields, pricing and limits.

### 0.1 — 2026-09-07

- **Enabled AI-agent payments (x402) + rebuilt the README to the full standard** (What-is / when, AI-agents + x402 agentic payments + MCP, Overview, Features, Use cases, Integration, FAQ, Troubleshooting, Support & contact).

### 0.0

- Initial release: hiring signals from public LinkedIn job listings, looked up by LinkedIn company slug or URL. *(Corrected 2026-09-10 — this line said "by name or registry ID".)*
