{"id":15454,"library":"linkedin-private-api","title":"NodeJS Unofficial LinkedIn API","description":"This `linkedin-private-api` package offers an unofficial, TypeScript-written wrapper for interacting with the LinkedIn platform programmatically. It operates by simulating browser requests, allowing automation of tasks without requiring official OAuth tokens; instead, it authenticates using direct user credentials (username and password). The current stable version is 1.1.2, with recent minor updates (v1.1.1, for example, introduced job searching and invitation notes). Its release cadence appears infrequent, suggesting a more conservative development or maintenance-oriented approach. A key differentiator is its ability to bypass official API restrictions, enabling direct automation of tasks such as searching profiles and jobs, sending connection invitations, and managing messages. This functionality is well-suited for specialized automation not covered by the public LinkedIn API, though users must be aware of the inherent risks associated with using unofficial access methods, including potential account action by LinkedIn.","status":"active","version":"1.1.2","language":"javascript","source_language":"en","source_url":"https://github.com/eilonmore/linkedin-private-api","tags":["javascript","linkedin-nodejs-api","linkedin-api","linked-private-api","linked-unofficial-api","linkedin-web-api","typescript"],"install":[{"cmd":"npm install linkedin-private-api","lang":"bash","label":"npm"},{"cmd":"yarn add linkedin-private-api","lang":"bash","label":"yarn"},{"cmd":"pnpm add linkedin-private-api","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"The primary entry point for the API client. Prefer `import` for modern Node.js and TypeScript projects.","wrong":"const Client = require('linkedin-private-api')","symbol":"Client","correct":"import { Client } from 'linkedin-private-api'"},{"note":"Used for paginating results from methods that return multiple entities (e.g., search results, invitations).","wrong":"import Scroller from 'linkedin-private-api'","symbol":"Scroller","correct":"import { Scroller } from 'linkedin-private-api'"},{"note":"A type definition for individual job search result objects. Use `import type` for clarity and optimal bundling in modern TypeScript environments.","wrong":"import { JobSearchHit } from 'linkedin-private-api'","symbol":"JobSearchHit","correct":"import type { JobSearchHit } from 'linkedin-private-api'"}],"quickstart":{"code":"import { Client } from 'linkedin-private-api';\n\nconst username = process.env.USERNAME as string;\nconst password = process.env.PASSWORD as string;\n\n(async () => {\n  // Login\n  const client = new Client();\n  await client.login.userPass({ username, password });\n  \n  // Search for React development jobs in Israel\n  const jobsScroller = await client.search.searchJobs({\n    keywords: 'React',\n    filters: { location: 'Israel' },\n    limit: 20,\n    skip: 5,\n  });\n\n  const [someReactJobHit] = await jobsScroller.scrollNext();\n  const jobCompanyName = someReactJobHit.hitInfo.jobPosting.companyDetails.company.name;\n\n  // Fetch the job's company\n  const companiesScroller = await client.search.searchCompanies({ keywords: jobCompanyName });\n  const [{ company: jobCompany }] = await companiesScroller.scrollNext();\n\n  // Search for profiles and send an invitation\n  const peopleScroller = await client.search.searchPeople({\n    keywords: 'Bill Gates'\n  });\n  const [{ profile: billGates }] = await peopleScroller.scrollNext();\n  \n  await client.invitation.sendInvitation({\n    profileId: billGates.profileId,\n    trackingId: billGates.trackingId,\n  });\n  \n  // Search in my connections\n  const ownConnectionsScroller = await client.search.searchOwnConnections({ keywords: 'Bill Gates', limit: 1 });\n  const connections = await ownConnectionsScroller.scrollNext();\n\n  // Get conversation\n  const [billConversation] = await client.conversation.getConversations({\n    recipients: billGates.profileId\n  }).scrollNext();\n \n  const conversationMessages = await client.message.getMessages({\n    conversationId: billConversation.conversationId\n  }).scrollNext();\n \n  // Send a message\n  const sentMessage = await client.message.sendMessage({\n    profileId: billGates.profileId,\n    text: 'Hey Bill!',\n  });\n})();","lang":"typescript","description":"Demonstrates logging in, searching for jobs and people, sending connection invitations, and exchanging messages."},"warnings":[{"fix":"Proceed with extreme caution and be aware of the risks. Monitor library updates for compatibility fixes, and implement robust error handling.","message":"Use of this unofficial API violates LinkedIn's Terms of Service and may lead to account suspension or termination. LinkedIn frequently updates its website, which can cause this library to break without notice.","severity":"breaking","affected_versions":">=1.0.0"},{"fix":"Implement significant delays between requests and use sensible rate limiting strategies. Consider using proxies to distribute traffic if operating at scale, and handle CAPTCHA challenges gracefully if encountered.","message":"This library performs actions through simulated browser requests. Aggressive usage (high request rates) can trigger LinkedIn's rate limiting or bot detection mechanisms, leading to temporary blocks or CAPTCHAs.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Utilize secure environment variable management (e.g., Docker secrets, Kubernetes secrets, cloud secrets managers) and avoid hardcoding credentials. For production, consider a secure vault solution and ensure restricted access to any system using these credentials.","message":"Authentication relies on direct username/password submission, which is inherently less secure than OAuth tokens. Storing these credentials, even in environment variables, requires robust security practices to prevent leakage.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Double-check credentials. Try logging in manually via a browser to ensure the account is active and not locked. Verify `process.env.USERNAME` and `process.env.PASSWORD` are correctly set.","cause":"The provided username or password was incorrect, or LinkedIn may have flagged the login attempt due to unusual activity or location.","error":"Login failed: Invalid credentials"},{"fix":"Always check if scroller results or specific properties exist before accessing them (e.g., `if (someReactJobHit?.hitInfo?.jobPosting)`). Update the library to the latest version, or check the GitHub issues for known breaking changes if LinkedIn's API structure has been modified.","cause":"A scroller returned no results, or the internal structure of LinkedIn's API response for a specific entity changed, leading to incorrect parsing by the library.","error":"Cannot read properties of undefined (reading 'jobPosting') (or similar for other entity properties)"},{"fix":"Implement asynchronous delays (e.g., `await new Promise(resolve => setTimeout(resolve, delayMs))`) between API calls, increasing `delayMs` gradually if errors persist. Use a proxy rotation service for high-volume operations.","cause":"LinkedIn's rate limiting system detected excessive requests from your IP address or account within a short period.","error":"Too many requests (HTTP 429) / You have been temporarily blocked"}],"ecosystem":"npm"}