linkedints
linkedints
Unofficial TypeScript client for LinkedIn's internal (Voyager) API — a port of the Python
open_linkedin_apilibrary.
Programmatically search people, companies, and jobs, fetch profiles, send messages, manage connections, and interact with the feed — using a regular LinkedIn member account (no OAuth app or API key required).
Features
- Cookie-cached authentication — logs in once, reuses cookies on subsequent runs
- Profiles — full profile data, skills, experiences, contact info, network info
- Search — people, companies, and jobs with rich filters
- Messaging — list conversations, send messages, mark as seen
- Connections — send, accept, and remove connection requests
- Feed — fetch posts, comments, reactions, and react to posts
- Companies & schools — company pages, updates, follow/unfollow
- TypeScript-first — ships typed options and full async/await API
Installation
# bun
bun add linkedints
# npm
npm install linkedints
# pnpm
pnpm add linkedints
# yarn
yarn add linkedints
The package ships compiled ESM plus TypeScript declarations, and works on both Bun and Node.js (it uses only node: built-ins and axios).
Quick start
import { Linkedin } from "linkedints";
// Authenticate (uses cached cookies when available, otherwise logs in).
const api = await Linkedin.login("you@example.com", "password");
// Fetch a profile.
const profile = await api.getProfile("some-public-id");
// Search for people.
const people = await api.searchPeople({ keywords: "software engineer", limit: 10 });
// Search for jobs.
const jobs = await api.searchJobs({ keywords: "typescript", locationName: "Remote", limit: 20 });
Every method that hits the network is async and returns a Promise. Authentication cannot run in a constructor, so use the async factory Linkedin.login(...), or construct with { authenticate: false } and call await api.authenticate() yourself.
Using existing cookies
Skip the username/password login entirely by supplying a pre-built cookie jar (e.g. cookies exported from your browser):
import { Linkedin, CookieJar } from "linkedints";
const jar = new CookieJar();
jar.updateFromSetCookie([
'JSESSIONID="ajax:..."; Path=/',
"li_at=...; Path=/",
]);
const api = new Linkedin("", "", { authenticate: true, cookies: jar });
await api.authenticate();
Options
Linkedin.login(username, password, options) / new Linkedin(username, password, options) accept:
| Option | Default | Description |
|---|---|---|
authenticate |
true |
Whether authenticate() performs a login. |
refreshCookies |
false |
Ignore the cookie cache and log in fresh. |
debug |
false |
Verbose logging. |
proxy |
— | An axios AxiosProxyConfig, or false to disable. |
cookiesDir |
~/.linkedin_api/cookies |
Where cached cookie jars are stored. |
cookies |
— | A pre-built CookieJar to use instead of a username/password login. |
API overview
| Area | Methods |
|---|---|
| Profiles | getProfile, getProfileContactInfo, getProfileSkills, getProfileExperiences, getProfileConnections, getProfileNetworkInfo, getProfilePrivacySettings, getProfileMemberBadges, getCurrentProfileViews, getUserProfile |
| Search | search, searchPeople, searchCompanies, searchJobs |
| Jobs | getJob, getJobSkills |
| Messaging | getConversations, getConversation, getConversationDetails, sendMessage, markConversationAsSeen |
| Connections | addConnection, removeConnection, getInvitations, replyInvitation |
| Feed & posts | getFeedPosts, getProfilePosts, getProfileUpdates, getPostComments, getPostReactions, reactToPost |
| Companies & schools | getCompany, getCompanyUpdates, followCompany, unfollowEntity, getSchool |
All methods return plain JSON as delivered by the Voyager API.
Error handling
import { ChallengeException, UnauthorizedException, LinkedinSessionExpired } from "linkedints";
ChallengeException— LinkedIn asked for a security challenge (e.g. CAPTCHA or 2FA); log in through a browser first.UnauthorizedException— credentials were rejected.LinkedinSessionExpired— cached cookies are stale; retry withrefreshCookies: true.
Notes on the port
- Method names are camelCase (
getProfile,searchPeople) rather than the Python snake_case. - Cookies are cached as JSON (
<username>.jr) instead of Python pickles, so caches are not interchangeable between the two libraries. - HTML metadata parsing uses a small regex extractor instead of BeautifulSoup.
Disclaimer
This library uses LinkedIn's private API and is not endorsed or supported by LinkedIn. Using it may violate LinkedIn's Terms of Service and can get your account restricted — use at your own risk, ideally with a throwaway account.