LinkedIn Company Jobs Scraper — Jobs by Company, No Cookies
Pricing
from $0.64 / 1,000 jobs
LinkedIn Company Jobs Scraper — Jobs by Company, No Cookies
Give it a company - LinkedIn URL, website, name or numeric ID - and get every role it has open on LinkedIn right now: title, location, the exact posting date and a link. Turn on trackChanges to see which roles opened and closed since the last run. No login, no cookies.
Pricing
from $0.64 / 1,000 jobs
Rating
0.0
(0)
Developer
Northbell
Maintained by CommunityActor stats
0
Bookmarked
16
Total users
3
Monthly active users
3 hours ago
Last modified
Categories
Share
LinkedIn Jobs by Company Scraper
Give it a company. Get every role that company has open right now.
Try it now — the input is already filled in. Press Start: Stripe's job postings from the past week — about 250, for about $0.22, in 40 seconds to 2½ minutes (the last five runs of this example; longer when LinkedIn asks it to slow down).
For exact matches, give the LinkedIn URL or the company's website rather than a bare name. A name is matched by guessing; every company row says how it was found (resolvedBy) and how sure that is (matchConfidence: high, medium, low), and a low match is never charged: its company row and jobs are still returned, marked low, so you can check them; Only confident matches skips collecting them and gives a short free unconfirmed row instead.
title | location | postedOn | activelyHiring |
|---|---|---|---|
| Staff Product Manager, Agentic Commerce | San Francisco, CA | 2026-10-15 | true |
| Engineering Manager, Machine Learning - Credit Risk | Seattle, WA | 2026-10-17 | true |
| Abuse Research Engineer | Atlanta, GA | 2026-10-11 | true |
Plus one summary row for the company: openJobs (246), byLocation (San Francisco 61, New York 51, United States 46, Chicago 40…) and collectionComplete — false here, because the form stops at 30 requests so a first run stays short; raise Request ceiling per company for the whole roster. LinkedIn shows one country per search: left empty it is the US for a US company like Stripe, so set Filter by location for another country.
Run it on a schedule with Track what changed since last run on, and each run also reports the roles that opened and closed since the previous one.
$0.01 per company plus $0.80 per 1,000 jobs — 10 companies with 50 open roles each cost $0.51 including the run start.
Most LinkedIn job scrapers take a search query. This one takes a company — in whatever form your list has it:
linkedin.com/company/stripe, stripe.com or just Stripe. A website is matched to the LinkedIn page whose own
website is the same, and companies LinkedIn splits over several IDs (Johnson & Johnson has five) are searched as one.
No login. No cookies. No account. Public pages only.
Call it from a script or a schedule
$curl -X POST "https://api.apify.com/v2/acts/northbell~linkedin-company-jobs-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" -H "Content-Type: application/json" -d '{"companies":["stripe"],"datePosted":"past-week"}'
The response is the rows themselves (a JSON array). To watch the same companies, save the input as a task in Apify Console and add a daily Schedule; with Track what changed since last run on, each run reports the roles opened and closed since the previous one. n8n, Make and Zapier run it through their Apify app with the same input, and an MCP client can add https://mcp.apify.com?tools=northbell/linkedin-company-jobs-scraper.
What you get
One row per open role:
| Field | Meaning |
|---|---|
title, location | The role and where it is |
postedOn | The real posting date, not "3 days ago" |
activelyHiring | Whether LinkedIn flags the company as actively hiring |
jobUrl | Direct link |
And one summary row per company: openJobs, byLocation, the resolved companyId, and
collectionComplete (see below).
When a company comes back with 0 jobs, its row says why in note. LinkedIn dates a job by when it was
first posted, so a company that is hiring but posted nothing new this week returns 0 with Posted within: Past week
(on 2026-10-09 HubSpot had 0 jobs from the past week, 12 from the past month and 30 or more at any date). The Actor then
checks once without the date filter and writes, for example,
No job posted in the past week. ... this company has 10 or more open jobs posted earlier: set "Posted within" to "Any time" to get them.Run it again and again
- On a schedule — save your input as a task and add a Schedule: the same companies every morning. Send each run to Google Sheets, Slack or email with an integration on the task.
- Watch for changes — Turn on Track what changed since last run: each run reports the roles opened and closed since the previous one (when both runs read the same filters in full).
- In bulk — Put every company in Companies in one run.
How complete is the list?
LinkedIn's public job listing does not paginate the way you would expect. Asking for
start=20 does not return "results 21–30" — it returns a different random sample. Fetch
the same company twice with naive paging and 40–60% of the job IDs differ. Offsets of 1000
or more are rejected outright.
So a naive scrape of a large company returns a sample, not the roster. Measured on a company with 880 open roles: naive paging returned 660 — a quarter of the roles silently missing, with no indication anything was wrong.
This Actor keeps sampling and measures its own coverage. Splitting the requests into two independent halves and comparing the overlap gives an estimate of the true total — the same mark-and-recapture method used to count fish in a lake. It keeps going until the estimated coverage reaches your target.
Every company row carries the result:
| Field | Meaning |
|---|---|
openJobs | Roles actually collected |
estimatedTotal | Estimated true number of open roles |
coverage | Fraction collected (e.g. 1.0) |
estimatedMissing | Roles believed still unseen |
requestsUsed | What it cost to get there |
Verified against that 880-role company: 880 collected, 880 estimated, coverage 1.0, in 452 requests.
Optional: what changed since last run
Closed roles vanish from LinkedIn and leave nothing behind, so "what disappeared" cannot be
reconstructed after the fact — only recorded. Turn on trackChanges and each run compares
against the last.
This is only reported when the comparison is sound. Two runs, both at full coverage, sixty seconds apart, on that same 880-role company:
opened: 0 closed: 0 changeMarginOfError: 0
Which is the correct answer — nothing changed in a minute. An earlier version of this Actor
reported "170 opened, 159 closed" for exactly that case, because it was comparing two
different samples. It now refuses to answer unless coverage is high, and reports
changeMarginOfError so you can see how much of any number could be measurement noise.
Opened/closed come back as null, with a reason, when: it is the first run, coverage did not
reach the target, or you changed the filters between runs (which changes which roles were in
scope). Hiring pace additionally needs 7 days of observation.
With a datePosted filter (past 24 hours, week or month), a role that simply got older than the
window also leaves the list. Those are not counted as closed: they come back separately as
agedOutOfWindowSinceLastRun on the company row, and only roles still inside the window that
disappeared count as closedSinceLastRun. (The first run after this change reports opened roles
but leaves closed null, because the earlier run did not keep posting dates.)
Cost of certainty: full coverage of a 880-role company took ~450 requests — about 15
minutes at the default 30 requests per minute (about 8 at 60). You are charged per job returned, not per request, so this costs you time rather
than money. Set targetCoverage lower (default 0.99) if you would rather have speed.
Input
{"companies": ["https://www.linkedin.com/company/stripe/","anthropicresearch","1035"],"maxJobsPerCompany": 1000,"location": "United States","datePosted": "past-week"}
companies— company URL, slug, or numeric ID, or just the company website (stripe.com) or name (Scale AI). A website is matched to the LinkedIn page whose own website is the same, and the company row says so indomainMatch(true,same-namefor stripe.com vs stripe.dev,falsewhen only a same-named page was found); names that had to be turned into a guess carryguessedFrom. A name with a legal suffix (Stripe, Inc.,Deutsche Bank AG) is also tried without it, and that page is used only when its company name matches what you typed (matchedBy: "name-without-legal-suffix"). A name whose LinkedIn address does not follow it (McDonald's,Nestlé), and a one-word name whose handle belongs to a smaller company (anthropic), is also looked up on Wikidata, which records many companies' LinkedIn page and official website; that page is used only when its own website matches the one Wikidata lists (matchedBy: "wikidata", with thewikidataId). This adds about 4 seconds per name the first time (answers are remembered for 30 days);lookUpNames: falseturns it off. A one-word name whose plain page is tiny or does not exist (Twilio,Mercari) also tries LinkedIn's usual other addresses for the same name (twilio-inc-,mercari-inc-,…hq,…-io,…app) and takes the far larger same-named page (resolvedBy: "largest-same-name", confidencemedium). Two entries that end on the same company are collected and charged once; the second gets a free row that says so. You can also paste a LinkedIn job posting URL: the company that posted it is tracked (matchedBy: "job-posting"). An entry that cannot be read becomes a free error row and the rest of the run goes on. Country subdomains (uk.linkedin.com/...), non-Latin page addresses andurn:li:organization:<id>work too. Showcase pages are refused with a reason: their jobs are posted under the parent company.location— LinkedIn's public search shows one country at a time, and with no location it picks the searcher's country (our servers are in the US). So when you leave it empty and the company's headquarters is outside the US, we search the headquarters country instead (searchedLocation,locationFrom: "headquarters-country"on the company row). Until 17 October 2026 we did not, and a Tokyo company could come back with 0 open jobs. A company's jobs in other countries need one run (or one entry) per country withlocationset.location,keywords,datePosted— optional filters, applied on top of the company filter. These three actually work — we verifydatePostedagainst the returned postings' real dates. There is deliberately no workplace or experience filter here: LinkedIn's public search acceptsf_WT/f_Eand silently ignores them (we measured it — "remote" and "on-site" queries return 88% the same postings). IfworkTypeorexperienceis sent anyway, the run carries on and says so — in the status, in OUTPUT (ignoredInput) and in a freenoticerow — so you never mistake the results for filtered ones. If you need a real experience filter, use LinkedIn Jobs Scraper — Filters That Actually Work, which applies it from each job page's own value.maxJobsPerCompany— default 1000, max 5000. Set it above the company's real number of open roles. You are charged per job returned, not per request, so a generous ceiling costs nothing extra for a smaller company.trackChanges— off by default. See above for when it is worth turning on.
Start from one company
similarPerCompany (0–10, default 0) also reads the open jobs of the first N companies LinkedIn lists as similar on each company's page — stripe with similarPerCompany: 5 shows how Stripe and five peers are hiring. Their job and company rows carry similarTo (the company they came from) and are charged like any other; added companies are not expanded again. Added 2026-10-24.
Pricing
Pay per event. You are charged for what you receive.
Our own running cost is about **$0.035 per 1,000 rows** of Apify platform usage at 512 MB (22-run measurement, Sept 2026 — [how it was measured](https://dev.to/apify/i-measured-what-my-11-actors-cost-to-run-the-96x-spread-was-mostly-one-config-field-hoj)) — already included in the price; nothing is billed on top.| Event | Price |
|---|---|
| Run started | $0.01 |
| Per company | $0.01 |
| Per job | $0.0008 ($0.80 / 1,000) |
Job rows are priced the same as a plain listing scrape, because that is what they are.
Failed company lookups and low matches (matchConfidence: low) are not charged. A company with zero open roles still returns a
company row — "they are not hiring right now" is an answer, not a failure.
How it works
Reads only LinkedIn's public, logged-out job listing pages — 10 roles per request. Because each request returns a fresh sample rather than a fixed page, the Actor keeps requesting until several rounds in a row bring nothing new, then stops. A 670-role company took about 93 requests this way.
The company ID is resolved from the public company page using two independent markers that must agree. If they disagree, the Actor returns an error instead of a guess — returning another company's jobs under your company's name would be worse than returning nothing.
The line this Actor does not cross
Logging in is a design decision, not a promise:
- Request headers are a frozen object.
CookieandAuthorizationcannot be attached at runtime. - Input fields that look like credentials (
cookie,session,token,li_at,password) are rejected. - Both are covered by unit tests.
Related Actors
| Actor | Use it when |
|---|---|
| LinkedIn Jobs Scraper with Applicant Counts | You want applicant counts and how fast they grow |
| Fast LinkedIn Jobs Scraper | You want volume and speed, by search query |
| LinkedIn Company Scraper with Headcount Growth | You want employee counts and growth |
| LinkedIn Company Posts Scraper | You want what a company publishes and how it lands |
| Job Dedupe & Merge | You also read the company's own career page (Greenhouse, Lever …) and want one row per job — Stripe's 510 LinkedIn + 728 career-page rows became 1,079 jobs, 143 on both |
Pair this with the headcount scraper: headcount tells you how big a company is, open roles tell you where it is going next.
**Something broke or looks wrong?** Open an issue on this Actor's Issues tab and I'll look at it. **Found it useful?** A short review on the Store page helps other people find it.For AI agents
This Actor works well as an agent tool: the input schema is small and fully described, every run returns structured rows, and failures come back as data rather than silent gaps. Use it when you need to:
- scrape all open jobs at a specific company on LinkedIn
- track which roles a company opened or closed since the last check
- list every job a company is hiring for, with measured coverage
Use it from Claude Code (or another coding agent)
Save this as ~/.claude/skills/linkedin-company-jobs/SKILL.md (other agents that read SKILL.md files: their skills folder), put your Apify API token in the APIFY_TOKEN environment variable, and ask the agent in plain words — "List the open jobs at stripe.com posted in the past week".
---name: linkedin-company-jobsdescription: List a company's open LinkedIn jobs (title, place, date) from its website, LinkedIn URL or name, and what is new since the last run. Runs the Apify Actor northbell/linkedin-company-jobs-scraper with the user's APIFY_TOKEN.---Run: curl -s -X POST "https://api.apify.com/v2/acts/northbell~linkedin-company-jobs-scraper/run-sync-get-dataset-items?timeout=300" -H "Authorization: Bearer $APIFY_TOKEN" -H "Content-Type: application/json" -d '{"companies": ["stripe.com"], "datePosted": "past-week"}'For long lists start `/runs` instead and read the dataset when the run finishes.Rows have type job or company; read matchConfidence on the company row and treat low as unconfirmed (not charged).Never print the token. Tell the user the price on the Actor's Store page before a large run.
Prefer MCP? Add https://mcp.apify.com?tools=northbell/linkedin-company-jobs-scraper as a remote MCP server — in Claude Code: claude mcp add --transport http apify "https://mcp.apify.com?tools=northbell/linkedin-company-jobs-scraper" — and sign in to Apify when asked; the Actor then shows up as a tool.
How the coverage number is measured
The write-up of the method, and the four bugs behind it, is published under the Apify organisation on DEV: My scraper returned 660 jobs. There were 880. Nothing in the output said so.
The estimator, the guards and the tests that pin down each bug are open source, with no dependencies: northbell-dev/honest-scraping
More no-login scrapers by northbell
Every one of these reads only public pages — no login, no cookies — and most of them record the numbers that cannot be back-filled if you don't capture them today.
LinkedIn jobs
- LinkedIn Jobs Scraper with Applicant Counts — jobs plus how fast applicants are arriving
- LinkedIn Jobs Scraper — Filters That Actually Work — the experience/workplace filters LinkedIn silently ignores, applied for real
- LinkedIn Jobs Salary Data — Filter by Pay — salary parsed into numbers so you can filter by yearly pay
- Fast LinkedIn Jobs Scraper — bulk job listings, cheap and quick
- LinkedIn Company Jobs Scraper — every open role at a company you name
LinkedIn companies
- LinkedIn Company Scraper with Headcount Growth — the real headcount and how fast it's growing
- LinkedIn Company Posts + Engagement — a company's posts with exact reaction and comment counts
- Official Company Headcount — the headcount from business registers and tax boards (8 European countries, Japan and the US), with source and date
App stores
- App Store Rank & Rating Scraper — iOS keyword rank and rating changes over time
- Shopify App Reviews Scraper — Filter & Sort by Rating — exact per-star review counts, filter and sort
- Google Play Rating & Review Tracker — an Android app's rating tracked day by day