How to Track Hiring Trends and Company Growth Signals With LinkedIn Data
AI Summary: This guide shows how to build company-specific hiring signals from raw LinkedIn job-posting data instead of relying on LinkedIn's aggregate economy reports, surfacing honest growth indicators like a competitor opening new roles or a target account hiring in a new country.

Search for LinkedIn hiring trends and you will find LinkedIn telling you about the economy. The Economic Graph, the annual Global Talent Trends report, the "Jobs on the Rise" lists — LinkedIn publishes an enormous amount of workforce data, and all of it is aggregate. It tells you that AI roles are growing across the market. It will never tell you that a specific competitor just opened three machine-learning roles in two days, or that the account you have been chasing for a quarter just posted its first job in a new country.
That second kind of signal — company-specific, current, and about the businesses you actually care about — is the one worth having, and it is not in any report. You have to build it yourself from raw job-posting data. The good news is that job postings are one of the most honest signals a company emits. Marketing can spin, press releases can be timed, but a company only pays to post a role when it genuinely intends to fill it. A job posting is a company spending money to tell you what it is about to become.
This is a guide to reading those signals and building a system that captures them, for investors sizing up a company, competitors watching a rival, and sales teams timing their outreach. It uses ScrapeBadger's LinkedIn Scraper, which returns job postings, company data, and search results as structured JSON.
What a Job Posting Actually Tells You
Before any code, learn to read the signal — because the value is entirely in interpretation, and the raw data is useless if you don't know what you are looking at. To make this concrete, here is a real slice of LinkedIn job data: US postings for "AI engineer" from a single recent week, pulled through the LinkedIn search endpoint. Even in ten results, the signals are already visible.
Notion posted the same role — "Software Engineer, AI Platform" — in both San Francisco and New York on the same day. A small AI company called Canals posted three machine-learning roles across Denver, San Francisco, and New York inside forty-eight hours. Several postings carried an "Actively Hiring" badge; others didn't. None of this is in any trends report, and all of it means something. Learning what it means is the whole skill.
Volume and velocity signal growth or distress. The raw count of open roles at a company is a snapshot; the change in that count over time is the signal. A company going from 12 open roles to 45 over a quarter is expanding, and expansion has a cause worth understanding — funding, a new product line, a market push. A company whose postings quietly disappear is contracting, and that often shows up in hiring data weeks before it shows up in the news. You only see this if you track the same company repeatedly, which is why a one-time scrape is nearly worthless and a time series is valuable.
Department mix tells you the strategy. What a company hires reveals where it is placing its bets far more honestly than its homepage does. A company that has spent two years hiring only engineers and suddenly opens six "enterprise account executive" and "sales engineer" roles is telling you it has shifted from building to selling — it thinks the product is ready and it is going after revenue. A company loading up on "supply chain" and "operations" roles is scaling physical capacity. The department composition, and especially a change in that composition, is a strategy leak.
Seniority tells you the stage. A wave of senior and director-level postings often precedes a build-out — you hire the leaders before the teams they will run. A sudden run of junior and mid-level roles in a department that already has its leadership suggests that team is now scaling execution. Reading the seniority mix tells you whether a company is planning a move or already making it.
Geography reveals expansion. This is the clearest signal of all, and Notion's dual SF/NY posting is a mild version of it. When a company that has only ever hired in one country posts its first roles in a new one, that is a market-entry signal, often months ahead of any formal announcement. New-city postings map a company's physical and organizational expansion in near real time. For a competitor or an investor, the first job posting in a new geography is a genuine leading indicator.
Specific roles telegraph specific moves. Individual postings, read closely, are almost embarrassingly informative. A first "Head of Partnerships" hire signals a channel strategy forming. A "Head of International" signals global ambitions. A cluster of roles built around a named technology tells you the stack they are betting on. The job description itself — which the detail endpoint returns in full, sometimes with salary and applicant counts — often describes the unannounced initiative in plain language, because they have to tell candidates what they'll be working on.
From Reading Signals to Building a System
Once you can read the signals by hand, the work is turning that into something repeatable across the companies you care about. The architecture is simple and has three moving parts: a watchlist, a scheduled capture, and a comparison over time. The last part is the one that matters — a single snapshot tells you almost nothing, and the entire value is in the delta between this week and last.
The building blocks map directly onto the LinkedIn endpoints. You resolve a company to its LinkedIn ID once, then pull its postings on a schedule; or you run a saved job search — a role keyword, a location, a date window — and watch how the result set changes week over week. Here is the shape of it in Python.
python
# hiring_monitor.py
import asyncio
import os
from datetime import datetime
from scrapebadger import ScrapeBadger
# The companies you actually care about — competitors, targets, portfolio.
WATCHLIST = ["notionhq", "canals-ai", "linear", "vercel"]
async def snapshot_company(client, universal_name: str) -> dict:
"""Capture one company's current hiring posture."""
# Resolve the company and pull its live postings
company = await client.linkedin.get_company(universal_name=universal_name)
company_id = company.company_id
postings = []
start = 0
while True:
page = await client.linkedin.company_jobs(
company_id=company_id, start=start
)
batch = page.jobs if hasattr(page, "jobs") else []
if not batch:
break
postings.extend(batch)
if len(batch) < 25: # Last page
break
start += 25
await asyncio.sleep(0.3)
# Reduce the postings to the signals that matter
by_department = {}
by_location = {}
by_seniority = {}
for job in postings:
dept = classify_department(job.title)
by_department[dept] = by_department.get(dept, 0) + 1
by_location[job.location] = by_location.get(job.location, 0) + 1
level = classify_seniority(job.title)
by_seniority[level] = by_seniority.get(level, 0) + 1
return {
"company": universal_name,
"captured_at": datetime.utcnow().date().isoformat(),
"total_open_roles": len(postings),
"by_department": by_department,
"by_location": by_location,
"by_seniority": by_seniority,
"role_titles": [j.title for j in postings],
}
def classify_department(title: str) -> str:
"""Bucket a job title into a department. Tune to your industry."""
t = title.lower()
if any(w in t for w in ["engineer", "developer", "ml", "data", "infrastructure"]):
return "engineering"
if any(w in t for w in ["sales", "account executive", "revenue", "sdr"]):
return "sales"
if any(w in t for w in ["marketing", "growth", "demand", "brand"]):
return "marketing"
if any(w in t for w in ["operations", "supply", "logistics"]):
return "operations"
if any(w in t for w in ["partnership", "business development", "bd"]):
return "partnerships"
if any(w in t for w in ["recruiter", "people", "talent", "hr"]):
return "people"
return "other"
def classify_seniority(title: str) -> str:
t = title.lower()
if any(w in t for w in ["head of", "director", "vp", "chief", "lead", "principal"]):
return "leadership"
if any(w in t for w in ["senior", "staff", "sr."]):
return "senior"
if any(w in t for w in ["junior", "associate", "intern", "entry"]):
return "junior"
return "mid"
async def main():
async with ScrapeBadger(api_key=os.environ["SCRAPEBADGER_API_KEY"]) as client:
for name in WATCHLIST:
snap = await snapshot_company(client, name)
save_snapshot(snap) # Append to your store, keyed by company + date
print(
f"{snap['company']}: {snap['total_open_roles']} roles | "
f"{snap['by_department']}"
)
await asyncio.sleep(1.0)
if __name__ == "__main__":
asyncio.run(main())The save_snapshot step is the whole point. Append each capture to a store keyed by company and date, and the comparison logic that reads the deltas is where the intelligence lives:
python
def diff_snapshots(previous: dict, current: dict) -> list[str]:
"""Turn two snapshots into human-readable signals."""
signals = []
# Volume change
delta = current["total_open_roles"] - previous["total_open_roles"]
if delta >= 5:
signals.append(
f"📈 Hiring surge: {previous['total_open_roles']} → "
f"{current['total_open_roles']} open roles (+{delta})"
)
elif delta <= -5:
signals.append(
f"📉 Hiring pullback: {previous['total_open_roles']} → "
f"{current['total_open_roles']} open roles ({delta})"
)
# New departments ramping
for dept, count in current["by_department"].items():
prev_count = previous["by_department"].get(dept, 0)
if prev_count == 0 and count >= 2:
signals.append(f"🆕 New {dept} hiring: {count} roles (was 0)")
elif count - prev_count >= 3:
signals.append(
f"⬆️ {dept.capitalize()} scaling: {prev_count} → {count} roles"
)
# New geographies — the market-entry signal
for loc in current["by_location"]:
if loc not in previous["by_location"]:
signals.append(f"🌍 First posting in new location: {loc}")
# Leadership build-out
lead_now = current["by_seniority"].get("leadership", 0)
lead_before = previous["by_seniority"].get("leadership", 0)
if lead_now - lead_before >= 2:
signals.append(
f"👔 Leadership build-out: {lead_before} → {lead_now} senior roles "
f"(often precedes team expansion)"
)
return signalsRun the snapshot weekly, diff against the prior week, and route the signals wherever you need them — a Slack channel, a CRM field, a dashboard. The mechanics are ordinary. The value is entirely in the watchlist you choose and the interpretation you bring.
Putting the Signals to Work
The same data means different things depending on who is reading it, and the interpretation is where this stops being a scraping exercise and becomes intelligence.
For sales teams, hiring is a timing signal. The best moment to reach a prospect is when they are building the team your product serves. A company opening its first data-engineering roles is a company about to have data-infrastructure problems — which is the moment to be in their inbox, not six months later when they have already chosen a vendor. A job-change trigger — a new person landing in a role that owns your category — is one of the strongest buying signals in B2B, because new decision-makers reevaluate the stack they inherited. Watching a target account's hiring tells you when the window is open.
For competitive intelligence, hiring is a strategy leak. You cannot read a competitor's roadmap, but you can read their job board, and it is a surprisingly faithful shadow of that roadmap. The shift from engineering-heavy to sales-heavy hiring tells you they think the product is ready. A cluster of roles around a specific capability tells you what they are building before they announce it. A new-geography posting tells you where they are going. None of this requires anything private — it is all public, if you are watching systematically instead of stumbling on it.
For investors and analysts, hiring is an early fundamental. Headcount growth is a leading indicator that shows up in job-posting data well before it appears in a funding announcement or a filing. A portfolio company slowing its hiring, or a target quietly freezing roles, is information you want before the market prices it in. Aggregate a sector's hiring — every company in a category, tracked together — and you have a real-time read on where the sector's collective conviction is moving. As practitioners regularly note in discussions like the r/careeradvice threads that dissect each LinkedIn "Jobs on the Rise" release, the aggregate reports are directionally interesting but always lagging; building your own from raw postings is how you get ahead of them.
The Honest Caveats
Job-posting data is a strong signal, not a perfect one, and treating it as gospel will burn you. Some companies leave stale postings up for months, inflating an apparent hiring level that isn't real; tracking changes rather than absolute counts largely controls for this, since a stale post doesn't move week to week. Some hire through agencies or private channels and under-post publicly, so a low public count is not proof of a hiring freeze. Reposts and duplicate listings — like the identical Notion roles across two cities — can look like more demand than exists, so deduplicate on title plus description before counting. And a single week is noise; the signal lives in trends across weeks and in patterns across many roles, never in one posting read in isolation.
The discipline that makes this reliable is the same discipline that makes any measurement reliable: a consistent watchlist, a regular cadence, and attention to the delta rather than the snapshot. Do that, and LinkedIn's job data becomes a genuine early-warning system for the companies you care about — one that is watching what businesses do with their hiring budgets, not what they say in their reports.
Free trial at scrapebadger.com/linkedin-scraper — 1,000 credits, no card. Full endpoint docs at docs.scrapebadger.com.
Common Questions
Is scraping LinkedIn job data legal? Public job postings are public data, and the hiQ Labs v. LinkedIn ruling (Ninth Circuit, reaffirmed 2022) established that scraping publicly available data does not violate the US Computer Fraud and Abuse Act. LinkedIn's Terms of Service restrict automated access as a contractual matter, so collect only public data, run at reasonable rates, avoid personal data where you lack a lawful basis, and consult legal counsel for your situation.
How often should I capture snapshots? Weekly is the right default for company hiring monitoring. Job postings change over days and weeks, not minutes, so weekly captures real movement without redundant runs. For a fast-moving situation — an account you're actively working, a competitor mid-launch — you might tighten to a few times a week.
Won't stale job postings distort the numbers? They can, which is exactly why you track the change over time rather than the absolute count. A stale posting sits at the same number week after week and contributes nothing to the delta, so a signal built on movement naturally filters it out. Deduplicating on title and description before counting handles reposts and multi-city duplicates.
What's the single most reliable signal? Change in geography. When a company posts its first role in a country or city it has never hired in before, that is a clean, hard-to-fake market-entry signal, often months ahead of any announcement. Volume velocity and department-mix shifts are strong too, but new-geography postings are the least ambiguous.
Can I track a whole sector, not just single companies? Yes. Run a saved job search by role keyword and location on a schedule and watch how the result set changes, or maintain a watchlist of every company in a category and aggregate their snapshots. Sector-level aggregation gives you a real-time read on collective hiring conviction that lags reports never will.

Written by
Thomas Shultz
Thomas Shultz is the Head of Data at ScrapeBadger, working on public web data, scraping infrastructure, and data reliability. He writes about real-world scraping, data pipelines, and turning unstructured web data into usable signals. ScrapeBadger is a web scraping API platform specialising in Twitter/X, Reddit and Google data, with dedicated scrapers also covering TikTok, YouTube, LinkedIn, Amazon, eBay, Zillow and 40+ more: with built-in anti-bot bypass and an MCP server for AI agents.
Ready to get started?
Join thousands of developers using ScrapeBadger for their data needs.