linkedin-automation-cli
v2.0.2
Published
A CLI tool for LinkedIn automation using Playwright
Downloads
430
Maintainers
Readme
LinkedIn Automation CLI
A TypeScript CLI tool for LinkedIn automation using Playwright. Designed for sales representatives to manage LinkedIn messaging efficiently.
Features
- Authentication: Secure login with 2FA/TOTP support (Microsoft Authenticator)
- Message Management: List conversations, read threads, send replies
- Templates: Template-based message drafting with variable substitution
- Session Persistence: Encrypted session storage for seamless re-authentication
- Rate Limiting: Built-in protection against LinkedIn rate limits
- Audit Logging: Complete audit trail of all actions
Installation
# Clone the repository
git clone <repository-url>
cd linkedin-automation-cli
# Install dependencies
npm install
# Build the project
npm run build
# Link for global access (optional)
npm linkQuick Start
1. Login to LinkedIn
# Interactive login (will prompt for email, password, and 2FA if needed)
linkedin-cli auth login
# Or provide email inline
linkedin-cli auth login --email [email protected]2. List Conversations
# List recent conversations
linkedin-cli messages list
# Show only unread
linkedin-cli messages list --unread
# Limit to 10 results
linkedin-cli messages list --limit 103. Read a Conversation
linkedin-cli messages show --thread 12345678904. Send a Reply
# Send a message inline
linkedin-cli reply send --thread 1234567890 --message "Thanks for your message!"
# Send from file
linkedin-cli reply send --thread 1234567890 --file message.txt
# Dry run (simulate without sending)
linkedin-cli reply send --thread 1234567890 --message "Test" --dry-run5. Use Templates
# List available templates
linkedin-cli templates list
# Generate a message from template
linkedin-cli draft --thread 1234567890 --template welcome --var firstName=John --var company=Acme
# Preview without sending
linkedin-cli draft --thread 1234567890 --template welcome --var firstName=John --previewPinchTab Backend
PinchTab is the default backend for profile, company, and messaging operations. It provides:
- Token efficiency: Accessibility snapshots (~800 tokens vs 10,000+ DOM tokens)
- Stability: Accessibility tree is more stable than CSS selectors
- No AI required: Simple extractions parse accessibility tree directly
- Session persistence: Browser profiles maintain login state
Installation
Install PinchTab server (choose one):
# npm
npm install -g pinchtab
# Homebrew
brew install pinchtab
# Docker
docker pull pinchtab/pinchtabUsage
PinchTab is the default for profile, company, and messaging operations. Simply run:
linkedin-cli profile get https://linkedin.com/in/username
linkedin-cli company info https://linkedin.com/company/openai
linkedin-cli messages list
linkedin-cli reply send --thread 12345 --message "Hello!"
linkedin-cli connect send https://linkedin.com/in/usernameStart the PinchTab server first:
pinchtab serve --port 9867Fallback Options
If PinchTab doesn't work for a specific operation, use legacy backends:
# Use Playwright for profile extraction
linkedin-cli profile get https://linkedin.com/in/username --playwright
# Use AI for company extraction
linkedin-cli company info https://linkedin.com/company/openai --ai
# Use Playwright for messaging
linkedin-cli messages list --playwright
linkedin-cli reply send --thread 12345 --message "Hi" --playwright
linkedin-cli connect send https://linkedin.com/in/username --playwright
# Or set environment variables
export LINKEDIN_CLI_USE_PLAYWRIGHT=true # For profile/messaging
export LINKEDIN_CLI_USE_AI=true # For companyConfiguration
Add to ~/.linkedin-cli/config.json:
{
"pinchtab": {
"url": "http://localhost:9867",
"timeout": 30000,
"profile": "default"
}
}| Option | Default | Description |
|--------|---------|-------------|
| url | http://localhost:9867 | PinchTab server URL |
| timeout | 30000 | Request timeout (ms) |
| profile | default | Browser profile name |
Environment Variables
| Variable | Purpose |
|----------|---------|
| LINKEDIN_CLI_USE_PLAYWRIGHT | Force Playwright backend for profiles and messaging |
| LINKEDIN_CLI_USE_AI | Force AI backend for company extraction |
Messaging Commands
All messaging commands use PinchTab by default for token-efficient extraction.
List Conversations
linkedin-cli messages list
linkedin-cli messages list --unread
linkedin-cli messages list --limit 10View Thread
linkedin-cli messages show --thread <thread-id>Send Reply
linkedin-cli reply send --thread <thread-id> --message "Hello!"
linkedin-cli reply send --thread <thread-id> --file message.txt
linkedin-cli reply send --thread <thread-id> --message "Test" --dry-runSend Connection
linkedin-cli connect send https://linkedin.com/in/username/
linkedin-cli connect send https://linkedin.com/in/username/ --note "Hi, I'd like to connect"Configuration
Configuration is stored in ~/.linkedin-cli/config.json:
# View current config
linkedin-cli config --get
# Set values
linkedin-cli config --set headless=false
linkedin-cli config --set rateLimit=10000Available Options
| Option | Default | Description |
|--------|---------|-------------|
| headless | true | Run browser in headless mode |
| rateLimit | 5000 | Delay between actions (ms) |
| sessionTimeout | 86400000 | Session validity (24 hours) |
| dryRun | false | Default dry-run mode |
Templates
Templates use Handlebars-style variable substitution:
Hi {{firstName}},
Thanks for connecting! I noticed you're working at {{company}}.
Best regards,
{{senderName}}Creating Custom Templates
- Create a file in
~/.linkedin-cli/templates/custom/:
mkdir -p ~/.linkedin-cli/templates/custom
cat > ~/.linkedin-cli/templates/custom/intro.txt << 'EOF'
---
name: Introduction
description: Brief introduction template
category: welcome
---
Hi {{firstName}},
I'm {{senderName}} from {{company}}. I came across your profile and was impressed by your experience in {{industry}}.
I'd love to connect and learn more about your work.
Best regards,
{{senderName}}
EOF- Use the template:
linkedin-cli draft --thread 1234567890 --template intro --var firstName=John --var industry=TechSecurity
- Encrypted Storage: Sessions and credentials are encrypted using AES-256-GCM
- Machine-Bound: Encryption keys are derived from machine-specific data
- No Credential Storage: Passwords are never stored; only session cookies
- Audit Logging: All actions are logged to
~/.linkedin-cli/audit.log
Troubleshooting
Login Issues
# Check auth status
linkedin-cli auth status
# Re-login if needed
linkedin-cli auth logout
linkedin-cli auth loginRate Limiting
If you encounter rate limiting:
# Increase rate limit delay
linkedin-cli config --set rateLimit=10000
# Use non-headless mode to see what's happening
linkedin-cli messages list --headless falseSelector Failures
If LinkedIn UI changes cause failures:
- Check the audit log:
cat ~/.linkedin-cli/audit.log - Run with non-headless mode to see the current state
- The multi-layer selector system will attempt fallbacks automatically
Development
Setup
# Install dependencies
npm install
# Build
npm run build
# Watch mode
npm run watch
# Run locally
node dist/index.js --helpQuality Checks
# Type check
npm run typecheck
# Lint
npm run lint
npm run lint:fix # Auto-fix issues
# Format
npm run format:check
npm run format # Auto-format code
# Run tests
npm run test # Run tests
npm run test:watch # Watch mode
npm run test:coverage # With coverage reportPre-commit Hooks
Husky runs automatically before each commit:
- ESLint validation
- Prettier format check
If the hook fails, fix the issues and re-commit.
Testing
Tests are written with Vitest and located alongside source files:
src/
├── core/
│ ├── storage.ts
│ └── storage.test.ts
├── templates/
│ ├── engine.ts
│ └── engine.test.tsCoverage threshold: 80% minimum across all files.
Publishing
See NPM_PUBLISHING.md for detailed publishing instructions.
Quick Publish
# Run all checks
npm run test:coverage
npm run build
# Bump version (choose: patch, minor, major)
npm version patch
# Push (triggers auto-publish via GitHub Actions)
git push && git push --tagsManual Publish
npm login # One-time setup
npm publish --dry-run # Preview
npm publish --access publicLicense
MIT
Contributing
Contributions welcome! Please ensure:
- TypeScript compiles without errors
- Follow existing code style
- Add tests for new features
- Update documentation
Disclaimer: This tool is for legitimate sales and business development purposes. Users are responsible for complying with LinkedIn's Terms of Service and applicable laws. Use responsibly and respect rate limits to avoid account restrictions.
