Logo
LinkedIn API

How to Search LinkedIn People Without API (No OAuth Needed)

Learn how to search LinkedIn profiles and extract people data without using the official API. Includes scraping, automation, and alternative methods.

How to Search LinkedIn People Without API (No OAuth Needed)

How to Search LinkedIn People Without API (No OAuth Needed)

LinkedIn is the world's largest professional network, making it an invaluable resource for recruiters, sales teams, and data professionals looking to find and connect with specific individuals. Whether you're building a recruiting platform, enriching CRM data, or conducting market research, the ability to search for people on LinkedIn programmatically is crucial.

However, LinkedIn's official People Search API has become increasingly restrictive, requiring OAuth authentication, partnership approvals, and offering limited search capabilities. This comprehensive guide explores how to search LinkedIn for people without using the official API, leveraging scraping methods and alternative solutions that bypass these restrictions.

Table of Contents

Limitations of LinkedIn's Official People Search API

LinkedIn once offered a People Search API that allowed developers to query member profiles with various filters. However, access to this functionality has been dramatically curtailed over the years.

Current State of LinkedIn's Official API

What Changed:

  • Deprecated Features: LinkedIn removed public access to most search endpoints in 2015
  • Partner-Only Access: Search functionality now requires LinkedIn partnership status
  • OAuth Required: All requests must use OAuth 2.0 with user authentication
  • Limited Query Filters: Even with access, available search parameters are restricted
  • Rate Limiting: Strict quotas on number of searches per day

Major Restrictions

  1. No Public Access: The People Search API is not available to general developers
  2. Application Approval: Requires lengthy approval process with no guarantee
  3. Usage Constraints: Limited to specific use cases approved by LinkedIn
  4. Data Restrictions: Cannot store or cache search results long-term
  5. Cost: Enterprise pricing for partners with significant usage

Why Developers Need Alternatives

Given these limitations, most developers and businesses cannot:

  • Build recruiting tools that search for candidates
  • Create lead generation platforms that find prospects
  • Develop CRM enrichment features that match contacts
  • Conduct market research on professional demographics

This has created a strong demand for alternative methods to search LinkedIn people without requiring official API access.

How to Search LinkedIn Without Using API

There are several approaches to searching LinkedIn for people programmatically without using the official API:

1. Manual LinkedIn Search URLs

LinkedIn's search functionality works through URL parameters that you can construct and access directly.

Example Search URL Structure:

https://www.linkedin.com/search/results/people/?keywords={search_term}&geoUrn={location_code}

Common URL Parameters:

  • keywords: General search term (name, title, company)
  • firstName: Filter by first name
  • lastName: Filter by last name
  • title: Job title filter
  • company: Current or past company
  • school: Educational institution
  • geoUrn: Geographic location code
  • network: Connection degree (1st, 2nd, 3rd)

Example URLs:

# Search for software engineers in San Francisco
https://www.linkedin.com/search/results/people/?keywords=software%20engineer&geoUrn=urn:li:geo:90000084

# Search by name and title
https://www.linkedin.com/search/results/people/?firstName=john&lastName=smith&title=manager

# Search by company
https://www.linkedin.com/search/results/people/?company=microsoft

2. Web Scraping with Automation Tools

Use headless browsers to programmatically access LinkedIn search pages and extract results.

Popular Tools:

  • Puppeteer (Node.js): Chromium-based automation
  • Playwright (Node.js/Python): Cross-browser automation
  • Selenium (Multiple languages): Web testing framework
  • Scrapy (Python): Web scraping framework

Challenges:

  • Requires handling cookies and sessions
  • Must bypass LinkedIn's anti-bot detection
  • Needs proxy rotation for scale
  • Maintenance required when HTML structure changes

3. Third-Party LinkedIn Scraper APIs

Specialized APIs that handle the complexity of scraping LinkedIn search results, providing clean, structured data through simple REST endpoints.

Advantages:

  • No OAuth required
  • Pre-built infrastructure handles anti-bot measures
  • Structured JSON responses
  • Pay-per-use pricing models
  • Maintained by the provider

This is often the most practical solution for developers and businesses.

