UNPKG

@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
# 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.