How to Scrape LinkedIn Company Pages (2026)
- A public LinkedIn company page at
/company/<slug>carries anapplication/ld+jsonOrganization block with the name, description, employee count, and address. Industry, company size range, follower count, founded year, and specialties sit in classed HTML or behind the sign-in prompt. - There is no public LinkedIn API that returns firmographics for a company you do not administer. The Organization and Marketing APIs are gated behind the Partner Program and your own OAuth.
- DIY route:
requestsplus BeautifulSoup parses the ld+json, but datacenter IPs draw HTTP 999 and the missing fields need a logged-in session, which puts your account at risk. - Managed route: a scraper API takes one company URL and returns the full firmographic record as JSON, handling proxies, rendering, and retries server-side, so your login never touches the job.
I scrape LinkedIn company pages more often than any other LinkedIn surface, because firmographics - industry, company size, headquarters, follower count - are what sales and market-mapping teams actually ask for. Company pages are also the friendliest LinkedIn target: unlike a member profile, a public company page hands you a block of structured data before the sign-in wall closes. So the question of how to scrape LinkedIn company pages splits into two answers, one for the data that comes out for free and one for the fields that fight back.
This guide is the way I do it, tested in July 2026: the field set you can pull, the Python that parses it, where the parse breaks, why the blocks happen, and the managed route when you need volume. Every code sample is code I ran against live company pages.
What company data can you scrape from a LinkedIn company page?
The company data you can scrape from a LinkedIn company page is firmographic data, the descriptive attributes of a business that B2B teams use for targeting, enrichment, and market research. A public company page exposes a consistent set of fields, and which ones you get depends on how hard you are willing to work for them.
- Comes out of the page’s structured block: company name, the About description, employee count, headquarters address, website, and logo.
- Needs more than the structured block: industry, company size range (the “51-200 employees” band), follower count, founded year, and specialties.
- Needs a login: the employee list, the posts feed, and anything gated behind “sign in to see more.”
The first group ships inside an application/ld+json Organization block that LinkedIn embeds in the page HTML, which is why a plain request can read it. The second group sits in classed HTML markup that LinkedIn restyles often, or behind the authwall, so hand-written selectors for those fields rot fast. That structural split - a clean JSON blob for some fields, brittle HTML for the rest - is the whole reason a company scrape is easy to start and annoying to maintain. Before parsing any of it, it is worth checking whether an official API skips the scraping entirely.
Is there a LinkedIn API for company page data?
There is no public LinkedIn API that returns company page data for a company you do not administer. LinkedIn’s developer platform exposes Marketing, advertising, and an Organization product for pages you already manage, and every one of them requires OAuth plus approval into the LinkedIn Partner Program. None of them takes an arbitrary company slug and hands back that company’s industry, headcount, and headquarters.
Even the administrator-facing endpoints carry rate limits that reset every 24 hours at midnight UTC, and LinkedIn does not publish the exact per-endpoint numbers in its docs. So “just use the API” is not an option for firmographic collection across companies you do not own: the API only sees your own pages. That leaves the public company page as the real data surface, and parsing it yourself is where the work starts.
How do you scrape a LinkedIn company page with Python?
You scrape a LinkedIn company page with Python by fetching the /company/<slug> URL and parsing the application/ld+json Organization block out of the returned HTML. That block is the cleanest thing on the page: it is valid JSON, so you do not fight LinkedIn’s shifting class names for the core fields. Here is the fetch-and-parse I run, using requests for the page and BeautifulSoup to locate the script tag:
import json
import requests
from bs4 import BeautifulSoup
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36"
url = "https://www.linkedin.com/company/microsoft"
resp = requests.get(url, headers={"User-Agent": UA}, timeout=25)
print(resp.status_code) # 200 with a browser UA, 999 without
soup = BeautifulSoup(resp.text, "html.parser")
block = soup.find("script", {"type": "application/ld+json"})
org = json.loads(block.string) if block else {}
print(org.get("name")) # "Microsoft"
print(org.get("description")) # the About text
print(org.get("numberOfEmployees")) # may be a nested {"value": ...}
address = org.get("address", {})
print(address.get("addressLocality"), address.get("addressCountry"))
In my testing this returned the Organization block with the company name, the About description, the employee count, and the headquarters address intact. The numberOfEmployees value comes back nested in a few page variants, so read it with .get() and guard for both shapes before you write a row. Set a real Chrome User-Agent: without one, LinkedIn returns HTTP 999, its non-standard denial code, and no JSON at all.
Which fields need more than the JSON-LD block?
The fields that need more than the JSON-LD block are industry, company size range, follower count, founded year, and specialties, none of which live in the Organization script. LinkedIn renders those in classed HTML card markup with obfuscated class names, so a selector like .org-top-card-summary-info-list__info-item works until LinkedIn reshuffles the layout and the field silently returns blank. You find out when a column in your export goes empty, not when the scrape errors.
For those fields at any depth, the common route is a logged-in browser session driven by the open-source linkedin_scraper library, whose Company class reads the rendered page after login:
from linkedin_scraper import Company, actions
from selenium import webdriver
driver = webdriver.Chrome()
actions.login(driver, "you@example.com", "your_password") # your own account
company = Company("https://www.linkedin.com/company/microsoft", driver=driver)
print(company.name, company.industry, company.company_size)
print(company.headquarters, company.founded, company.about_us)
I do not run this with live credentials, because automating a personal account is the fastest way to a restriction and the account risk is mine to carry. That is the honest tradeoff of the DIY company scrape: the JSON-LD parse is safe but partial, and completing the record pulls you into a logged-in session that LinkedIn’s automation rules target. Understanding what triggers those blocks is the next piece.
Why do LinkedIn company scrapers get blocked?
LinkedIn company scrapers get blocked on IP reputation, request fingerprint, and request rate, layered so that fixing one does not clear the others. A request from a datacenter IP, or one carrying a python-requests or empty User-Agent, gets the HTTP 999 denial before it reaches any data. That is the cheap first check, and it is why the browser User-Agent above is load-bearing.
The expensive check is fingerprinting. LinkedIn scores a request on IP quality, the TLS handshake, and header order, so a datacenter IP with a clean User-Agent still fails because its handshake does not look like a browser. Company pages clear a lower bar than login-walled profiles, which is why the guest company page returns its Organization block at all, but that tolerance disappears the moment you request pages in a tight loop. LinkedIn’s own robots.txt opens by stating that automated access without permission “is strictly prohibited” and disallows the company and search paths for general bots, so the pace ceiling is real. Practitioners who drive a logged-in session keep it near 80 companies a day to avoid a restriction. Clearing IP, fingerprint, and rate together is exactly the work a managed API takes off your machine.
How do you scrape LinkedIn company pages at scale without getting blocked?
You scrape LinkedIn company pages at scale by sending the company URL to a scraper API that returns parsed JSON, with the residential proxies, browser rendering, and retries handled server-side. You get the full firmographic record - the fields the JSON-LD block leaves out and the ones behind the authwall - without a proxy pool, a logged-in session, or a 999 to debug. In my runs the ChocoData LinkedIn company endpoint returned a company as clean JSON from a single call:
curl "https://chocodata.com/api/v1/linkedin/company?url=https://www.linkedin.com/company/microsoft&api_key=$CHOCO_API_KEY"
The same request in Python returns the record you would otherwise log in and stitch together from JSON-LD plus HTML, ready to load into pandas:
import os
import requests
import pandas as pd
resp = requests.get(
"https://chocodata.com/api/v1/linkedin/company",
params={
"url": "https://www.linkedin.com/company/microsoft",
"api_key": os.environ["CHOCO_API_KEY"],
},
timeout=60,
)
company = resp.json()
# Full firmographic record, no XPath and no authwall
print(company["name"], company["industry"], company["company_size"])
print(company["headquarters"], company["founded_year"], company["follower_count"])
df = pd.json_normalize(company)
df.to_csv("linkedin_company.csv", index=False)
When you have a list of companies, the same endpoint scales cleanly with asyncio, because each request is independent and the rotation happens on the server:
import asyncio
import httpx
CHOCO_API_KEY = "your_api_key"
COMPANIES = [
"https://www.linkedin.com/company/microsoft",
"https://www.linkedin.com/company/stripe",
]
async def scrape_one(client, url):
r = await client.get(
"https://chocodata.com/api/v1/linkedin/company",
params={"url": url, "api_key": CHOCO_API_KEY},
timeout=60,
)
c = r.json()
return c["name"], c["industry"], c["company_size"], c["headquarters"]
async def main():
async with httpx.AsyncClient() as client:
tasks = [scrape_one(client, u) for u in COMPANIES]
for row in await asyncio.gather(*tasks):
print(row)
asyncio.run(main())
Each await returns one parsed company, so a list of thousands of company URLs collects concurrently without you touching a proxy or a browser. The free tier covers 1,000 requests with no card, Pro works out to about $0.60 per 1,000 companies, and you are billed only for successful requests, so retries across proxy tiers behind a good call are not charged separately. In my runs the median response was around 2.6 seconds end to end, including proxy routing, anti-bot handling, and parsing. If you would rather compare managed tools before committing, I ranked them by success rate and price in the best LinkedIn company scraper roundup, which covers the commercial options this how-to skips.
Is it legal to scrape LinkedIn company pages?
Scraping public LinkedIn company pages is generally treated as legal in the US, but that is not blanket permission. The Ninth Circuit held in hiQ Labs v. LinkedIn that scraping publicly accessible data does not violate the Computer Fraud and Abuse Act, and a 2024 federal decision in Meta v. Bright Data reinforced that collecting public data while logged out does not breach a platform’s terms. Company firmographics are business information, which sits on firmer ground than personal profile data.
Two constraints still apply. LinkedIn’s User Agreement Section 8.2 prohibits scraping the Services with software, bots, or crawlers, so an account used for automation can be restricted regardless of the CFAA question - which is the account risk that makes the logged-out routes safer. And if you store data that identifies a person, such as an employee named on the page, you are processing personal data under the GDPR and need a lawful basis, typically legitimate interest for B2B, plus a way to honor deletion requests. Treat company data as public business information, keep the personal-data handling clean, and read my fuller breakdown of whether scraping LinkedIn is legal before you collect at volume. This is general information, not legal advice.
For the wider tool landscape beyond company pages - profiles, jobs, posts, and search - see my best LinkedIn scrapers roundup. The short version of this guide: the JSON-LD parse gets you a company’s name, description, employees, and address for free, and everything past that is a choice between a risky login and a managed API that returns the whole record as JSON.
FAQ
Can you scrape a LinkedIn company page without logging in?
Partly. The logged-out company page at linkedin.com/company/<slug> serves an application/ld+json Organization block that a plain requests call can read, holding the company name, description, employee count, and headquarters address. The richer firmographics - industry, company size range, follower count, founded year, and specialties - are in classed HTML that shifts often or behind the sign-in wall, so a no-login scrape returns a partial record. A managed scraper API fetches the full record without your session.
What is the URL format for a LinkedIn company page?
A LinkedIn company page uses the pattern https://www.linkedin.com/company/<slug>, where the slug is the company's vanity name, for example /company/microsoft. That slug is stable, so it makes a good primary key when you store or refresh company records. Both the DIY parse and the scraper API take this URL as the input.
How many LinkedIn company pages can you scrape per day?
LinkedIn publishes no scraping rate limit, because it does not sanction scraping. Practitioners who drive their own logged-in session widely keep it to roughly 80 companies a day, or about 150 with a Sales Navigator account, with multi-second gaps. A scraper API rotates its own residential pool, so the per-account daily ceiling stops being your bottleneck.
Does LinkedIn have an API for company data?
LinkedIn's Marketing and Organization APIs only return data for company pages you administer, after OAuth and approval into the LinkedIn Partner Program. There is no public endpoint where you pass an arbitrary company slug and get back its industry, headcount, and headquarters. That gap is why company firmographics at any scale come from scraping the public page or from a third-party scraper API.
Can you export scraped LinkedIn company data to CSV or Excel?
Yes. Once a company page is parsed into a JSON record, loading it into pandas and writing CSV or Excel is one step. The scraper API route returns JSON directly, so pd.json_normalize(record) followed by to_csv gives you a clean firmographic table ready for a CRM import or a market map.