Using a LinkedIn Search Scraper API

For most use cases, leveraging a specialized LinkedIn scraper API provides the best balance of ease of use, reliability, and scalability.

How It Works

LinkedIn scraper APIs provide REST endpoints that accept search parameters and return structured profile data:

  1. Make API Request: Send search criteria (name, title, location, etc.)
  2. API Handles Scraping: Service handles headless browsing and data extraction
  3. Receive Structured Data: Get JSON response with profile information
  4. Paginate Results: Access additional pages for large result sets

Available Search Parameters

The LinkedIn people search API supports a comprehensive set of optional parameters for precise filtering:

Parameter Type Description Example
name String Search keyword for people (general search) "john"
first_name String Filter by first name "john"
last_name String Filter by last name "smith"
title String Filter by job title or headline "software engineer"
company String Filter by company name "microsoft"
school String Filter by educational institution "stanford university"
geocode_location String Geographical code for location-based search. find location code here "103644278" (United States)
current_company String Filter by current company ID Company ID from LinkedIn
profile_language String Filter by profile language "en", "es", "fr"
industry String Filter by industry ID Industry ID from LinkedIn
service_category String Filter by service category ID Service category ID
page Number Page number for pagination (default: 1) 1, 2, 3

Note: All parameters are optional. You can combine multiple parameters for more precise search results.

Here's a practical example using a LinkedIn scraper API with Node.js:

const axios = require("axios");

async function searchLinkedInPeople(searchParams) {
  const options = {
    method: "GET",
    url: "https://fresh-linkedin-scraper-api.p.rapidapi.com/api/v1/search/people",
    params: {
      // Basic search parameters
      name: searchParams.name,                    // General keyword search
      first_name: searchParams.firstName,         // First name filter
      last_name: searchParams.lastName,           // Last name filter
      
      // Professional filters
      title: searchParams.title,                  // Job title
      company: searchParams.company,              // Company name
      current_company: searchParams.currentCompany, // Company ID
      
      // Education filter
      school: searchParams.school,                // Educational institution
      
      // Location and demographics
      geocode_location: searchParams.geocodeLocation, // Geographic code
      profile_language: searchParams.profileLanguage, // Profile language
      
      // Industry and service
      industry: searchParams.industry,            // Industry ID
      service_category: searchParams.serviceCategory, // Service category ID
      
      // Pagination
      page: searchParams.page || 1                // Page number (default: 1)
    },
    headers: {
      "x-rapidapi-key": "YOUR_API_KEY",
      "x-rapidapi-host": "fresh-linkedin-scraper-api.p.rapidapi.com"
    }
  };

  try {
    const response = await axios.request(options);
    
    if (response.data.success) {
      return {
        success: true,
        results: response.data.data,
        pagination: {
          currentPage: response.data.page,
          total: response.data.total,
          hasMore: response.data.has_more
        },
        processTime: response.data.process_time,
        cost: response.data.cost
      };
    } else {
      throw new Error(response.data.message || "Search failed");
    }
  } catch (error) {
    console.error("LinkedIn search error:", error);
    throw error;
  }
}

// Example 1: Search by name and title
searchLinkedInPeople({
  firstName: "john",
  lastName: "smith",
  title: "software engineer",
  page: 1
})
  .then(results => {
    console.log(`Found ${results.pagination.total} total results`);
    console.log(`Showing page ${results.pagination.currentPage}`);
    
    results.results.forEach(person => {
      console.log(`\nName: ${person.full_name}`);
      console.log(`Title: ${person.title}`);
      console.log(`Location: ${person.location}`);
      console.log(`Profile: ${person.url}`);
    });
  })
  .catch(err => console.error(err));

// Example 2: Search by company and location
searchLinkedInPeople({
  company: "google",
  geocodeLocation: "103644278", // United States
  title: "product manager",
  page: 1
})
  .then(results => {
    console.log(`Found ${results.results.length} Google Product Managers`);
  });

// Example 3: Search by education
searchLinkedInPeople({
  school: "stanford university",
  title: "data scientist",
  page: 1
})
  .then(results => {
    console.log(`Found ${results.results.length} Stanford Data Scientists`);
  });

