linkedin-api-ts

An unofficial LinkedIn API client for Node.js. Fetch profiles, experiences, education, skills, and more — using your own session cookies.
Install
npm install linkedin-api-ts
Getting Your API Key
The library authenticates using your LinkedIn session cookies, encoded as a base64 string.
Step 1: Get your cookies
- Log in to linkedin.com in your browser (use an incognito window for a longer-lived session — cookies can last up to 1 year)
- Open DevTools (
F12 or Cmd+Shift+I)
- Go to Application → Cookies →
https://www.linkedin.com
- Copy the values of:
li_at — your session token
JSESSIONID — your CSRF token (remove surrounding quotes if present)
Step 2: Encode as API key
import { encodeApiKey } from 'linkedin-api-ts';
const apiKey = encodeApiKey({
li_at: 'your_li_at_value',
JSESSIONID: 'your_jsessionid_value',
});
console.log(apiKey);
Or encode manually:
echo -n '{"li_at":"your_li_at_value","JSESSIONID":"your_jsessionid_value"}' | base64
Usage
import { LinkedIn } from 'linkedin-api-ts';
const linkedin = new LinkedIn({ apiKey: 'BASE64_ENCODED_API_KEY' });
const isValid = await linkedin.auth.verify();
console.log('Session valid:', isValid);
const profile = await linkedin.profile.details('williamhgates');
console.log(profile.fullName);
console.log(profile.headline);
console.log(profile.experiences);
console.log(profile.education);
console.log(profile.skills);
console.log(profile.raw);
console.log(profile.toJSON());
People Search
const results = await linkedin.search.people('software engineer', {
start: 0,
});
console.log(results.total);
console.log(results.results.length);
for (const person of results.results) {
console.log(person.fullName);
console.log(person.headline);
console.log(person.location);
console.log(person.username);
console.log(person.profileUrl);
console.log(person.profilePicture);
}
const page2 = await linkedin.search.people('software engineer', { start: 10 });
console.log(results.raw);
console.log(results.toJSON());
Hot-swap API Key
Rotate session cookies without creating a new client:
linkedin.apiKey = 'NEW_BASE64_KEY';
Example Response
profile.toJSON() returns structured data like this:
{
"username": "williamhgates",
"firstName": "Bill",
"lastName": "Gates",
"fullName": "Bill Gates",
"headline": "Co-chair, Bill & Melinda Gates Foundation",
"location": "Seattle, Washington, United States",
"profilePicture": "https://media.licdn.com/dms/image/...",
"summary": "Co-chair of the Bill & Melinda Gates Foundation. Founder of Breakthrough Energy...",
"url": "https://www.linkedin.com/in/williamhgates",
"experiences": [
{
"title": "Co-chair",
"company": "Bill & Melinda Gates Foundation",
"location": "Seattle, Washington, United States",
"startDate": "2000-01",
"endDate": null,
"description": null,
"employmentType": "Full-time"
},
{
"title": "Founder",
"company": "Breakthrough Energy",
"location": null,
"startDate": "2015-01",
"endDate": null,
"description": null,
"employmentType": null
}
],
"education": [
{
"school": "Harvard University",
"degree": null,
"field": null,
"startDate": "1973",
"endDate": "1975"
}
],
"skills": [
{ "name": "Public Speaking", "endorsementCount": 99 },
{ "name": "Entrepreneurship", "endorsementCount": 99 },
{ "name": "Strategic Planning", "endorsementCount": 82 }
],
"certifications": [],
"languages": [{ "name": "English", "proficiency": "Native or bilingual" }]
}
Configuration
const linkedin = new LinkedIn({
apiKey: 'BASE64_ENCODED_API_KEY',
proxyUrl: 'http://proxy:8080',
timeout: 10000,
delay: 200,
maxRetries: 3,
logging: false,
errorHandler: customErrorHandler,
});
Custom Error Handler
import type { IErrorHandler } from 'linkedin-api-ts';
const errorHandler: IErrorHandler = {
handle(error: Error): void {
console.error('LinkedIn API error:', error.message);
},
};
Search Data
The results.toJSON() method returns an ISearchResult object:
{
results: IPersonResult[];
total: number;
start: number;
count: number;
}
Each IPersonResult:
{
fullName: string;
headline: string | null;
location: string | null;
profilePicture: string | null;
profileUrl: string;
username: string | null;
}
Profile Data
The profile.toJSON() method returns an IProfile object:
{
username: string;
firstName: string;
lastName: string;
fullName: string;
headline: string | null;
location: string | null;
profilePicture: string | null;
summary: string | null;
url: string;
experiences: IExperience[];
education: IEducation[];
skills: ISkill[];
certifications: ICertification[];
languages: ILanguage[];
}
Nested types
interface IExperience {
title: string;
company: string;
location: string | null;
startDate: string | null;
endDate: string | null;
description: string | null;
employmentType: string | null;
}
interface IEducation {
school: string;
degree: string | null;
field: string | null;
startDate: string | null;
endDate: string | null;
}
interface ISkill {
name: string;
endorsementCount: number;
}
interface ICertification {
name: string;
authority: string | null;
startDate: string | null;
endDate: string | null;
}
interface ILanguage {
name: string;
proficiency: string | null;
}
Error Handling
The library throws specific errors you can catch:
import { SessionExpiredError, RateLimitError, ProfileNotFoundError } from 'linkedin-api-ts';
try {
const profile = await linkedin.profile.details('username');
} catch (error) {
if (error instanceof SessionExpiredError) {
} else if (error instanceof RateLimitError) {
} else if (error instanceof ProfileNotFoundError) {
}
}
Usage Limits
LinkedIn enforces rate limits on API usage. The library includes built-in request delays and retry logic, but you should still be mindful of how many requests you make. Excessive usage may result in your account being temporarily or permanently restricted. See LinkedIn's Commercial Use Limit for more details.
Security
Your li_at and JSESSIONID cookies are equivalent to a logged-in LinkedIn session — treat them like passwords. Never commit them, never log them in plain text, and rotate them if you suspect they have leaked.
If you find a vulnerability in how this library handles credentials or request data, please report it privately via GitHub Security Advisories instead of opening a public issue.
Roadmap
License
MIT — This project is not affiliated with or endorsed by LinkedIn. Using your account's session cookies may risk account restriction. Use responsibly.