LinkedIn Profile Scraper: How to Extract Profile Data via API (2026)
A LinkedIn profile scraper pulls structured data from a person's profile – name, headline, experience, education, skills, activity – from its URL, whether you need one profile or a list of thousands. There is no official LinkedIn API for reading profile data, so every option is a scraper, and they differ a lot in reliability and account risk. This guide shows exactly what fields you can get, a real sample JSON, how to fetch one profile and a whole list in code, an honest take on Chrome extensions versus an API, and what you cannot get (spoiler: emails).
The short version. A person's headline, experience, education, skills, and activity are all extractable from their profile. Personal emails and phone numbers are not on the profile and need consented enrichment. Chrome extensions and homemade scripts run on your own account at machine speed and get it restricted; an API paces like a human and returns clean JSON.
What data is on a LinkedIn profile
A single profile is a rich record. Grouped by what it tells you:

| Group | Fields |
|---|---|
| Identity | name, headline, publicUrl, hashedUrl |
| Role and company | position, companyName, location, countryCode |
| About | about, followersCount |
| Experience | experiences[] – role, company, dates, duration, employment and location type |
| Education | education[] – school and details |
| Skills and languages | skills[] ({ name }), languages[] ({ name, proficiency }) |
| Activity | posts, comments, reactions |
One detail worth building around: use hashedUrl as your stable key, not publicUrl. The vanity URL (/in/jane-doe) changes when someone renames their profile, but the hashed member URL is durable – it is the difference between a deduped database and silent duplicates.
A real scraped profile
Each section is opt-in: you request the parts you need, and you get back typed JSON instead of HTML to parse.
{
"name": "Jane Doe",
"publicUrl": "https://www.linkedin.com/in/jane-doe",
"hashedUrl": "https://www.linkedin.com/in/ACoAAB1a2b3c4d",
"headline": "Head of Growth at Acme",
"location": "San Francisco, California, United States",
"countryCode": "US",
"position": "Head of Growth",
"companyName": "Acme",
"about": "Demand generation and lifecycle marketing leader.",
"followersCount": 4820,
"experiences": [
{
"position": "Head of Growth",
"companyName": "Acme",
"employmentType": "fullTime",
"locationType": "hybrid",
"duration": 26,
"startTime": "2024-01-01T00:00:00Z",
"endTime": null,
"location": "San Francisco, CA"
}
],
"education": [
{ "schoolName": "Stanford University", "details": "MBA, Marketing" }
],
"skills": [
{ "name": "Demand Generation" },
{ "name": "SEO" }
],
"languages": [
{ "name": "English", "proficiency": "nativeOrBilingual" },
{ "name": "Spanish", "proficiency": "professionalWorking" }
]
}Four ways to scrape a profile, compared
There is no official profile API, so the real choice is between four methods that trade off scale, output, and the risk to your account.
| Method | Scale | Output | Maintenance | Account-ban risk |
|---|---|---|---|---|
| Manual copy-paste | A few a day | You retype it | None | None |
| Chrome extension | 50–100/day | A spreadsheet | Breaks on layout changes | High – acts on your account at machine speed |
| DIY Python | High, until blocked | Raw HTML you parse | You own selectors and proxies | High – headless on your account |
| API on your own account | Hundreds to thousands/day | Structured JSON | Handled for you | Lower – paced like a human |
The honest distinction is account risk. A Chrome extension or a headless Python script acts through your own logged-in account at machine speed, which is exactly the pattern LinkedIn flags – accounts get restricted within days. An account-based API runs the same account but paces actions like a real user and returns maintained, structured JSON, so you are not re-writing selectors every time the page changes. We rank all the methods by risk in the guide to scraping LinkedIn, and compare the API models in the LinkedIn scraper API guide.
Scrape one profile by URL
Install the SDK:
# Node.js
npm install -S @linkedapi/node
# Python
pip install linkedapiThen fetch a profile by URL, choosing which sections to pull:
import LinkedApi from '@linkedapi/node';
const linkedapi = new LinkedApi({
linkedApiToken: process.env.LINKED_API_TOKEN,
identificationToken: process.env.IDENTIFICATION_TOKEN,
});
const workflow = await linkedapi.fetchPerson.execute({
personUrl: 'https://www.linkedin.com/in/jane-doe',
retrieveExperience: true,
retrieveEducation: true,
retrieveSkills: true,
retrieveLanguages: true,
});
const { data } = await linkedapi.fetchPerson.result(workflow.workflowId);
console.log(data?.name, data?.position, data?.hashedUrl);If you only have a name rather than a URL, search for people first and feed the resulting URLs into the fetch.
Scrape a list of profiles in bulk
The common job is enrichment: you have a list of profile URLs – from a CSV, a search export, or your CRM – and you want a structured row for each.