Response Structure

The API returns structured data for each profile found:

{
  "success": true,
  "message": "success",
  "process_time": 884,
  "data": [
    {
      "id": "478387397",
      "urn": "ACoAAByDnMUBr75NmvcrLQrNyMolO141Kg7TD_I",
      "url": "https://www.linkedin.com/in/john-heyer-685264114",
      "public_identifier": "john-heyer-685264114",
      "full_name": "John Heyer",
      "title": "ML @ depthfirst | ex Scale / Amazon / MIT",
      "location": "Boston, MA",
      "is_premium": false,
      "avatar": [
        {
          "width": 100,
          "height": 100,
          "url": "https://media.licdn.com/dms/image/...",
          "expires_at": 1752105600000
        }
      ],
      "services": []
    },
    {
      "id": "426203025",
      "urn": "ACoAABlnV5EBp1Z8-e9CYtCdibCRxSLDC5WdF6M",
      "url": "https://www.linkedin.com/in/john-finberg",
      "public_identifier": "john-finberg",
      "full_name": "John Finberg",
      "title": "CS Master's @ Brown | Former YC Founder",
      "location": "San Francisco, CA",
      "is_premium": false,
      "avatar": [
        {
          "width": 100,
          "height": 100,
          "url": "https://media.licdn.com/dms/image/...",
          "expires_at": 1752105600000
        }
      ],
      "services": []
    }
  ],
  "cost": 1,
  "page": 1,
  "total": 2173900,
  "has_more": true
}

Key Response Fields

  • id: LinkedIn's internal user ID
  • urn: LinkedIn's URN identifier
  • url: Full LinkedIn profile URL
  • public_identifier: URL slug for the profile
  • full_name: Person's display name
  • title: Current job title/headline
  • location: Geographic location
  • is_premium: Whether the user has LinkedIn Premium
  • avatar: Profile picture URLs in various sizes
  • page: Current page number
  • total: Total number of results found
  • has_more: Whether more pages are available

Advanced Search Example

Here's a more sophisticated search function with filtering and pagination:

async function findCandidates(criteria) {
  const allResults = [];
  let currentPage = 1;
  let hasMore = true;
  
  while (hasMore && currentPage <= criteria.maxPages) {
    const response = await searchLinkedInPeople({
      title: criteria.jobTitle,
      company: criteria.company,
      school: criteria.school,
      geocodeLocation: criteria.geocodeLocation,
      industry: criteria.industry,
      profileLanguage: criteria.profileLanguage,
      page: currentPage
    });
    
    // Filter results based on criteria
    const filtered = response.results.filter(person => {
      // Only include people with certain keywords in title
      if (criteria.mustInclude) {
        return criteria.mustInclude.some(keyword => 
          person.title.toLowerCase().includes(keyword.toLowerCase())
        );
      }
      return true;
    });
    
    allResults.push(...filtered);
    hasMore = response.pagination.hasMore;
    currentPage++;
    
    // Rate limiting - wait 2 seconds between requests
    if (hasMore && currentPage <= criteria.maxPages) {
      await new Promise(resolve => setTimeout(resolve, 2000));
    }
  }
  
  return allResults;
}

// Usage: Find senior software engineers in United States from Stanford
findCandidates({
  jobTitle: "software engineer",
  geocodeLocation: "103644278", // United States
  school: "stanford university",
  mustInclude: ["senior", "lead", "principal"],
  maxPages: 5
})
  .then(candidates => {
    console.log(`Found ${candidates.length} qualified candidates`);
    candidates.forEach(c => {
      console.log(`${c.full_name} - ${c.title} - ${c.location}`);
    });
  });

Method Comparison

Here's a comprehensive comparison of different approaches to searching LinkedIn people:

Method Pros Cons Best For
Official LinkedIn API - Official, stable- Structured data- Low risk of blocking - Requires partnership- OAuth complexity- Very limited access- High cost Enterprise partners with LinkedIn relationships
LinkedIn Scraper API - No OAuth needed- Easy integration- Flexible search- Maintained by provider- Affordable - Costs per request- Violates LinkedIn ToS Most developers and businesses needing scalable search
Custom Web Scraping - Full control- No per-request costs- Customizable - High maintenance- Anti-bot challenges- Slow to build- Requires proxies Teams with scraping expertise and time to build
Manual LinkedIn Search - Free- No coding needed - Not scalable- Time-consuming- No automation Small, one-off searches

