LinkedIn Gateway API

Unofficial LinkedIn API Gateway - Access LinkedIn data programmatically through a Chrome extension and REST API. Open-core solution for self-hosting.

Python 3.11+ FastAPI PostgreSQL Docker Chrome Extension WebSockets Open Source

⚠️ Important Notice

This is an unofficial tool and is not affiliated with, endorsed by, or connected to LinkedIn Corporation. Use at your own risk and in accordance with LinkedIn's Terms of Service.

🎯 Overview

LinkedIn Gateway bridges the gap between LinkedIn's web interface and your applications by providing:

  • Chrome Extension: Captures LinkedIn session and proxies requests
  • REST API: Clean, documented endpoints for LinkedIn data
  • Self-Hosted: Full control over your data and infrastructure
  • Open Core: Free and open source for self-hosting

Dual Execution Architecture

The system supports two modes of operation:

  • Browser Proxy Mode (Default): Routes requests through the Chrome extension using your active LinkedIn session
  • Server-Side Execution: Direct API calls from the backend using stored session cookies (requires self-hosted deployment)

βœ… Key Features

Complete LinkedIn API Coverage

  • β€’ Feed operations (fetch posts with engagement data)
  • β€’ Connection management (send/accept requests)
  • β€’ Messaging (send direct messages)
  • β€’ Profile scraping (extract profile data)
  • β€’ Comment operations (post & reply)
  • β€’ Reactions scraping (fetch post likes with user details)
  • β€’ User comments history (fetch all comments made by a profile)

Dual Execution Modes

  • β€’ Server-side execution for automated workflows
  • β€’ Browser proxy mode for enhanced session reliability
  • β€’ Seamless switching between modes
  • β€’ Automatic fallback handling

Enterprise-Ready

  • β€’ API key authentication with rate limiting
  • β€’ PostgreSQL database for data persistence
  • β€’ WebSocket support for real-time operations
  • β€’ Comprehensive error handling and logging

Production Deployment

  • β€’ Docker Compose setup included
  • β€’ Automated database migrations
  • β€’ Health checks and monitoring
  • β€’ HTTPS support with OAuth integration

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Your App      β”‚         β”‚  LinkedIn        β”‚         β”‚   Chrome        β”‚
β”‚   (API Client)  │────────▢│  Gateway API     │◀────────│   Extension     β”‚
β”‚                 β”‚  REST   β”‚  (FastAPI)       β”‚  WSS    β”‚   (Proxy)       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                     β”‚                            β”‚
                                     β”‚                            β”‚
                                     β–Ό                            β–Ό
                            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                            β”‚   PostgreSQL     β”‚        β”‚   LinkedIn      β”‚
                            β”‚   Database       β”‚        β”‚   Internal API  β”‚
                            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        

Execution Modes

1. Server-Side Execution (server_call=true)

The backend directly calls LinkedIn's internal APIs using stored session cookies.

βœ… Pros:

  • β€’ Fully automated, no browser required
  • β€’ Faster response times
  • β€’ Suitable for batch operations

⚠️ Cons:

  • β€’ Requires valid LinkedIn session cookies
  • β€’ May need periodic session refresh

2. Browser Proxy Mode (server_call=false)

Requests are proxied through the Chrome extension, which uses the user's active LinkedIn session.

βœ… Pros:

  • β€’ Always uses fresh, valid session
  • β€’ More reliable for long-running operations
  • β€’ Automatic session management

⚠️ Cons:

  • β€’ Requires Chrome extension to be running
  • β€’ Slightly higher latency

πŸš€ Quick Start

Prerequisites

  • Docker & Docker Compose (required - must be installed before running the installer)
  • OR Python 3.11+ and PostgreSQL (for manual setup without Docker)
  • Google Chrome or Chromium-based browser
  • LinkedIn Account (required for functionality)

Option 1: Docker Deployment (Recommended)

# Clone the repository
git clone https://github.com/vcentea/linkedin-gateway.git
cd linkedin-gateway

# Run the installation script
# Windows
deployment\scripts\install-core.bat

# Linux/Mac
chmod +x deployment/scripts/install-core.sh
./deployment/scripts/install-core.sh