Loop over the URLs and collect the results. Linked API runs workflows sequentially on your account, so this paces itself automatically:
const profileUrls = [
'https://www.linkedin.com/in/jane-doe',
'https://www.linkedin.com/in/john-smith',
// one row per profile
];
const rows = [];
for (const personUrl of profileUrls) {
const workflow = await linkedapi.fetchPerson.execute({ personUrl, retrieveExperience: true });
const { data, errors } = await linkedapi.fetchPerson.result(workflow.workflowId);
if (data) rows.push(data);
else console.warn('Skipped', personUrl, errors);
}Two realities to plan for: a share of URLs in any list are stale (people rename or delete profiles), and some profiles are private, so expect to skip a percentage rather than get a clean 100%. Handle the error case, as the loop above does, instead of assuming every fetch succeeds. Bulk volume is also bounded by your account's daily limits – this is your real account, not a proxy pool.
Can you get an email or phone from a profile?
Mostly no, and this is where a lot of tools oversell. Personal emails and phone numbers are almost never shown on a LinkedIn profile, so a scraper reading the profile cannot reliably return them. Tools that advertise "verified emails" are matching the person against a separate, ideally consented, B2B enrichment database – that is a different product from profile scraping, and the data does not come off the profile itself.
The practical split: scrape the profile for role, company, experience, and activity; get contact details from a consented enrichment provider. We cover why direct contact-harvesting is the riskiest move in the scraping guide.
Is it legal, and will my account get banned?
Profile data is largely public, and US courts (hiQ Labs v. LinkedIn) have held that scraping publicly available data is not a Computer Fraud and Abuse Act violation. But public is not a free pass: LinkedIn's User Agreement prohibits automated access (a civil matter, enforced with account restrictions and lawsuits – the data API Proxycurl was sued into shutting down), and personal data falls under GDPR and CCPA.
The ban risk is highest exactly where most people start: Chrome extensions and headless scripts driving your own account too fast. Pace like a human, stop on a CAPTCHA or restriction notice, and keep contact data to consented sources. The full four-layer legal model is in our guide to scraping LinkedIn. This is not legal advice.
Frequently Asked Questions (FAQ)
Name, headline, location, current role and company, the full experience and education history, skills, languages, follower count, and recent activity (posts, comments, reactions). Personal email and phone are generally not on the profile.
No. LinkedIn's official APIs are limited to your own data and approved partner use cases; there is no public API to read other people's profile data. Every "profile API" you see is a scraping or enrichment product.
Yes – pass a list of profile URLs and fetch each one in a loop, collecting structured rows. Plan for a percentage of stale or private URLs, and remember that volume on an account-based approach is bounded by your account's safe daily pace.
Not from the profile itself in most cases. Emails and phone numbers are rarely published on profiles, so reliable contact data comes from a separate consented enrichment provider, not from scraping the profile.
An API on your own account, by a wide margin. Extensions act through your logged-in account at machine speed and tend to get it restricted quickly; an API paces actions like a human, returns structured JSON, and is maintained against LinkedIn UI changes.
Install the SDK (pip install linkedapi), then call fetch_person.execute(...) with the profile URL and the sections you want, and read the result with fetch_person.result(...). See the code above for a full example, including the bulk loop.
Only the limited public version LinkedIn shows logged-out, which omits much of the profile. Full, structured profile data comes through an authenticated session – your own account, driven by an API.
There is no universal number; it depends on your account's age and history. A new account should stay conservative and ramp up, while an established one handles more. Behavior matters more than raw count – pace like a human and stop on warnings.
Need clean LinkedIn profile data by URL or in bulk, without running an extension or a fragile script? Start with Linked API – fetch a profile or a whole list from your own account and get structured JSON back.