@lineai/linkedin-api
Version:
Professional LinkedIn API client with TypeScript support, entity classes, and developer-friendly features. Perfect for AI coders, recruiting, lead generation, market research, and content analysis. Includes comprehensive JSDoc, helper constants (LOCATIONS
696 lines (579 loc) • 21.2 kB
Markdown
# LinkedIn API - AI Coder Usage Guide
This guide is specifically designed for AI assistants and automated code generation systems working with the LinkedIn API package.
## Quick Capability Overview
| Operation | Method | Purpose | Key Parameters | Returns |
|-----------|--------|---------|----------------|---------|
| **Profile Search** | `searchProfiles()` | Find profiles by criteria | keywords, geo, company | ProfileSearchResult |
| **Profile Details** | `getProfile()` | Get full profile data | username | LinkedInProfile |
| **Company Search** | `searchCompanies()` | Find companies by criteria | keywords, industries, sizes | CompanySearchResult |
| **Company Details** | `getCompany()` | Get full company data | username | LinkedInCompany |
| **Post Search** | `searchPosts()` | Find posts by criteria | keywords, author, datePosted | PostSearchResult |
| **Post Details** | `getPost()` | Get full post data | postId | LinkedInPost |
## Essential Import Pattern
```javascript
import LinkedInAPI, {
LOCATIONS,
INDUSTRIES,
COMPANY_SIZES,
LinkedInError,
RateLimitError,
NotFoundError
} from '@lineai/linkedin-api';
const api = new LinkedInAPI(process.env.RAPIDAPI_KEY);
```
## 🆕 v1.3.8+ Enhanced Features
### Improved TypeScript Types (v1.3.8)
```typescript
// v1.3.8+: Better type safety for post search results
import { PostSearchItemData, PostSearchItemAuthorData } from '@lineai/linkedin-api';
const posts = await api.searchPosts({ keyword: 'AI' });
// Now properly typed with PostSearchItemAuthorData interface
posts.items.forEach((post: PostSearchItemData) => {
const author = post.author; // Type: PostSearchItemAuthorData
// Enhanced IntelliSense and type checking
console.log(author.fullName); // ✅ Correct property name
console.log(author.headline); // ✅ Available in search results
console.log(author.username); // ✅ Profile identifier
console.log(author.type); // ✅ Always 'user' for search results
});
// Compare with full post data (uses different PostAuthor interface)
const fullPost = await api.getPost(posts.items[0].urn);
const fullAuthor = fullPost.getAuthor(); // Type: PostAuthor
// Different schema - has firstName/lastName instead of fullName
console.log(`${fullAuthor.firstName} ${fullAuthor.lastName}`);
```
### Package Optimization (v1.3.6)
```javascript
// v1.3.6+: Optimized package structure for better compatibility
// - Removed examples directory to reduce package size
// - Fixed Next.js build compatibility issues
// - Streamlined file structure for better module resolution
// Smaller, more focused package for production use
import LinkedInAPI from '@lineai/linkedin-api';
const api = new LinkedInAPI(process.env.RAPIDAPI_KEY);
```
### Streamlined Dependencies (v1.3.5)
```javascript
// v1.3.5+: Cleaner development environment
// - Removed Prettier and related ESLint configs
// - Reduced package size and dependency conflicts
// - Simplified build process for better maintainability
// Package is now more focused and lightweight
import LinkedInAPI from '@lineai/linkedin-api';
const api = new LinkedInAPI(process.env.RAPIDAPI_KEY);
```
### Username Field Consistency (v1.3.4)
```javascript
// v1.3.4+: Company search results consistently use 'username' field
const companies = await api.searchCompanies({ keyword: 'tech' });
// ✅ Consistent field name across all search types
companies.items.forEach(company => {
console.log(company.username); // Same field name as profile search
});
// ✅ Works seamlessly with getCompany method
const fullCompany = await api.getCompany(companies.items[0].username);
console.log(fullCompany.getName());
```
## v1.3.1+ Enhanced Features
### Fixed Location Parameter Types (v1.3.1)
```javascript
// v1.3.1+: Location constants are now properly typed as numbers
const params = {
keyword: 'technology',
locations: [LOCATIONS.US.SAN_FRANCISCO], // Now correctly typed as number: 102277331
companySizes: [COMPANY_SIZES.LARGE]
};
// ✅ Works correctly with LinkedIn API (no "Payload is incorrect" errors)
const companies = await api.searchCompanies(params);
// ✅ Profile search also handles number locations correctly
const profiles = await api.searchProfiles({
keywords: 'engineer',
geo: [LOCATIONS.US.SEATTLE] // Number gets joined to "104116203" for GET query param
});
```
## v1.3.0+ Enhanced Features
### Type Safety & Immutability
```javascript
// v1.3.0+: Parameters are now immutable
const searchParams = { keywords: 'engineer', page: 1, minItems: 10 };
const result = await api.searchProfiles(searchParams);
// ✅ Original params remain unchanged
console.log(searchParams.page); // Still 1
// ✅ Access via getter returns defensive copy
console.log(result.params.page); // 1
result.params.page = 999; // Won't affect original
console.log(result.params.page); // Still 1
```
### Enhanced Caching (v1.3.0+)
```javascript
// First call hits API
const profile1 = await api.getProfile('satyanadella'); // ~2000ms
// Second call hits cache (100% faster)
const profile2 = await api.getProfile('satyanadella'); // ~0ms
// Cache works for all get methods
const company1 = await api.getCompany('microsoft'); // API call
const company2 = await api.getCompany('microsoft'); // Cached
```
### Better Debug Information (v1.3.0+)
```javascript
// Set NODE_ENV=development for enhanced debug logs
process.env.NODE_ENV = 'development';
const result = await api.searchProfiles({ keywords: 'CEO', minItems: 5 });
// Logs now show: responseHasData: true, dataHasItems: true, itemsCount: 3
```
## Core Usage Patterns
### 1. Basic Profile Search
```javascript
// Simple keyword search
const results = await api.searchProfiles({ keywords: 'software engineer' });
// Location-based search (always use LOCATIONS constants)
const sfEngineers = await api.searchProfiles({
keywords: 'frontend developer',
geo: [LOCATIONS.US.SAN_FRANCISCO]
});
// Multi-criteria search
const targetProfiles = await api.searchProfiles({
keywords: 'product manager',
geo: [LOCATIONS.US.NEW_YORK],
company: 'Meta'
});
```
### 2. Profile Data Access
```javascript
const profile = await api.getProfile('satyanadella');
// Safe data access (always use helper methods)
const name = profile.getFullName(); // "Satya Nadella"
const headline = profile.getHeadline(); // "CEO at Microsoft"
const url = profile.getLinkedInUrl(); // Full LinkedIn URL
const location = profile.getLocation(); // Location object
const currentJob = profile.getCurrentPosition(); // Current position object
```
### 3. Company Operations
```javascript
// Company search with filters
const techCompanies = await api.searchCompanies({
keywords: 'artificial intelligence',
industries: [INDUSTRIES.TECHNOLOGY],
companySizes: [COMPANY_SIZES.LARGE, COMPANY_SIZES.ENTERPRISE]
});
// Company search with minItems (v1.2.2+)
const manyCompanies = await api.searchCompanies({
keywords: 'startup',
minItems: 15, // Keep retrying until 15+ companies found
maxRetries: 5 // But don't try more than 5 times
});
// Company details
const company = await api.getCompany('microsoft');
const companyName = company.getName();
const followerCount = company.getFollowerCount();
```
### 4. Post Operations
```javascript
// Recent posts search
const recentPosts = await api.searchPosts({
keywords: 'machine learning',
datePosted: 'past-week',
sortBy: 'date'
});
// Post search with minItems (v1.2.2+)
const manyPosts = await api.searchPosts({
keywords: 'AI',
minItems: 20, // Keep retrying until 20+ posts found
maxRetries: 4 // But don't try more than 4 times
});
// Author-specific posts
const authorPosts = await api.searchPosts({
author: 'satyanadella'
});
// Post details
const post = await api.getPost('post-id');
const content = post.getText();
const engagement = {
likes: post.getLikeCount(),
comments: post.getCommentCount(),
shares: post.getShareCount()
};
```
## 🆕 New Features (v1.1.0+)
### Smart Retry Logic with minItems (All Search Types)
The `minItems` parameter is now available for **all search types** - profiles, companies, and posts! This feature automatically retries searches across different pages/positions until the desired number of results is found.
#### Profile Search with minItems
```javascript
// Basic retry - stops at first non-empty result (default behavior)
const results = await api.searchProfiles({
keywords: 'software engineer'
});
// Will automatically retry until at least 1 item found
// Require minimum number of results (v1.2.0+)
const richResults = await api.searchProfiles({
keywords: 'product manager',
minItems: 10, // Keep retrying until 10+ profiles found
maxRetries: 5 // But don't try more than 5 times
});
// Disable retry for exact pagination control
const exactResults = await api.searchProfiles({
keywords: 'manager',
start: '20',
minItems: 0 // Disable retries completely
});
```
#### Company Search with minItems (v1.2.2+)
```javascript
// Get substantial company dataset
const companies = await api.searchCompanies({
keywords: 'fintech',
minItems: 15, // Keep retrying until 15+ companies found
industries: [INDUSTRIES.FINANCIAL_SERVICES],
maxRetries: 5
});
// Disable retries for company search
const exactCompanies = await api.searchCompanies({
keywords: 'startup',
page: '2',
minItems: 0 // Disable retries completely
});
```
#### Post Search with minItems (v1.2.2+)
```javascript
// Collect many posts for analysis
const posts = await api.searchPosts({
keywords: 'machine learning',
minItems: 25, // Keep retrying until 25+ posts found
datePosted: 'past-week',
maxRetries: 6
});
// Disable retries for post search
const exactPosts = await api.searchPosts({
keywords: 'AI',
page: '3',
minItems: 0 // Disable retries completely
});
```
### Debug Mode for Troubleshooting
```javascript
// Enable debug logging to see API response structures
api.setDebugMode(true);
const results = await api.searchProfiles({ keywords: 'test' });
// Will log detailed response structure information
// Disable debug mode
api.setDebugMode(false);
```
### Why These Features Matter for AI Coders:
- **Private Profile Handling**: LinkedIn has many private profiles that show in total counts but don't return data. The retry logic automatically finds pages with public profiles.
- **Minimum Items Control (v1.2.2+)**: Now available for **all search types**! Specify exactly how many results you need for your dataset. Perfect for data collection, analysis, or training where you need substantial sample sizes.
- **Universal Retry Logic**: Companies and posts can also have sparse results or pagination gaps. The same intelligent retry logic now works across profiles, companies, and posts.
- **Debug Mode**: When integrating or troubleshooting, see exactly what response structure the API returns.
- **Configurable Behavior**: Control retry logic based on your specific use case (data collection vs. pagination).
## Advanced Patterns
### 1. Pagination Handling
```javascript
// Profile search with pagination
let allProfiles = [];
let results = await api.searchProfiles({ keywords: 'ceo' });
do {
allProfiles.push(...results.items);
if (results.hasNextPage()) {
results = await results.getNextPage();
} else {
break;
}
} while (allProfiles.length < 100); // Limit results
```
### 2. Search Item to Full Data
```javascript
// Efficient pattern: search then load full data
const searchResults = await api.searchProfiles({ keywords: 'engineer' });
for (const item of searchResults.items) {
// Get full profile using username from search result
const fullProfile = await api.getProfile(item.username);
console.log(fullProfile.getFullName());
}
```
### 3. Bulk Operations with Rate Limiting
```javascript
async function processProfilesBatch(usernames, batchSize = 5) {
const results = [];
for (let i = 0; i < usernames.length; i += batchSize) {
const batch = usernames.slice(i, i + batchSize);
const batchPromises = batch.map(async (username) => {
try {
return await api.getProfile(username);
} catch (error) {
if (error instanceof RateLimitError) {
// Wait and retry
await new Promise(resolve => setTimeout(resolve, 60000));
return await api.getProfile(username);
}
throw error;
}
});
const batchResults = await Promise.all(batchPromises);
results.push(...batchResults);
// Rate limiting delay
await new Promise(resolve => setTimeout(resolve, 1000));
}
return results;
}
```
## Error Handling Patterns
### 1. Comprehensive Error Handling
```javascript
try {
const profile = await api.getProfile(username);
return profile;
} catch (error) {
if (error instanceof NotFoundError) {
console.log('Profile not found or private');
return null;
} else if (error instanceof RateLimitError) {
console.log('Rate limited, retry after:', error.retryAfter);
// Implement retry logic
throw error;
} else if (error instanceof LinkedInError) {
console.log('LinkedIn API error:', error.message);
throw error;
} else {
console.log('Unexpected error:', error.message);
throw error;
}
}
```
### 2. Graceful Degradation
```javascript
async function getProfileSafely(username) {
try {
const profile = await api.getProfile(username);
return {
success: true,
data: {
name: profile.getFullName(),
headline: profile.getHeadline(),
url: profile.getLinkedInUrl(),
location: profile.getLocation(),
currentPosition: profile.getCurrentPosition()
}
};
} catch (error) {
return {
success: false,
error: error.message,
errorType: error.constructor.name
};
}
}
```
## Helper Constants Reference
### Locations (Use for geo parameter)
```javascript
LOCATIONS.US.NEW_YORK // 105080838 (number)
LOCATIONS.US.SAN_FRANCISCO // 102277331 (number)
LOCATIONS.US.LOS_ANGELES // 102448103 (number)
LOCATIONS.US.CHICAGO // 103112676 (number)
LOCATIONS.US.BOSTON // 102380872 (number)
LOCATIONS.US.SEATTLE // 104116203 (number)
LOCATIONS.US.AUSTIN // 104472866 (number)
LOCATIONS.US.DENVER // 103736294 (number)
LOCATIONS.US.MIAMI // 105149290 (number)
```
### Industries (Use for company search)
```javascript
INDUSTRIES.TECHNOLOGY // 96
INDUSTRIES.FINANCIAL_SERVICES // 43
INDUSTRIES.HEALTHCARE // 14
INDUSTRIES.RETAIL // 27
INDUSTRIES.MANUFACTURING // 12
INDUSTRIES.EDUCATION // 69
INDUSTRIES.CONSTRUCTION // 48
INDUSTRIES.REAL_ESTATE // 44
INDUSTRIES.ENTERTAINMENT // 28
INDUSTRIES.CONSULTING // 9
```
### Company Sizes (Use for company search)
```javascript
COMPANY_SIZES.SELF_EMPLOYED // 'A'
COMPANY_SIZES.TINY // 'B' (1-10)
COMPANY_SIZES.SMALL // 'C' (11-50)
COMPANY_SIZES.MEDIUM // 'D' (51-200)
COMPANY_SIZES.LARGE // 'E' (201-500)
COMPANY_SIZES.XLARGE // 'F' (501-1000)
COMPANY_SIZES.ENTERPRISE // 'G' (1001-5000)
COMPANY_SIZES.MASSIVE // 'H' (5001-10000)
COMPANY_SIZES.MEGA // 'I' (10000+)
```
## Common Use Case Implementations
### 1. Recruiting Pipeline
```javascript
async function findCandidates(criteria) {
const { role, location, company, skills } = criteria;
// Search profiles
const results = await api.searchProfiles({
keywords: `${role} ${skills.join(' ')}`,
geo: [location],
company: company || undefined
});
// Get full profiles for top candidates
const candidates = [];
for (const item of results.items.slice(0, 20)) {
const profile = await api.getProfile(item.username);
candidates.push({
name: profile.getFullName(),
headline: profile.getHeadline(),
location: profile.getLocation().city,
experience: profile.getAllPositions(),
education: profile.getEducation(),
skills: profile.getSkills(),
url: profile.getLinkedInUrl()
});
}
return candidates;
}
```
### 2. Market Research
```javascript
async function analyzeIndustry(industry, location) {
// Find companies in industry
const companies = await api.searchCompanies({
keywords: industry,
industries: [INDUSTRIES[industry.toUpperCase()]],
location: location
});
// Analyze company data
const analysis = {
totalCompanies: companies.items.length,
companies: []
};
for (const item of companies.items.slice(0, 10)) {
const company = await api.getCompany(item.username);
analysis.companies.push({
name: company.getName(),
size: company.getEmployeeCount(),
followers: company.getFollowerCount(),
description: company.getDescription(),
specialties: company.getSpecialties()
});
}
return analysis;
}
```
### 3. Content Analysis
```javascript
async function analyzePostPerformance(keywords, timeframe = 'past-week') {
const posts = await api.searchPosts({
keywords: keywords,
datePosted: timeframe,
sortBy: 'date'
});
const metrics = {
totalPosts: posts.total,
avgEngagement: 0,
topPosts: []
};
let totalLikes = 0;
let totalComments = 0;
for (const item of posts.items) {
const post = await api.getPost(item.urn);
const likes = post.getLikeCount();
const comments = post.getCommentCount();
totalLikes += likes;
totalComments += comments;
metrics.topPosts.push({
text: post.getText().substring(0, 200),
likes: likes,
comments: comments,
author: post.getAuthor().name,
engagement: likes + comments
});
}
// Sort by engagement
metrics.topPosts.sort((a, b) => b.engagement - a.engagement);
metrics.avgEngagement = (totalLikes + totalComments) / posts.items.length;
return metrics;
}
```
## Performance Best Practices
### 1. Caching Strategy
```javascript
// Cache is enabled by default with 5-minute timeout
// Clear cache if you need fresh data
api.clearCache();
// For frequent requests, rely on built-in caching
const profile1 = await api.getProfile('user'); // API call
const profile2 = await api.getProfile('user'); // Cached result
```
### 2. Rate Limiting
```javascript
// Implement delays between requests
async function delayBetweenRequests(ms = 1000) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Use batch processing
async function processBatch(items, processor, batchSize = 5) {
const results = [];
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
const batchResults = await Promise.all(batch.map(processor));
results.push(...batchResults);
if (i + batchSize < items.length) {
await delayBetweenRequests();
}
}
return results;
}
```
### 3. Memory Management
```javascript
// For large datasets, process in chunks
async function processLargeDataset(searchParams, processor) {
let results = await api.searchProfiles(searchParams);
let processedCount = 0;
do {
// Process current page
for (const item of results.items) {
await processor(item);
processedCount++;
// Clear cache periodically to prevent memory issues
if (processedCount % 100 === 0) {
api.clearCache();
}
}
// Get next page if available
if (results.hasNextPage()) {
results = await results.getNextPage();
} else {
break;
}
} while (true);
}
```
## Debugging and Validation
### 1. Parameter Validation
```javascript
// Validate parameters before making requests
const validation = api.validateParameters('search_people', {
keywords: 'engineer',
geo: LOCATIONS.US.SAN_FRANCISCO
});
if (!validation.valid) {
console.log('Missing required params:', validation.missingRequired);
console.log('Extra params:', validation.extraParams);
}
```
### 2. Endpoint Information
```javascript
// Get all available endpoints
const endpoints = api.listEndpoints();
console.log('Available endpoints:', endpoints);
// Get specific endpoint info
const profileEndpoint = api.getEndpointInfo('get_profile_data');
console.log('Required params:', profileEndpoint.parameters.required);
```
## Key Decision Points for AI Coders
1. **Always use helper constants** (LOCATIONS, INDUSTRIES, COMPANY_SIZES) instead of raw values
2. **Always use entity helper methods** instead of accessing raw data directly
3. **Implement proper error handling** for all API calls with specific error types
4. **Use search-then-load pattern** for efficiency (search first, then load full data only when needed)
5. **Implement rate limiting delays** for bulk operations
6. **Clear cache periodically** for long-running processes
7. **Validate parameters** before making API calls when in doubt
8. **Use pagination helpers** instead of manual pagination logic
This guide provides comprehensive coverage of all package capabilities with practical, copy-pasteable examples optimized for AI code generation.