# Access the API
# API: http://localhost:7778
# API Docs: http://localhost:7778/docs
# Health Check: http://localhost:7778/health

πŸ“š Installing Docker

Option 2: Local Development

# 1. Set up virtual environment
python -m venv venv
source venv/bin/activate  # Linux/Mac
# or
venv\Scripts\activate  # Windows

# 2. Install dependencies
cd backend
pip install -r requirements/base.txt

# 3. Configure environment
cp .env.example .env
# Edit .env with your database credentials

# 4. Run database migrations
alembic upgrade head

# 5. Start the server
uvicorn main:app --reload --host 0.0.0.0 --port 8000

Chrome Extension Setup

cd chrome-extension

# Install dependencies
npm install

# Build for development
npm run build:dev

# Build for production
npm run build:prod

Load in Chrome:

  1. Go to chrome://extensions/
  2. Enable "Developer mode"
  3. Click "Load unpacked"
  4. Select chrome-extension/dist-dev/ (or dist-prod/)

πŸ” Authentication

LinkedIn Gateway uses API keys for authentication. Generate your API key through the web interface or OAuth flow.

API Key Authentication

All API endpoints require authentication using an API key. You can provide the key in two ways:

1. Header Authentication (Recommended)

Pass the API key in the X-API-Key header:

curl -X POST https://localhost:7778/api/v1/feed/posts \
  -H "X-API-Key: LKG_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"start_index": 0, "count": 10, "server_call": false}'

2. Body Authentication

Include the API key in the request body:

{
  "api_key": "LKG_your_api_key_here",
  "start_index": 0,
  "count": 10,
  "server_call": false
}

πŸ’‘ server_call Parameter

All endpoints support dual execution modes via the server_call parameter:

  • β€’ server_call: false (default) - Executes via browser extension proxy (requires extension installed and connected)
  • β€’ server_call: true - Executes directly from server using stored LinkedIn session (requires self-hosted deployment with valid session)

OAuth 2.0 Flow

LinkedIn Gateway supports LinkedIn OAuth for user authentication:

  1. User initiates login via Chrome extension
  2. Extension redirects to LinkedIn OAuth
  3. LinkedIn redirects back with authorization code
  4. Backend exchanges code for access token
  5. User session is created with JWT token
  6. API key is generated for programmatic access

πŸ”‘ API Key Management

  • β€’ Format: LKG_prefix_secret
  • β€’ Storage: Hashed in PostgreSQL database
  • β€’ Scope: Per-user, with rate limiting
  • β€’ Rotation: Users can regenerate keys anytime

πŸ“š API Reference

All endpoints support dual execution modes via the server_call parameter.

Base URL: http://localhost:7778 (or your deployed server URL)

Feed Operations

POST /api/v1/feed/posts

Fetch posts from your LinkedIn feed with full engagement data.

Headers:

X-API-Key: LKG_your_api_key_here
Content-Type: application/json

Request Body:

{
  "start_index": 0,
  "count": 10,
  "server_call": false
}

Parameters:

Parameter Type Description
start_index integer Starting index for posts (default: 0)
count integer Number of posts to fetch (1-50, default: 10)
server_call boolean Execution mode (false: proxy, true: server)

Response:

[
  {
    "id": 1,
    "postid": "urn:li:activity:7123456789",
    "ugcpostid": "urn:li:ugcPost:7123456789",
    "url": "https://linkedin.com/feed/update/urn:li:activity:7123456789",
    "postcontent": "Post content here...",
    "author_id": 42,
    "author_linkedin_id": "john-doe-123",
    "author_name": "John Doe",
    "author_headline": "Software Engineer at TechCorp",
    "author_connection_degree": "1st",
    "reactions": 42,
    "comments": 5,
    "reposts": 3,
    "engagement": 50,
    "timestamp": "2025-01-15T10:30:00Z"
  }
]

Connection Management

POST /api/v1/connections/simple

Send a simple connection request without a message.

Request Body:

{
  "profile_identifier": "john-doe-123",
  "server_call": false
}

Parameters:

  • β€’ profile_identifier (string) - LinkedIn profile ID (e.g., 'john-doe-123') or full profile URL
  • β€’ server_call (boolean) - Execution mode (false: proxy, true: server)

