Your sales team needs to find all "Head of Sales" contacts at Series B SaaS companies in San Francisco.
Manually, you'd spend hours clicking through LinkedIn search results, scrolling through dozens of pages, copying names into a spreadsheet.
With a people search API: 30 seconds. 147 matching profiles. Complete data on each.
But here's the problem: LinkedIn's official API doesn't let you search for people. At all.
You can post to your feed. You can get your own profile data. But searching for "Head of Sales at SaaS companies in SF"? LinkedIn says that's impossible through their API.
Except it's not impossible. Thousands of sales teams, recruiters, and marketers do it every day.
The answer: Unofficial LinkedIn people search APIs.
This guide shows you exactly how to search LinkedIn programmatically—by name, company, title, location, keywords, and more. We'll cover real use cases (not theory), working code examples, and how to build automated prospect-finding systems.
By the end, you'll be able to search LinkedIn like a pro and build tools that would cost $50,000 to develop from scratch.
Why You Need People Search
Let's be honest about what manual LinkedIn searching actually costs:
The Manual Approach
Scenario: Your sales team needs to find 100 decision-makers for outreach.
Your criteria:
- Title: VP Sales, Head of Sales, or Sales Director
- Industry: SaaS/Software
- Location: United States
- Company size: 50-500 employees
Manual process:
11. LinkedIn search: "VP Sales" + filters
22. Scroll through results (slow loading)
33. Click each profile to verify details
44. Copy name, title, company to spreadsheet
55. Manually check if company fits ICP
66. Find email separately (Hunter.io, etc.)
77. Repeat for "Head of Sales"
88. Repeat for "Sales Director"
99. Remove duplicates
1010. QA the list
11
12Time per qualified contact: 8-12 minutes
13Total time for 100 contacts: 800-1,200 minutes (13-20 hours)
14Cost at $50/hour: $650-1,000And you still have:
- Incomplete profiles (some data missing)
- Manual errors (typos, wrong company)
- Outdated information (people changed jobs)
- No way to re-run or update the list
The API Approach
Same task with LinkdAPI:
1from linkdapi import LinkdAPI
2
3api = LinkdAPI("your_api_key")
4
5# Search once with all criteria
6results = api.search_profiles(
7 keyword="VP Sales OR Head of Sales OR Sales Director",
8 geo_urn="103644278", # United States
9 current_company_size=["51-200", "201-500"],
10 industries="6" # Computer Software
11)
12
13# Get 100+ qualified contacts in seconds
14for profile in results['data']:
15 print(f"{profile['fullName']} - {profile['headline']} at {profile['company']}")
16
17# Time: 30 seconds
18# Cost: $0.30 (100 profiles × $0.003)
19# Quality: Fresh, accurate, structuredSavings: 13-20 hours → 30 seconds. $650-1,000 → $0.30.
That's a 2,000-3,300x ROI.
Real Business Impact
Sales teams:
- Build prospect lists 100x faster
- Always-fresh data (not stale CSV exports)
- Score leads automatically
- Never research the same person twice
Recruiters:
- Source passive candidates at scale
- Find people with specific skills
- Track when candidates change jobs
- Build talent pipelines automatically
Marketers:
- Identify influencers in your space
- Build lookalike audiences
- Segment by job function and seniority
- Find event speakers and panelists
Example ROI:
1SDR team (5 reps):
2- Manual prospecting: 10 hours/week/rep = 50 hours/week
3- API automation: 30 minutes/week total
4- Time saved: 49.5 hours/week
5- Value at $50/hour: $2,475/week = $128,700/year
6
7API cost: $200-400/month = $2,400-4,800/year
8
9ROI: 2,581-5,362%Official API vs Unofficial API
Let's be crystal clear about what LinkedIn's official API can and cannot do:
LinkedIn Official API (Marketing Developer Platform)
What you CANNOT do (the important part):
- ❌ Search for people by name
- ❌ Search by title or company
- ❌ Search by location or industry
- ❌ Get profile data for people you don't know
- ❌ Find contacts matching criteria
- ❌ Build prospect lists
- ❌ Source candidates
What you CAN do (not very useful):
- ✅ Post to your own profile
- ✅ Get your own connections (if they authorize)
- ✅ Manage ad campaigns
- ✅ Get analytics for your company page
The reality: The official API is for managing your own LinkedIn presence, not for finding other people.
Unofficial People Search APIs
These APIs access LinkedIn's public profile data programmatically, including search functionality.
How they work:
- You provide search criteria (title, company, location, etc.)
- API searches LinkedIn's public directory
- Returns structured profile data (JSON format)
- No LinkedIn account needed (account-less architecture)
Legal status: The hiQ Labs vs. LinkedIn case (2022) established that scraping publicly available data is legal under the CFAA. These APIs operate within this legal framework.
Key difference:
1Official API:
2"Give me MY profile data" ✓
3"Search for OTHER people" ✗
4
5Unofficial API:
6"Give me MY profile data" ✗
7"Search for OTHER people" ✓For 99% of business use cases (sales, recruiting, marketing), you need an unofficial API.
What You Can Search By
Here's everything you can search for with LinkdAPI's people search:
Basic Search Criteria
1. Keyword Search:
1# Search by name
2api.search_profiles(keyword="John Smith")
3
4# Search by title
5api.search_profiles(keyword="Software Engineer")
6
7# Search by skills
8api.search_profiles(keyword="Python React AWS")
9
10# Boolean operators
11api.search_profiles(keyword="CEO OR Founder OR Co-Founder")2. Geographic Location:
1# By country
2api.search_profiles(geo_urn="103644278") # United States
3
4# By city
5api.search_profiles(geo_urn="90009706") # San Francisco Bay Area
6
7# By region
8api.search_profiles(geo_urn="102095887") # California3. Current Company:
1# By company ID
2api.search_profiles(current_company_id=["1441"]) # OpenAI
3
4# By company size
5api.search_profiles(current_company_size=["51-200", "201-500"])
6
7# Combine with keyword for specific companies
8api.search_profiles(keyword="Google Microsoft Amazon")4. Industry:
1# By industry code
2api.search_profiles(industries="6") # Computer Software
3
4# Multiple industries
5api.search_profiles(industries="6,3,4") # Software, Healthcare, Finance5. Profile Language:
1# English profiles only
2api.search_profiles(profile_language="en")
3
4# Spanish profiles
5api.search_profiles(profile_language="es")Advanced Filters
6. Past Companies:
1# People who worked at Google
2api.search_profiles(past_company_id=["1441"])
3
4# Find ex-employees of competitors
5api.search_profiles(past_company_id=["competitor1", "competitor2"])7. Schools:
1# Alumni of specific schools
2api.search_profiles(school_id=["18290"]) # Stanford University
3
4# Find Ivy League graduates
5api.search_profiles(school_id=["ivy_league_schools"])8. Keywords (Title, Company, Skills):
1# Multiple search terms (OR logic)
2api.search_profiles(keyword="VP Sales OR Head of Sales OR Director Sales")
3
4# Skills and technologies
5api.search_profiles(keyword="React Node.js TypeScript")
6
7# Company names in keyword
8api.search_profiles(keyword="Stripe Square Shopify")Data You Get Back
1{
2 "success": true,
3 "data": [
4 {
5 "fullName": "Sarah Chen",
6 "headline": "VP of Sales at Acme Corp",
7 "location": "San Francisco Bay Area",
8 "username": "sarachen",
9 "company": "Acme Corp",
10 "companyId": "12345",
11 "profilePicture": "https://...",
12 "connectionDegree": "2nd",
13 "premium": true
14 }
15 ]
16}LinkdAPI Search Methods
LinkdAPI provides a powerful search_profiles() method with extensive filters:
Basic Search
1from linkdapi import LinkdAPI
2
3api = LinkdAPI("your_api_key")
4
5# Simple keyword search
6results = api.search_profiles(keyword="software engineer")
7
8print(f"Found {len(results['data'])} profiles")
9
10for profile in results['data']:
11 print(f"- {profile['fullName']}: {profile['headline']}")Search with Multiple Filters
1# Advanced search with multiple criteria
2results = api.search_profiles(
3 keyword="VP Sales OR Head of Sales",
4 geo_urn="103644278", # United States
5 current_company_size=["51-200", "201-500"],
6 industries="6", # Computer Software
7 profile_language="en",
8 start=0 # Pagination
9)
10
11# Results are already filtered and relevant
12qualified_prospects = results['data']Available Parameters
1def search_profiles(
2 keyword: str = None, # Search term (name, title, skills)
3 geo_urn: str = None, # Geographic location
4 start: int = 0, # Pagination (0, 25, 50, etc.)
5 current_company_id: list = None, # Filter by current company
6 past_company_id: list = None, # Filter by past companies
7 school_id: list = None, # Filter by schools attended
8 industries: str = None, # Industry codes (comma-separated)
9 current_company_size: list = None,# Company size ranges
10 profile_language: str = None # Language code (en, es, fr, etc.)
11)Pagination
1# Get multiple pages of results
2all_results = []
3
4for page in range(4): # Get 100 results (4 pages × 25 results)
5 results = api.search_profiles(
6 keyword="Product Manager",
7 geo_urn="102221843", # New York
8 start=page * 25
9 )
10
11 all_results.extend(results['data'])
12
13 if len(results['data']) < 25:
14 break # No more results
15
16print(f"Total results: {len(all_results)}")Async Search (Bulk Operations)
1from linkdapi import AsyncLinkdAPI
2import asyncio
3
4async def bulk_search(queries):
5 """
6 Search multiple criteria concurrently
7 """
8 async with AsyncLinkdAPI("your_api_key") as api:
9 # Create tasks for each search
10 tasks = [
11 api.search_profiles(keyword=query, geo_urn="103644278")
12 for query in queries
13 ]
14
15 # Execute all searches at once
16 results = await asyncio.gather(*tasks)
17
18 return results
19
20# Search for multiple titles simultaneously
21titles = [
22 "VP Sales",
23 "VP Marketing",
24 "VP Product",
25 "VP Engineering"
26]
27
28all_results = asyncio.run(bulk_search(titles))
29
30# Process results
31for title, result in zip(titles, all_results):
32 print(f"{title}: {len(result['data'])} people found")Use Case 1: Sales Prospecting
Scenario: You're selling marketing automation software. You need to find marketing leaders at mid-size tech companies.
Step 1: Define Your ICP (Ideal Customer Profile)
1from linkdapi import LinkdAPI
2
3api = LinkdAPI("your_api_key")
4
5# Your ICP
6ICP = {
7 'titles': ['VP Marketing', 'Head of Marketing', 'Director Marketing', 'CMO'],
8 'company_size': ['51-200', '201-500'],
9 'industry': '6', # Computer Software
10 'location': '103644278' # United States
11}Step 2: Search for Prospects
1def find_prospects(icp):
2 """
3 Find all prospects matching ICP
4 """
5 all_prospects = []
6
7 # Search for each title variant
8 for title in icp['titles']:
9 print(f"Searching for: {title}")
10
11 results = api.search_profiles(
12 keyword=title,
13 geo_urn=icp['location'],
14 current_company_size=icp['company_size'],
15 industries=icp['industry']
16 )
17
18 all_prospects.extend(results['data'])
19
20 # Remove duplicates (same person with multiple title matches)
21 seen = set()
22 unique_prospects = []
23
24 for prospect in all_prospects:
25 if prospect['username'] not in seen:
26 seen.add(prospect['username'])
27 unique_prospects.append(prospect)
28
29 return unique_prospects
30
31# Find all matching prospects
32prospects = find_prospects(ICP)
33print(f"Found {len(prospects)} unique prospects")Step 3: Enrich and Score
1def score_prospect(profile):
2 """
3 Score prospect based on fit
4 """
5 score = 0
6
7 # Title scoring
8 title = profile['headline'].lower()
9 if 'vp' in title or 'vice president' in title:
10 score += 10
11 elif 'head' in title:
12 score += 8
13 elif 'director' in title:
14 score += 6
15
16 # Company signals
17 if 'saas' in title or 'software' in title:
18 score += 5
19
20 # Premium account (more engaged on LinkedIn)
21 if profile.get('premium'):
22 score += 3
23
24 # Connection degree (warmer if 2nd connection)
25 if profile.get('connectionDegree') == '2nd':
26 score += 5
27
28 return score
29
30# Score all prospects
31for prospect in prospects:
32 prospect['fit_score'] = score_prospect(prospect)
33
34# Sort by score (highest first)
35prospects.sort(key=lambda x: x['fit_score'], reverse=True)
36
37# Top 50 best-fit prospects
38top_prospects = prospects[:50]
39
40print("\nTop 10 Prospects:")
41for i, p in enumerate(top_prospects[:10], 1):
42 print(f"{i}. {p['fullName']} - {p['headline']} (Score: {p['fit_score']})")Step 4: Export for Outreach
1import csv
2
3def export_prospects(prospects, filename='prospects.csv'):
4 """
5 Export prospects to CSV for sales team
6 """
7 with open(filename, 'w', newline='') as f:
8 fieldnames = ['Name', 'Title', 'Company', 'Location', 'LinkedIn', 'Fit Score']
9 writer = csv.DictWriter(f, fieldnames=fieldnames)
10
11 writer.writeheader()
12
13 for p in prospects:
14 writer.writerow({
15 'Name': p['fullName'],
16 'Title': p['headline'],
17 'Company': p.get('company', 'N/A'),
18 'Location': p.get('location', 'N/A'),
19 'LinkedIn': f"https://linkedin.com/in/{p['username']}",
20 'Fit Score': p['fit_score']
21 })
22
23 print(f"Exported {len(prospects)} prospects to {filename}")
24
25# Export top 100 prospects
26export_prospects(top_prospects[:100], 'high_fit_prospects.csv')Result: 100 high-quality, scored prospects ready for outreach in under 5 minutes.
Manual alternative: 50+ hours of work.
Use Case 2: Recruiter Sourcing
Scenario: You need to find senior backend engineers with specific skills for a startup.
The Challenge
Traditional recruiting:
- Post job on LinkedIn (1,000+ unqualified applications)
- Search manually (hours of scrolling)
- Limited to LinkedIn's UI filters
- Can't search by specific tech stack
Better approach: Programmatic candidate sourcing
Step 1: Define Requirements
1# What you're looking for
2REQUIREMENTS = {
3 'title_keywords': 'Senior Backend Engineer OR Staff Engineer OR Principal Engineer',
4 'skill_keywords': 'Python Kubernetes AWS',
5 'location': '90009706', # San Francisco Bay Area
6 'company_size': ['51-200', '201-500', '501-1000'], # Established startups
7 'past_companies': ['1441', '2382910', '791962'] # Google, Meta, Microsoft alumni
8}Step 2: Multi-Criteria Search
1def find_candidates(requirements):
2 """
3 Find candidates matching multiple criteria
4 """
5 candidates = []
6
7 # Search 1: By title
8 title_results = api.search_profiles(
9 keyword=requirements['title_keywords'],
10 geo_urn=requirements['location'],
11 current_company_size=requirements['company_size']
12 )
13
14 candidates.extend(title_results['data'])
15
16 # Search 2: By skills
17 skills_results = api.search_profiles(
18 keyword=requirements['skill_keywords'],
19 geo_urn=requirements['location']
20 )
21
22 candidates.extend(skills_results['data'])
23
24 # Search 3: Alumni from top companies
25 alumni_results = api.search_profiles(
26 past_company_id=requirements['past_companies'],
27 geo_urn=requirements['location']
28 )
29
30 candidates.extend(alumni_results['data'])
31
32 # Remove duplicates
33 seen = set()
34 unique_candidates = []
35
36 for candidate in candidates:
37 if candidate['username'] not in seen:
38 seen.add(candidate['username'])
39 unique_candidates.append(candidate)
40
41 return unique_candidates
42
43candidates = find_candidates(REQUIREMENTS)
44print(f"Found {len(candidates)} potential candidates")Step 3: Filter and Qualify
1def qualifies_for_role(profile):
2 """
3 Check if candidate meets minimum requirements
4 """
5 headline = profile['headline'].lower()
6
7 # Must be an engineer
8 if not any(term in headline for term in ['engineer', 'developer', 'software']):
9 return False
10
11 # Must be senior+ level
12 seniority_terms = ['senior', 'staff', 'principal', 'lead']
13 if not any(term in headline for term in seniority_terms):
14 return False
15
16 # Check for relevant skills
17 skills = profile.get('skills', '').lower()
18 required_skills = ['python', 'backend', 'api']
19
20 skill_match = sum(1 for skill in required_skills if skill in headline or skill in skills)
21
22 return skill_match >= 2 # At least 2 required skills
23
24# Filter candidates
25qualified_candidates = [c for c in candidates if qualifies_for_role(c)]
26
27print(f"Qualified candidates: {len(qualified_candidates)}")Step 4: Prioritize by Signals
1def calculate_candidate_score(profile):
2 """
3 Score candidates by desirability
4 """
5 score = 0
6 headline = profile['headline'].lower()
7
8 # Seniority level
9 if 'principal' in headline or 'staff' in headline:
10 score += 15
11 elif 'senior' in headline:
12 score += 10
13 elif 'lead' in headline:
14 score += 12
15
16 # Current company quality (if they're at a competitor/good company)
17 company = profile.get('company', '').lower()
18 top_companies = ['google', 'meta', 'amazon', 'microsoft', 'netflix', 'uber']
19 if any(comp in company for comp in top_companies):
20 score += 10
21
22 # Premium account (active on LinkedIn = easier to reach)
23 if profile.get('premium'):
24 score += 5
25
26 # 2nd degree connection (mutual connection)
27 if profile.get('connectionDegree') == '2nd':
28 score += 8
29
30 # Tech stack matches
31 desired_tech = ['python', 'kubernetes', 'aws', 'docker', 'microservices']
32 tech_matches = sum(1 for tech in desired_tech if tech in headline)
33 score += tech_matches * 3
34
35 return score
36
37# Score all candidates
38for candidate in qualified_candidates:
39 candidate['recruiter_score'] = calculate_candidate_score(candidate)
40
41# Sort by score
42qualified_candidates.sort(key=lambda x: x['recruiter_score'], reverse=True)
43
44# Top 20 candidates
45top_candidates = qualified_candidates[:20]
46
47print("\nTop 10 Candidates to Contact:")
48for i, c in enumerate(top_candidates[:10], 1):
49 print(f"{i}. {c['fullName']} - {c['headline']}")
50 print(f" Company: {c.get('company', 'N/A')} | Score: {c['recruiter_score']}")Step 5: Track Outreach
1import json
2from datetime import datetime
3
4def save_candidate_pipeline(candidates):
5 """
6 Save candidates to recruiting pipeline
7 """
8 pipeline = []
9
10 for candidate in candidates:
11 pipeline.append({
12 'name': candidate['fullName'],
13 'headline': candidate['headline'],
14 'company': candidate.get('company'),
15 'location': candidate.get('location'),
16 'linkedin_url': f"https://linkedin.com/in/{candidate['username']}",
17 'score': candidate['recruiter_score'],
18 'status': 'to_contact',
19 'added_date': datetime.now().isoformat(),
20 'notes': ''
21 })
22
23 with open('candidate_pipeline.json', 'w') as f:
24 json.dump(pipeline, f, indent=2)
25
26 print(f"Saved {len(pipeline)} candidates to pipeline")
27
28save_candidate_pipeline(top_candidates)Start building with 100 free credits
Access profiles, companies, jobs, and more through our reliable, high-performance API. No credit card required.
Result: 20 highly-qualified candidates identified and prioritized in 10 minutes.
Manual recruiting: 10-15 hours to find the same candidates.
Use Case 3: Building Custom Search Tools
Scenario: You want to build an internal tool for your team to search LinkedIn on-demand.
Simple Web Search Interface
1from flask import Flask, request, jsonify, render_template
2from linkdapi import LinkdAPI
3
4app = Flask(__name__)
5api = LinkdAPI("your_api_key")
6
7@app.route('/')
8def home():
9 return render_template('search.html')
10
11@app.route('/api/search', methods=['POST'])
12def search():
13 """
14 API endpoint for LinkedIn search
15 """
16 data = request.json
17
18 # Extract search parameters
19 keyword = data.get('keyword', '')
20 location = data.get('location', '')
21 company_size = data.get('company_size', [])
22
23 # Search LinkedIn
24 results = api.search_profiles(
25 keyword=keyword,
26 geo_urn=location if location else None,
27 current_company_size=company_size if company_size else None
28 )
29
30 # Format results
31 profiles = []
32 for profile in results['data']:
33 profiles.append({
34 'name': profile['fullName'],
35 'headline': profile['headline'],
36 'company': profile.get('company', 'N/A'),
37 'location': profile.get('location', 'N/A'),
38 'linkedin_url': f"https://linkedin.com/in/{profile['username']}",
39 'image': profile.get('profilePicture')
40 })
41
42 return jsonify({
43 'success': True,
44 'count': len(profiles),
45 'profiles': profiles
46 })
47
48if __name__ == '__main__':
49 app.run(debug=True)HTML Interface (search.html)
1<!DOCTYPE html>
2<html>
3<head>
4 <title>LinkedIn Search Tool</title>
5 <style>
6 body { font-family: Arial, sans-serif; max-width: 1200px; margin: 0 auto; padding: 20px; }
7 .search-box { background: #f5f5f5; padding: 20px; border-radius: 8px; }
8 input, select { padding: 10px; margin: 5px; width: 300px; }
9 button { padding: 10px 20px; background: #0077b5; color: white; border: none; cursor: pointer; }
10 .results { margin-top: 20px; }
11 .profile-card { border: 1px solid #ddd; padding: 15px; margin: 10px 0; border-radius: 5px; }
12 .profile-card img { width: 60px; height: 60px; border-radius: 50%; float: left; margin-right: 15px; }
13 </style>
14</head>
15<body>
16 <h1>🔍 LinkedIn Search Tool</h1>
17
18 <div class="search-box">
19 <input type="text" id="keyword" placeholder="Job title, skills, or name">
20 <select id="location">
21 <option value="">All Locations</option>
22 <option value="103644278">United States</option>
23 <option value="90009706">San Francisco Bay Area</option>
24 <option value="102221843">New York City</option>
25 </select>
26 <button onclick="search()">Search</button>
27 </div>
28
29 <div id="results" class="results"></div>
30
31 <script>
32 async function search() {
33 const keyword = document.getElementById('keyword').value;
34 const location = document.getElementById('location').value;
35
36 const response = await fetch('/api/search', {
37 method: 'POST',
38 headers: {'Content-Type': 'application/json'},
39 body: JSON.stringify({keyword, location})
40 });
41
42 const data = await response.json();
43 displayResults(data.profiles);
44 }
45
46 function displayResults(profiles) {
47 const resultsDiv = document.getElementById('results');
48 resultsDiv.innerHTML = ``;
49
50 profiles.forEach(profile => {
51 resultsDiv.innerHTML += `59`;
60 });
61 }
62 </script>
63</body>
64</html>


