LinkedIn Scraping API: Extract Profiles, Companies & Jobs
LinkedIn has the best B2B data on the internet. 1 billion professionals. 65 million companies. Decision-makers, job titles, company sizes, funding data—all in one place.
But LinkedIn's official API? Nearly useless for data extraction. They shut down most endpoints in 2015.
This guide shows you how to use a LinkedIn scraping API to get the data you actually need.
Why LinkedIn's Official API Falls Short
Here's what LinkedIn's API lets you do (and doesn't):
| Can Do | Can't Do |
|---|---|
| Post to your own profile | Search for people |
| Get your own connections | Get company employees |
| Share updates | Extract profile details |
| Basic profile (with user permission) | Bulk data extraction |
For any serious B2B use case—lead generation, market research, competitor analysis—you need scraping.
What You Can Scrape from LinkedIn
| Data Type | What You Get |
|---|---|
| Profiles | Name, headline, location, current company, experience, education, skills |
| Companies | Name, industry, size, headquarters, description, employee count, funding |
| Jobs | Title, company, location, description, requirements, posted date |
| Posts | Content, likes, comments, shares, author info |
| Search Results | People matching filters (title, company, location) |
All publicly visible data—the same information anyone sees on linkedin.com without logging in.
LinkedIn Scraping API: How It Works
A scraping API handles all the complexity:
- Proxy rotation and IP management
- Browser fingerprinting
- Rate limit handling
- CAPTCHA solving
- Data parsing and normalization
You just make HTTP requests and receive clean JSON data.
Extract a LinkedIn Profile
const API_KEY = 'your_sociavault_api_key';
async function getLinkedInProfile(profileUrl) {
const response = await fetch(
`https://api.sociavault.com/v1/scrape/linkedin/profile?url=${encodeURIComponent(profileUrl)}`,
{
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
}
}
);
return response.json();
}
// Usage
const profile = await getLinkedInProfile('https://www.linkedin.com/in/satyanadella/');
console.log(profile);
/* Response:
{
"success": true,
"data": {
"name": "Satya Nadella",
"headline": "Chairman and CEO at Microsoft",
"location": "Redmond, Washington, United States",
"connections": "500+",
"about": "...",
"experience": [
{
"title": "Chairman and CEO",
"company": "Microsoft",
"duration": "10+ years",
"description": "..."
}
],
"education": [...],
"skills": [...]
}
}
*/
Python Example
import requests
API_KEY = 'your_sociavault_api_key'
BASE_URL = 'https://api.sociavault.com/v1/scrape/linkedin'
def get_linkedin_profile(profile_url):
response = requests.get(
f'{BASE_URL}/profile',
params={'url': profile_url},
headers={'Authorization': f'Bearer {API_KEY}'}
)
return response.json()
def get_company_info(company_url):
response = requests.get(
f'{BASE_URL}/company',
params={'url': company_url},
headers={'Authorization': f'Bearer {API_KEY}'}
)
return response.json()
# Usage
profile = get_linkedin_profile('https://www.linkedin.com/in/jeffweiner08/')
print(f"Name: {profile['data']['name']}")
print(f"Headline: {profile['data']['headline']}")
Extract Company Data
async function getLinkedInCompany(companyUrl) {
const response = await fetch(
`https://api.sociavault.com/v1/scrape/linkedin/company?url=${encodeURIComponent(companyUrl)}`,
{
headers: {
'Authorization': `Bearer ${API_KEY}`
}
}
);
return response.json();
}
// Get company information
const company = await getLinkedInCompany('https://www.linkedin.com/company/stripe/');
console.log(company);
/* Response:
{
"success": true,
"data": {
"name": "Stripe",
"industry": "Financial Services",
"company_size": "5,001-10,000 employees",
"headquarters": "San Francisco, California",
"founded": "2010",
"specialties": ["Payments", "APIs", "Developer Tools"],
"website": "https://stripe.com",
"about": "..."
}
}
*/
Scrape Job Listings
async function getJobListings(companyUrl, limit = 20) {
const response = await fetch(
`https://api.sociavault.com/v1/scrape/linkedin/jobs?company_url=${encodeURIComponent(companyUrl)}&limit=${limit}`,
{
headers: {
'Authorization': `Bearer ${API_KEY}`
}
}
);
return response.json();
}
// Get open positions at a company
const jobs = await getJobListings('https://www.linkedin.com/company/openai/', 50);
jobs.data.forEach(job => {
console.log({
title: job.title,
location: job.location,
postedDate: job.posted_date,
applicants: job.applicant_count
});
});
Use Cases
1. B2B Lead Generation
Build targeted prospect lists:
async function buildProspectList(profiles) {
const prospects = [];
for (const profileUrl of profiles) {
const result = await getLinkedInProfile(profileUrl);
if (result.success) {
const { data } = result;
prospects.push({
name: data.name,
title: data.headline,
company: data.experience?.[0]?.company,
location: data.location,
profileUrl: profileUrl,
skills: data.skills?.slice(0, 5)
});
}
// Rate limiting courtesy
await new Promise(r => setTimeout(r, 500));
}
return prospects;
}
// Export to CSV
function exportToCSV(prospects) {
const headers = ['name', 'title', 'company', 'location', 'profileUrl'];
const rows = prospects.map(p => headers.map(h => `"${p[h] || ''}"`).join(','));
return [headers.join(','), ...rows].join('\n');
}
2. Competitor Employee Analysis
Track hiring and team composition:
import requests
def analyze_competitor_team(company_url, target_departments):
# Get company info
company = get_company_info(company_url)
# Get employees (from company page)
employees = requests.get(
f'{BASE_URL}/company/employees',
params={'url': company_url, 'limit': 100},
headers={'Authorization': f'Bearer {API_KEY}'}
).json()
# Analyze by department
department_counts = {}
for emp in employees.get('data', []):
for dept in target_departments:
if dept.lower() in emp.get('headline', '').lower():
department_counts[dept] = department_counts.get(dept, 0) + 1
return {
'company': company['data']['name'],
'total_employees': company['data']['company_size'],
'departments': department_counts
}
# Analyze engineering team size
result = analyze_competitor_team(
'https://www.linkedin.com/company/vercel/',
['Engineering', 'Product', 'Sales', 'Marketing']
)
print(result)
3. Market Research
Analyze industry trends:
async function analyzeIndustryHiring(companies) {
const results = [];
for (const companyUrl of companies) {
const jobs = await getJobListings(companyUrl, 100);
// Count job types
const jobTypes = {};
jobs.data.forEach(job => {
const category = categorizeJob(job.title);
jobTypes[category] = (jobTypes[category] || 0) + 1;
});
results.push({
company: companyUrl.split('/company/')[1].replace('/', ''),
totalOpenings: jobs.data.length,
breakdown: jobTypes
});
}
return results;
}
function categorizeJob(title) {
const lower = title.toLowerCase();
if (lower.includes('engineer') || lower.includes('developer')) return 'Engineering';
if (lower.includes('sales') || lower.includes('account')) return 'Sales';
if (lower.includes('marketing') || lower.includes('growth')) return 'Marketing';
if (lower.includes('product')) return 'Product';
if (lower.includes('design')) return 'Design';
return 'Other';
}
// Compare fintech hiring
const fintechCompanies = [
'https://www.linkedin.com/company/stripe/',
'https://www.linkedin.com/company/plaid/',
'https://www.linkedin.com/company/wise/'
];
analyzeIndustryHiring(fintechCompanies).then(console.table);
4. Enrich CRM Data
Add LinkedIn data to your contacts:
async function enrichCRMContacts(contacts) {
const enriched = [];
for (const contact of contacts) {
// Find LinkedIn URL if not present
let linkedInUrl = contact.linkedInUrl;
if (!linkedInUrl && contact.name && contact.company) {
// Search for profile
const search = await searchLinkedIn(contact.name, contact.company);
linkedInUrl = search.data?.[0]?.profile_url;
}
if (linkedInUrl) {
const profile = await getLinkedInProfile(linkedInUrl);
enriched.push({
...contact,
linkedInUrl,
currentTitle: profile.data?.headline,
location: profile.data?.location,
skills: profile.data?.skills?.slice(0, 5),
experience: profile.data?.experience?.length,
enrichedAt: new Date().toISOString()
});
} else {
enriched.push({ ...contact, enriched: false });
}
await new Promise(r => setTimeout(r, 500));
}
return enriched;
}
Storing LinkedIn Data
SQLite Database
const Database = require('better-sqlite3');
const db = new Database('linkedin_data.db');
db.exec(`
CREATE TABLE IF NOT EXISTS profiles (
profile_url TEXT PRIMARY KEY,
name TEXT,
headline TEXT,
location TEXT,
company TEXT,
connections TEXT,
scraped_at TEXT
);
CREATE TABLE IF NOT EXISTS companies (
company_url TEXT PRIMARY KEY,
name TEXT,
industry TEXT,
company_size TEXT,
headquarters TEXT,
founded TEXT,
scraped_at TEXT
);
`);
function saveProfile(profileUrl, data) {
const stmt = db.prepare(`
INSERT OR REPLACE INTO profiles
VALUES (?, ?, ?, ?, ?, ?, datetime('now'))
`);
stmt.run(
profileUrl,
data.name,
data.headline,
data.location,
data.experience?.[0]?.company || null,
data.connections
);
}
function saveCompany(companyUrl, data) {
const stmt = db.prepare(`
INSERT OR REPLACE INTO companies
VALUES (?, ?, ?, ?, ?, ?, datetime('now'))
`);
stmt.run(
companyUrl,
data.name,
data.industry,
data.company_size,
data.headquarters,
data.founded
);
}
Legal Considerations
Scraping public LinkedIn data is legal when you:
- ✅ Only access publicly visible information (no login required)
- ✅ Don't bypass authentication or access controls
- ✅ Respect rate limits
- ✅ Don't use data for spam or harassment
- ✅ Comply with GDPR/CCPA for personal data
The landmark hiQ Labs v. LinkedIn case (2022) established that scraping public LinkedIn profiles doesn't violate the Computer Fraud and Abuse Act.
Read more: LinkedIn Scraping Legal Guide
API vs DIY Scraping
| DIY Scraping | API |
|---|---|
| Build proxy infrastructure | Proxies included |
| Handle browser fingerprinting | Handled for you |
| Fix when LinkedIn changes | Always maintained |
| Risk account bans | No account needed |
| $300-500/month infrastructure | Pay per request |
For anything beyond a few dozen profiles, an API is far more practical.
Getting Started
- Sign up at sociavault.com
- Get 50 free credits to test
- Copy your API key from the dashboard
- Start extracting LinkedIn data
Frequently Asked Questions
Is LinkedIn scraping legal?
Yes, scraping publicly visible LinkedIn data is legal. The hiQ Labs case established this precedent. However, never scrape data behind login walls or violate privacy laws.
Does LinkedIn block scraping?
LinkedIn actively blocks scrapers. That's why using an API is recommended—it handles proxy rotation, browser fingerprinting, and anti-bot detection.
Can I get email addresses from LinkedIn?
Email addresses aren't publicly displayed on LinkedIn. You'd need the profile owner's permission or use an email finder service separately.
How accurate is scraped LinkedIn data?
Data accuracy depends on when users last updated their profiles. For best results, focus on verified information like current company and title.
Related guides:
Found this helpful?
Share it with others who might benefit
Ready to Try SociaVault?
Start extracting social media data with our powerful API. No credit card required.