Response:

{
  "success": true
}

POST /api/v1/connections/with-message

Send a connection request with a personalized message.

Request Body:

{
  "profile_identifier": "john-doe-123",
  "message": "Hi John, I'd like to connect!",
  "server_call": false
}

Parameters:

  • β€’ profile_identifier (string) - LinkedIn profile ID or full profile URL
  • β€’ message (string) - Custom message to include with connection request
  • β€’ server_call (boolean) - Execution mode (false: proxy, true: server)

Response:

{
  "success": true
}

Messaging

POST /api/v1/messages/send

Send a direct message to a LinkedIn profile.

Request Body:

{
  "profile_identifier": "john-doe-123",
  "message_text": "Hello! I saw your profile...",
  "server_call": false
}

Parameters:

  • β€’ profile_identifier (string) - LinkedIn profile ID or full profile URL
  • β€’ message_text (string) - Message text to send
  • β€’ server_call (boolean) - Execution mode (false: proxy, true: server)

Response:

{
  "success": true
}

POST /api/v1/messages/my-id

Get your authenticated user's LinkedIn profile ID.

Request Body:

{
  "server_call": false
}

Response:

{
  "success": true,
  "profile_id": "john-doe-123"
}

Profile Operations

POST /api/v1/profiles/scrape

Extract complete profile data including identity, contact info, about section, and skills.

Request Body:

{
  "profile_id": "john-doe-123",
  "server_call": false
}

Parameters:

  • β€’ profile_id (string) - LinkedIn profile ID or full profile URL
  • β€’ server_call (boolean) - Execution mode (false: proxy, true: server)

POST /api/v1/profiles/experiences

Scrape work experience history from a LinkedIn profile.

Request Body:

{
  "profile_id": "john-doe-123",
  "server_call": false
}

POST /api/v1/profiles/identity

Get identity data (name, headline, location, connection degree, follower count).

Request Body:

{
  "profile_id": "john-doe-123",
  "server_call": false
}

POST /api/v1/posts/profile-posts

Fetch posts published by a specific LinkedIn profile.

Request Body:

{
  "profile_id": "john-doe-123",
  "count": 10,
  "server_call": false
}

Parameters:

  • β€’ profile_id (string) - LinkedIn profile ID or URL
  • β€’ count (integer) - Number of posts to fetch (default: 10)
  • β€’ server_call (boolean) - Execution mode

Comment Operations

POST /api/v1/posts/get-commenters

Fetch commenters and comments from a LinkedIn post with pagination support.

Request Body:

{
  "post_url": "https://linkedin.com/feed/update/urn:li:activity:7123456789",
  "count": -1,
  "num_replies": 0,
  "server_call": false
}

Parameters:

  • β€’ post_url (string) - LinkedIn post URL or activity URN
  • β€’ count (integer) - Number of comments to fetch (-1 for all, default: -1)
  • β€’ num_replies (integer) - Number of replies to fetch per comment (default: 0)
  • β€’ server_call (boolean) - Execution mode

POST /api/v1/posts/post-comment

Post a comment on a LinkedIn post.

Request Body:

{
  "post_url": "https://linkedin.com/feed/update/urn:li:activity:7123456789",
  "comment_text": "Great post!",
  "server_call": false
}

Parameters:

  • β€’ post_url (string) - Full LinkedIn post URL, feed URL, or post ID (e.g., "activity:7123456789")
  • β€’ comment_text (string) - Comment text to post
  • β€’ server_call (boolean) - Execution mode

Response:

{
  "success": true
}

POST /api/v1/posts/reply-to-comment

Reply to an existing comment on a LinkedIn post.

Request Body:

{
  "comment_urn": "urn:li:fsd_comment:(7123456789,urn:li:activity:7123456789)",
  "reply_text": "Thanks for sharing!",
  "server_call": false
}

Parameters:

  • β€’ comment_urn (string) - Comment URN (provided by get-commenters endpoint in commentUrn field)
  • β€’ reply_text (string) - Reply text to post
  • β€’ server_call (boolean) - Execution mode

Response:

{
  "success": true
}

Reactions

POST /api/v1/posts/get-reactions

