Track LinkedIn Hiring Velocity by Company (2026)
Detect company hiring spikes using Thirdwatch's LinkedIn Jobs Scraper. Daily snapshot per-company role counts + velocity alerts inside.

Thirdwatch's LinkedIn Jobs Scraper feeds a per-company hiring-velocity tracker with pay-per-result pricing — daily snapshot a target watchlist, compute 30-day role-count delta per company, alert on velocity spikes. Built for B2B sales prospecting teams identifying buying signals, venture investors scouting ramping companies, competitive-intelligence functions, and account-executive teams timing outreach.
Why track LinkedIn hiring velocity by company
Open headcount is one of the cleanest leading indicators of company growth. According to LinkedIn's 2024 economic graph disclosures, job-posting velocity at the company level leads revenue-growth disclosures by 90-180 days for public companies and correlates with imminent fundraises for private ones. For sales prospecting, this means hiring-velocity tracking surfaces accounts in their buying window — meaningfully more actionable than generic firmographic targeting.
The job-to-be-done is structured. A B2B sales team prospecting Indian startups for SaaS contracts wants daily alerts when a Series B fintech opens five engineering roles in a week. A venture investor scouts growth-stage startups by velocity to find ramping companies before TechCrunch coverage. A competitive-intelligence team at one product company tracks which competitors are doubling down on which functions. All reduce to per-company snapshot × velocity computation × alert routing.
How does this compare to the alternatives?
Three options for getting per-company hiring velocity into a pipeline:
| Approach | Cost per 1,000 jobs × daily × 200 companies | Reliability | Setup time | Maintenance |
|---|---|---|---|---|
| Headcount-tracker SaaS (Bonterra, Live Data Technologies) | $20K–$100K/year flat | High | Days–weeks | Vendor lock-in |
| LinkedIn Sales Navigator + manual tracking | $99/seat/month | Vendor-dependent | Hours | Manual updates |
| Thirdwatch LinkedIn Jobs Scraper | Pay per result | Production-tested | Half a day | Thirdwatch tracks LinkedIn changes |
Headcount-tracker SaaS is priced for B2B-sales departments. The LinkedIn Jobs Scraper actor page gives you the data layer at meaningfully lower unit cost.
How to track LinkedIn hiring velocity in 4 steps
Step 1: How do I authenticate against Apify?
Sign in at apify.com (free tier, no credit card), open Settings → Integrations, and copy your personal API token. Every example below assumes the token is in APIFY_TOKEN:
export APIFY_TOKEN="apify_api_xxxxxxxxxxxxxxxx"Step 2: How do I take a daily snapshot per target company?
Spawn parallel runs across the watchlist with companyName scoped per run.
import os, requests, time, datetime, json, pathlib
ACTOR = "thirdwatch~linkedin-jobs-scraper"
TOKEN = os.environ["APIFY_TOKEN"]
WATCHLIST = ["Stripe", "Airbnb", "Figma", "Notion",
"Razorpay", "Phonepe", "Cred", "Groww",
"Watershed", "Plaza"]
run_ids = []
for company in WATCHLIST:
r = requests.post(
f"https://api.apify.com/v2/acts/{ACTOR}/runs",
params={"token": TOKEN},
json={"queries": ["engineer", "designer", "manager"],
"companyName": company,
"maxResultsPerQuery": 25,
"scrapeMode": "fast"},
)
run_ids.append((company, r.json()["data"]["id"]))
time.sleep(0.5)
today = datetime.date.today().isoformat()
out = pathlib.Path(f"snapshots/li-velocity-{today}")
out.mkdir(parents=True, exist_ok=True)
for company, run_id in run_ids:
while True:
s = requests.get(f"https://api.apify.com/v2/actor-runs/{run_id}",
params={"token": TOKEN}).json()["data"]["status"]
if s in ("SUCCEEDED", "FAILED", "ABORTED"):
break
time.sleep(20)
if s == "SUCCEEDED":
items = requests.get(
f"https://api.apify.com/v2/actor-runs/{run_id}/dataset/items",
params={"token": TOKEN}).json()
(out / f"{company.replace(' ', '-')}.json").write_text(json.dumps(items))10 companies × 3 queries × 25 jobs = up to 750 records — well within budget for a daily watchlist sweep on the FREE tier.
Step 3: How do I compute hiring velocity per company?
Aggregate snapshots, dedupe by apply_url, count active roles per company per day, compute 30-day delta.
import pandas as pd, glob
frames = []
for d in sorted(glob.glob("snapshots/li-velocity-*")):
date = pathlib.Path(d).name.replace("li-velocity-", "")
for f in glob.glob(f"{d}/*.json"):
company = pathlib.Path(f).stem.replace("-", " ")
for j in json.loads(pathlib.Path(f).read_text()):
frames.append({"date": date, "company": company,
"apply_url": j.get("apply_url")})
df = pd.DataFrame(frames).drop_duplicates(subset=["date", "apply_url"])
df["date"] = pd.to_datetime(df["date"])
daily = (df.groupby(["company", "date"])["apply_url"].nunique()
.reset_index(name="open_roles"))
daily = (daily.set_index("date").groupby("company")
.resample("1D").last().ffill().reset_index(level=0))
dates_present = sorted(daily.reset_index().date.unique())
if len(dates_present) >= 30:
velocity = (
daily.reset_index().groupby("company")
.apply(lambda s: s.iloc[-1].open_roles / s.iloc[-31].open_roles
if len(s) >= 31 and s.iloc[-31].open_roles > 0 else None)
.dropna().sort_values(ascending=False)
)
print(velocity.head(15))Companies with velocity > 3.0 are ramping fast. Add a floor of open_roles_today >= 5 to filter out single-digit noise.
Step 4: How do I forward velocity alerts to Slack?
Wire the velocity output to a sales-CRM Slack channel; forward only newly-flagged companies.
import requests as r, pathlib, json
snapshot = pathlib.Path("li-velocity-flagged.json")
prev = set(json.loads(snapshot.read_text())) if snapshot.exists() else set()
flagged_today = set(velocity[velocity >= 3.0].index)
new_flags = flagged_today - prev
for company in new_flags:
r.post("https://hooks.slack.com/services/.../...",
json={"text": (f":rocket: *{company}* hiring velocity 3x+ over 30d. "
f"Roles open today: {int(daily.reset_index()[daily.reset_index().company == company].iloc[-1].open_roles)}")},
timeout=10)
snapshot.write_text(json.dumps(list(flagged_today)))
print(f"{len(new_flags)} new velocity alerts forwarded")Schedule the actor on Apify's scheduler at daily cadence; the loop fires alerts only when companies cross the threshold for the first time.
Sample output
A single LinkedIn job record (fast mode, used for velocity tracking) looks like this. Five rows weigh ~5 KB.
{
"title": "Senior Backend Engineer",
"company_name": "Stripe",
"location": "San Francisco, CA",
"experience_level": "Mid-Senior level",
"job_type": "Full-time",
"applicant_count": "200+ applicants",
"is_easy_apply": true,
"posted_at": "2026-04-05",
"apply_url": "https://www.linkedin.com/jobs/view/123456/"
}apply_url is the canonical natural key — stable per posting and unique enough for cross-snapshot dedup. applicant_count is a soft signal of role demand (high applicant count + recent posted_at = competitive role; low applicant count + old posted_at = struggling-to-fill role). posted_at lets you isolate truly-new postings from re-listings.
Common pitfalls
Three things go wrong in production velocity-tracking pipelines. Re-listing inflation — companies occasionally close and re-open roles; smooth with a 7-day rolling average. Department concentration matters — a 30-role spike that's all sales hires means something different than 30 engineering hires; tag alerts with department breakdown using the department field on detail-mode pulls. Funding-window false positives — companies that just announced a raise spike for 30-60 days then plateau; cross-reference Crunchbase before treating as new signal.
Thirdwatch's actor returns applicant_count and posted_at on every record so the right velocity computations stay downstream. The pure-HTTP architecture means a 200-company daily watchlist completes in 25-40 minutes wall-clock and runs cheaply enough to operate unsupervised for B2B sales pipelines. A fourth subtle issue worth flagging: LinkedIn occasionally surfaces remote-eligible postings under multiple location facets simultaneously (a single role tagged "Remote, US" can show up under "New York", "San Francisco", and "Remote" depending on how the searcher set their location filter). For per-company velocity tracking this means dedupe on apply_url (the stable canonical key) before counting, otherwise the same role inflates count by 2-3x. A fifth pattern unique to velocity work: companies practising "stealth hiring" on senior roles (executive, principal, staff+) sometimes post to LinkedIn with deliberately vague titles like "Founding Engineer" or "Technical Leader" — these blunt automated department tagging, so for executive-search velocity tracking you'll want a secondary classifier on description keywords rather than relying on parsed title alone. A sixth and final pitfall: LinkedIn's applicant_count field is bucketed ("0-25 applicants", "200+ applicants") rather than exact — for velocity ratios that rely on applicant volume, treat the bucket boundary as the value rather than guessing within the range, otherwise you introduce systematic bias into the comparison.
Related use cases
Frequently asked questions
Why use LinkedIn for hiring-velocity tracking specifically?
LinkedIn shows applicant_count, posted_at, and structured fields per listing — richer than Indeed for velocity analysis. The companyName input lets you scope to a specific employer, and the structured output makes per-company posting velocity a direct measure rather than a derived metric. Most B2B sales prospecting and venture-investing teams anchor hiring-velocity tracking on LinkedIn for this reason.
What threshold defines a hiring spike worth alerting on?
A 3x increase in open roles at a single company over a 30-day rolling window with a floor of 5+ new postings is the standard B2B sales prospecting threshold. For larger enterprises, raise to 10+. Below 3 new postings, the velocity is noise — most companies open and close roles within normal cadence. Tune by vertical: early-stage startups normally ramp from single-digit to double-digit role counts; public companies move in absolute terms.
How does this differ from generic posting-velocity tracking?
Generic tracking aggregates across all companies for a role; per-company tracking surfaces signals tied to specific buyers or investors. A 30-role spike at Razorpay tells a sales team they're scaling for product launch; a similar spike at TCS tells you they won a contract. Per-company velocity is materially more actionable than aggregate role-volume tracking.
How fresh do hiring signals need to be?
Daily cadence is standard for sales/investing pipelines. LinkedIn ranks new listings highly for the first 24-48 hours, so missing that window costs your team the freshest signal. For real-time sales-prospect alerts where speed matters, six-hourly cadence is justified. Weekly is fine for trend-research pipelines without time-pressure.
Can I correlate hiring signals with funding events?
Yes. Cross-reference target-company watchlist against [Crunchbase](https://www.crunchbase.com/) raised dates. A 4-5x velocity spike in the 30-90 days following an announced raise is the textbook pattern. A spike WITHOUT a recent announcement is the more interesting signal — usually means the company is profitable enough to self-fund growth or a raise is imminent.
How do I scale to hundreds of target companies?
The companyName input scopes to one employer per query. For a 200-company watchlist, run 200 parallel queries with companyName set per-query. The actor handles concurrent runs through Apify's API. Daily 200-company tracking at maxResultsPerQuery=20 runs cheaply enough to schedule without manual oversight, with tiered volume pricing reducing per-record cost as you scale.
Related
100 free credits, no credit card.
About 30 real searches. Add the MCP to Claude or Cursor in two minutes.