Cost Comparison

LinkedIn Scraper API:

  • Pay-per-request model (typically $0.001-$0.01 per search)
  • No infrastructure costs
  • Predictable pricing

Custom Scraping:

  • Server/proxy costs ($100-$1000+/month)
  • Development time (weeks to months)
  • Ongoing maintenance

Official API:

  • Enterprise pricing (often $10,000+/year)
  • Limited quotas
  • Partnership requirements

Best Practices for LinkedIn People Search Automation

1. Implement Smart Rate Limiting

Avoid overwhelming LinkedIn's servers and reduce blocking risk:

class RateLimiter {
  constructor(requestsPerMinute) {
    this.requestsPerMinute = requestsPerMinute;
    this.queue = [];
    this.processing = false;
  }
  
  async execute(fn) {
    return new Promise((resolve, reject) => {
      this.queue.push({ fn, resolve, reject });
      if (!this.processing) {
        this.processQueue();
      }
    });
  }
  
  async processQueue() {
    this.processing = true;
    while (this.queue.length > 0) {
      const { fn, resolve, reject } = this.queue.shift();
      try {
        const result = await fn();
        resolve(result);
      } catch (error) {
        reject(error);
      }
      // Wait between requests
      const delay = 60000 / this.requestsPerMinute;
      await new Promise(r => setTimeout(r, delay));
    }
    this.processing = false;
  }
}

// Usage
const limiter = new RateLimiter(10); // 10 requests per minute

async function searchWithRateLimit(params) {
  return limiter.execute(() => searchLinkedInPeople(params));
}

2. Cache Search Results

Reduce API costs and improve performance:

const cache = new Map();
const CACHE_DURATION = 24 * 60 * 60 * 1000; // 24 hours

function getCacheKey(params) {
  return JSON.stringify(params);
}

async function searchWithCache(params) {
  const key = getCacheKey(params);
  const cached = cache.get(key);
  
  if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
    console.log("Returning cached results");
    return cached.data;
  }
  
  const results = await searchLinkedInPeople(params);
  cache.set(key, {
    data: results,
    timestamp: Date.now()
  });
  
  return results;
}

3. Use Realistic User Agents

When building custom scrapers, rotate user agents:

const userAgents = [
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
  "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
];

function getRandomUserAgent() {
  return userAgents[Math.floor(Math.random() * userAgents.length)];
}

4. Implement Error Handling and Retry Logic

Handle transient failures gracefully:

async function searchWithRetry(params, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await searchLinkedInPeople(params);
    } catch (error) {
      console.log(`Attempt ${attempt} failed:`, error.message);
      
      if (attempt === maxRetries) {
        throw error;
      }
      
      // Exponential backoff
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

5. Combine Search with AI Entity Matching

For better accuracy when searching by name:

async function findPersonByName(fullName, additionalCriteria = {}) {
  // Split name into components
  const nameParts = fullName.trim().split(" ");
  const firstName = nameParts[0];
  const lastName = nameParts.slice(1).join(" ");
  
  // Search with name components
  const results = await searchLinkedInPeople({
    firstName,
    lastName,
    ...additionalCriteria
  });
  
  // Use fuzzy matching to find best match
  const matches = results.results.map(person => {
    const similarity = calculateNameSimilarity(fullName, person.full_name);
    return { ...person, similarity };
  });
  
  // Sort by similarity and return best matches
  return matches.sort((a, b) => b.similarity - a.similarity);
}

function calculateNameSimilarity(name1, name2) {
  // Simple Levenshtein distance implementation
  // In production, use a library like 'string-similarity'
  const lower1 = name1.toLowerCase();
  const lower2 = name2.toLowerCase();
  
  if (lower1 === lower2) return 1.0;
  if (lower1.includes(lower2) || lower2.includes(lower1)) return 0.8;
  
  // More sophisticated matching here
  return 0.5;
}

6. Respect LinkedIn's Resources

  • Limit concurrent requests: Keep it to 1-2 per second
  • Use off-peak hours: Reduce load during high-traffic times
  • Cache aggressively: Don't re-fetch the same data
  • Monitor for blocks: Implement circuit breakers if errors spike

Use Cases

Use Case 1: Recruiting at Scale

Scenario: A recruiting firm needs to find 1,000 software engineers in specific locations.

Implementation:

async function findCandidatesForRole(role) {
  const geocodes = {
    "San Francisco": "90000084",
    "New York": "102571732",
    "Austin": "101318387",
    "Seattle": "103644278"
  };
  
  const allCandidates = [];
  
  for (const [city, geocode] of Object.entries(geocodes)) {
    console.log(`Searching in ${city}...`);
    
    const results = await searchLinkedInPeople({
      title: role.title,
      geocodeLocation: geocode,
      school: role.preferredSchool,
      profileLanguage: "en",
      page: 1
    });
    
    // Filter by experience level
    const qualified = results.results.filter(person => {
      return role.keywords.some(keyword => 
        person.title.toLowerCase().includes(keyword)
      );
    });
    
    allCandidates.push(...qualified);
    
    // Rate limiting
    await new Promise(resolve => setTimeout(resolve, 2000));
  }
  
  return allCandidates;
}

// Usage
findCandidatesForRole({
  title: "software engineer",
  keywords: ["senior", "lead", "staff", "principal"],
  preferredSchool: "stanford university"
})
  .then(candidates => {
    console.log(`Found ${candidates.length} qualified candidates`);
    // Export to CSV or ATS system
  });

Business Value: Reduce recruiting time by 70%, increase candidate pipeline quality.

Use Case 2: CRM Enrichment

Scenario: A B2B company wants to enrich their CRM contacts with LinkedIn profiles.

Implementation:

async function enrichCRMContact(contact) {
  try {
    // Search by name and company
    const results = await searchLinkedInPeople({
      firstName: contact.firstName,
      lastName: contact.lastName,
      company: contact.company,
      page: 1
    });
    
    if (results.results.length === 0) {
      return { ...contact, linkedinMatch: null };
    }
    
    // Find best match
    const bestMatch = results.results[0];
    
    return {
      ...contact,
      linkedinUrl: bestMatch.url,
      linkedinTitle: bestMatch.title,
      linkedinLocation: bestMatch.location,
      linkedinId: bestMatch.id,
      lastEnriched: new Date().toISOString()
    };
  } catch (error) {
    console.error(`Failed to enrich ${contact.firstName} ${contact.lastName}`);
    return contact;
  }
}

// Batch enrichment
async function enrichCRMDatabase(contacts) {
  const enriched = [];
  
  for (const contact of contacts) {
    const enrichedContact = await enrichCRMContact(contact);
    enriched.push(enrichedContact);
    
    // Rate limiting
    await new Promise(resolve => setTimeout(resolve, 1000));
  }
  
  return enriched;
}

Business Value: Improve data quality, enable better targeting, increase sales effectiveness.

Use Case 3: Market Research

Scenario: Analyzing career paths and job market trends in specific industries.

Implementation:

async function analyzeJobMarket(industry, titles) {
  const analysis = {
    totalProfessionals: 0,
    byTitle: {},
    byLocation: {},
    premiumPercentage: 0
  };
  
  for (const title of titles) {
    const results = await searchLinkedInPeople({
      title: title,
      page: 1
    });
    
    analysis.totalProfessionals += results.pagination.total;
    analysis.byTitle[title] = results.pagination.total;
    
    // Analyze locations
    results.results.forEach(person => {
      const loc = person.location || "Unknown";
      analysis.byLocation[loc] = (analysis.byLocation[loc] || 0) + 1;
      
      if (person.is_premium) {
        analysis.premiumPercentage++;
      }
    });
    
    await new Promise(resolve => setTimeout(resolve, 2000));
  }
  
  analysis.premiumPercentage = 
    (analysis.premiumPercentage / analysis.totalProfessionals) * 100;
  
  return analysis;
}

// Usage
analyzeJobMarket("Technology", [
  "Software Engineer",
  "Data Scientist",
  "Product Manager",
  "DevOps Engineer"
])
  .then(analysis => {
    console.log("Job Market Analysis:", analysis);
  });

Business Value: Understand market dynamics, identify talent hotspots, inform business strategy.

LinkedIn's Terms of Service:

  • Prohibits automated scraping without permission
  • Reserves right to block or ban accounts
  • Can pursue legal action for violations

Reality:

  • Scraping public data is common practice
  • LinkedIn rarely takes action against users scraping public profiles
  • Focus is on preventing abuse and spam

Best Practices for Compliance

  1. Only Scrape Public Data

    • Don't access data requiring login
    • Respect profile privacy settings
    • Focus on publicly visible information
  2. Respect Data Protection Laws

    • GDPR (EU): Requires lawful basis for processing personal data
    • CCPA (California): Mandates disclosure and opt-out rights
    • Store data securely and allow deletion requests
  3. Use Data Responsibly

    • Don't use for spam or harassment
    • Provide transparency in privacy policies
    • Honor opt-out requests promptly
    • Don't sell personal data without consent
  4. Implement Data Retention Policies

    • Only keep data as long as needed
    • Regularly purge outdated information
    • Secure sensitive personal information

Risk Mitigation Strategies

// Example: Compliance-focused data handling
class LinkedInDataHandler {
  constructor() {
    this.dataRetentionDays = 90;
  }
  
  async storeSearchResult(profile) {
    // Only store necessary fields
    const sanitized = {
      linkedin_id: profile.id,
      full_name: profile.full_name,
      title: profile.title,
      location: profile.location,
      profile_url: profile.url,
      collected_at: new Date(),
      expires_at: new Date(Date.now() + this.dataRetentionDays * 24 * 60 * 60 * 1000)
    };
    
    // Don't store: email, phone, detailed personal info
    return sanitized;
  }
  
  async purgeExpiredData() {
    // Automatically delete data past retention period
    const cutoff = new Date(Date.now() - this.dataRetentionDays * 24 * 60 * 60 * 1000);
    // Delete records where expires_at < cutoff
  }
}

Ethical Guidelines

  • Transparency: Be clear about data collection in your privacy policy
  • Purpose Limitation: Only use data for stated purposes
  • Accuracy: Keep data current and correct
  • Security: Protect data with appropriate safeguards
  • Accountability: Have processes to handle complaints and requests

Conclusion

Searching LinkedIn for people without using the official API is not only possible but often more practical for most developers and businesses. While LinkedIn's official People Search API remains restrictive and difficult to access, alternative methods provide flexible, scalable solutions for finding and extracting professional profile data.

Key Takeaways

Official LinkedIn API:

  • ❌ Requires partnership and approval
  • ❌ Limited search capabilities
  • ❌ OAuth complexity
  • ✅ Official and stable

LinkedIn Scraper APIs:

  • ✅ No OAuth required
  • ✅ Easy integration
  • ✅ Comprehensive search filters
  • ✅ Affordable pricing
  • ⚠️ Violates LinkedIn ToS

Best Approach:

  • Use specialized scraper APIs for most use cases
  • Implement rate limiting and caching
  • Focus on public data only
  • Comply with data protection laws
  • Use data ethically and responsibly

Getting Started

For developers and businesses needing to search LinkedIn people at scale, using a reliable LinkedIn scraper API like the Fresh LinkedIn Scraper API provides:

  • Simple REST API: Easy integration in any language
  • Comprehensive Search: Filter by name, title, company, location
  • Structured Data: Clean JSON responses with all profile fields
  • Pagination Support: Access thousands of results
  • Maintained Infrastructure: No need to build or maintain scrapers
  • Flexible Pricing: Pay only for what you use

Deepen your LinkedIn data extraction knowledge with these guides:

Ready to start searching LinkedIn people?

Whether you're recruiting top talent, generating leads, or enriching your CRM data, the ability to search LinkedIn programmatically without API restrictions opens up powerful opportunities. Start with a professional LinkedIn scraper API and unlock the full potential of LinkedIn's professional network data today.