Fetch all reactions (likes) for a LinkedIn post with detailed reactor information.

Headers:

X-API-Key: LKG_your_api_key_here
Content-Type: application/json

Request Body:

{
  "post_url": "https://linkedin.com/feed/update/urn:li:activity:7123456789",
  "count": -1,
  "server_call": false,
  "min_delay": 0.5,
  "max_delay": 1.5
}

Parameters:

Parameter Type Description
post_url string LinkedIn post URL or activity URN
count integer Number of reactions to fetch (-1 for all, default: 10)
server_call boolean Execution mode (false: proxy, true: server)
min_delay float Min delay between pagination requests (seconds, default: 0.5)
max_delay float Max delay between pagination requests (seconds, default: 1.5)

Response:

{
  "data": [
    {
      "userId": "ACoAAD7-6OkBzHtPyDUD0wH2GSITJntEoxFm8K0",
      "userName": "John Doe",
      "userTitle": "Software Engineer at TechCorp",
      "connectionLevel": "1st",
      "reactionType": "LIKE"
    },
    {
      "userId": "ACoAACXyz123...",
      "userName": "Jane Smith",
      "userTitle": "Product Manager",
      "connectionLevel": "2nd",
      "reactionType": "PRAISE"
    }
  ]
}

πŸ’‘ Reaction Types

LinkedIn supports multiple reaction types:

  • β€’ LIKE - Standard like reaction
  • β€’ PRAISE - Celebrate/hands clapping
  • β€’ APPRECIATION - Love/heart
  • β€’ EMPATHY - Care/hug
  • β€’ INTEREST - Curious/lightbulb
  • β€’ ENTERTAINMENT - Funny/laughing

User Comments

POST /api/v1/profile/comments

Fetch all comments made by a specific user profile with full context including posts and parent comments.

Headers:

X-API-Key: LKG_your_api_key_here
Content-Type: application/json

Request Body:

{
  "profile_id": "john-doe-123",
  "count": 20,
  "server_call": false,
  "min_delay": 0.5,
  "max_delay": 1.5
}

Parameters:

Parameter Type Description
profile_id string LinkedIn profile ID or full profile URL
count integer Number of comments to fetch (-1 for all, max: 200)
server_call boolean Execution mode (false: proxy, true: server)
min_delay float Min delay between pagination requests (seconds, default: 0.5)
max_delay float Max delay between pagination requests (seconds, default: 1.5)

Response:

{
  "data": [
    {
      "commentText": "Great insights! Thanks for sharing.",
      "commentId": "urn:li:comment:(7123456789,urn:li:activity:7123456780)",
      "postText": "Here's my latest article on AI...",
      "postUrl": "https://linkedin.com/feed/update/urn:li:activity:7123456780",
      "parentCommentText": null,
      "parentCommentId": null,
      "parentCommenterName": null,
      "parentCommenterHeadline": null,
      "parentCommenterProfileId": null,
      "isReply": false,
      "replyToUserCommentText": null,
      "replyToUserCommentId": null
    },
    {
      "commentText": "I agree with your point about automation.",
      "commentId": "urn:li:comment:(7123456790,urn:li:activity:7123456781)",
      "postText": "Discussion about the future of work...",
      "postUrl": "https://linkedin.com/feed/update/urn:li:activity:7123456781",
      "parentCommentText": "Automation is changing everything.",
      "parentCommentId": "urn:li:comment:(7123456788,urn:li:activity:7123456781)",
      "parentCommenterName": "Jane Smith",
      "parentCommenterHeadline": "Tech Lead at AI Corp",
      "parentCommenterProfileId": "ACoAACXyz123...",
      "isReply": true,
      "replyToUserCommentText": null,
      "replyToUserCommentId": null
    }
  ]
}

πŸ’‘ Comment Context

This endpoint provides rich context for each comment:

  • β€’ Root Comments: Direct comments on posts (isReply: false)
  • β€’ Reply Comments: Replies to other comments (isReply: true)
  • β€’ Post Context: Full post text and URL for each comment
  • β€’ Parent Details: When it's a reply, includes parent comment and commenter info
  • β€’ Hard Limit: Maximum 200 comments to prevent excessive API calls

πŸ“– Interactive Documentation

Once the server is running, visit the interactive API documentation:

🚒 Deployment

Production Deployment Options

1. Docker Compose (Recommended)

  • β€’ Complete setup in deployment/ folder
  • β€’ Includes PostgreSQL, backend, health checks
  • β€’ One-command deployment
  • β€’ See deployment/README.md

2. VPS/Self-Hosted

  • β€’ Ubuntu/Debian server
  • β€’ Nginx reverse proxy
  • β€’ Let's Encrypt SSL certificates
  • β€’ Systemd service management

3. Cloud Platforms

  • β€’ Heroku, Railway, Render
  • β€’ One-click deployment
  • β€’ Managed PostgreSQL
  • β€’ Auto-scaling

Environment Variables

Key environment variables (see backend/.env.example):

# Database
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=your_password
DB_NAME=LinkedinGateway

# API
API_HOST=0.0.0.0
API_PORT=8000

# JWT
JWT_SECRET_KEY=your_secret_key
JWT_ALGORITHM=HS256
JWT_EXPIRATION_MINUTES=10080

# LinkedIn OAuth
LINKEDIN_CLIENT_ID=your_client_id
LINKEDIN_CLIENT_SECRET=your_client_secret
LINKEDIN_REDIRECT_URI=https://your-domain.com/auth/user/callback

# CORS
CORS_ORIGINS=*

# Rate Limiting
DEFAULT_RATE_LIMIT=100
DEFAULT_RATE_WINDOW=3600

HTTPS Setup

⚠️ HTTPS Required

LinkedIn OAuth requires HTTPS. Available options:

  • β€’ Cloudflare Tunnel (Free, recommended for development)
  • β€’ Ngrok (Free tier available)
  • β€’ Nginx + Let's Encrypt (Self-hosted production)
  • β€’ Cloud Platform SSL (Managed)

See backend/HTTPS_TUNNELING_GUIDE.md for detailed setup instructions.

πŸ“Š Monitoring & Logging

Health Checks

Endpoint Description
GET /health API health status
GET /health/db Database connection health
GET /api/ws/status WebSocket connection status

Logging

Logs are written to:

  • Console: Structured JSON logs
  • File: backend/logs/ (if configured)
  • Docker: docker-compose logs -f backend

Log levels: DEBUG, INFO, WARNING, ERROR, CRITICAL

πŸ› οΈ Technology Stack

Backend

  • β€’ FastAPI (Python 3.11+)
  • β€’ PostgreSQL 15
  • β€’ SQLAlchemy 2.0 (async)
  • β€’ Alembic (migrations)
  • β€’ JWT + LinkedIn OAuth 2.0
  • β€’ HTTPX (async)

Chrome Extension

  • β€’ Manifest V3
  • β€’ Webpack 5
  • β€’ JavaScript (ES6+)
  • β€’ HTML5, CSS3
  • β€’ Chrome Extension APIs
  • β€’ WebSocket API

Infrastructure

  • β€’ Docker & Docker Compose
  • β€’ Nginx (reverse proxy)
  • β€’ Uvicorn with Gunicorn
  • β€’ Health check endpoints
  • β€’ Structured logging

⚠️ Important Notes

βš–οΈ LinkedIn Terms of Service

This tool interacts with LinkedIn's internal APIs. Users are responsible for:

  • β€’ Complying with LinkedIn's Terms of Service
  • β€’ Respecting rate limits and usage policies
  • β€’ Not engaging in spam or abusive behavior
  • β€’ Understanding potential account risks

Rate Limiting

  • Default: 100 requests per hour per API key
  • Configurable: Per user settings
  • Response: 429 status code when exceeded
  • Retry: Automatic retry with exponential backoff recommended

Session Management

  • LinkedIn sessions expire periodically
  • Server mode requires session refresh
  • Proxy mode uses browser's active session
  • Automatic session refresh on 401/403 errors

πŸ†˜ Support & Resources

Built with ❀️ using FastAPI, PostgreSQL, and modern web technologies.

Β© 2025 AInnovate.tech. Educational and development purposes only.

This is an unofficial tool not affiliated with LinkedIn Corporation.

↑