A Python-based automation tool that streamlines the creation and management of LinkedIn posts on organization profiles. The tool is split into two separate processes to handle different LinkedIn API permission requirements.
Multi-Organization Support: Manage multiple LinkedIn organization pages from a single installation. See Multi-Organization Setup Guide for details.
This project consists of two independent tools:
- Influent Poster - Creates LinkedIn posts with text and images
- Influent Commenter - Adds comments to posts (requires different LinkedIn app/permissions)
LinkedIn's API permissions are scope-based. Posting to an organization page requires different scopes than commenting on posts. By splitting the functionality, each tool can use the appropriate LinkedIn app with the correct permissions.
- Post content with images to LinkedIn organization pages
- Queue-based comment system for adding links after posting
- YAML-based configuration for posts
- Separate authentication for posting and commenting
- Multi-organization support - Manage multiple LinkedIn pages
- Dry-run mode for testing
- Rich CLI interface with progress indicators
- Structured logging with structlog
- Secure credential management per organization
- Clone the repository:
git clone https://github.com/yourusername/influent.git
cd influent- Install with uv (recommended):
uv venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
uv pip install -e .Or using the Makefile:
make installFor multi-organization setup, see Multi-Organization Setup Guide.
For single-organization setup:
Poster App scopes:
r_organization_socialw_organization_socialrw_organization_admin
Commenter App scope:
w_organization_social(same as poster for organization commenting)
# Set up organization
make setup-organization ORGANIZATION=your-organization
# Authenticate
make auth-all ORGANIZATION=your-organization
# Post content
make post ORGANIZATION=your-organization POST=sample-post.yaml
# Post and comment
make post-and-comment ORGANIZATION=your-organization POST=sample-post.yamlinfluent authThis will open your browser for LinkedIn OAuth authentication.
Create a YAML file in data/posts/:
post:
text: |
Exciting news! We're launching our new product.
Check it out and let us know what you think!
#ProductLaunch #Innovation #Tech
image_path: "product-launch.jpg"
comment: |
Learn more about our product here:
https://example.com/productPost it:
# Using just the filename (looks in organization's posts directory)
influent --organization your-organization post product-launch.yaml
# Or using full path
influent --organization your-organization post /path/to/product-launch.yamlAfter posting, if your YAML included a comment field, a queue entry is created automatically:
influent-commenter --organization your-organization process-queue# List available posts
influent --organization <name> post
# Post specific file
influent --organization <name> post data/<name>/posts/sample-post.yaml
# Validate post file
influent --organization <name> post data/<name>/posts/sample-post.yaml --validate
# Dry run (no API calls)
influent --organization <name> --dry-run post data/<name>/posts/sample-post.yaml
# Refresh access token
influent --organization <name> refresh# Process comment queue
influent-commenter --organization <name> process-queue
# Process limited number
influent-commenter --organization <name> process-queue --limit 5
# List pending comments
influent-commenter --organization <name> list-pending
# Verify authentication
influent-commenter --organization <name> verify-auth
# Dry run
influent-commenter --organization <name> --dry-run process-queueinfluent/
├── config/
│ ├── config.yaml # Global settings
│ └── organizations/
│ └── <organization-name>/
│ ├── config.yaml # Organization configuration
│ └── .env # Organization credentials (git-ignored)
├── data/
│ └── <organization-name>/
│ ├── posts/ # Post YAML files
│ ├── images/ # Post images
│ ├── comment_queue/ # Pending comments
│ └── processed/ # Successfully posted files
├── src/
│ ├── influent/ # Poster tool
│ ├── influent_commenter/ # Commenter tool
│ └── influent_common/ # Shared components
└── Makefile # User-friendly commands
post:
text: |
Your post text here.
Supports multiple lines and markdown formatting.
image_path: "image-filename.jpg" # Relative to data/images/
comment: |
Optional comment with link to add after posting.
https://your-link.comWhen a post is created with a comment, a queue file is automatically created:
post_urn: "urn:li:share:1234567890"
organization_urn: "urn:li:organization:12345"
comment_text: |
Your comment text with link
created_at: "2024-01-01T12:00:00"
post_url: "https://www.linkedin.com/feed/update/..."- Poster authentication fails: Ensure your LinkedIn app has the correct scopes for organization posting
- Commenter authentication fails: The commenter requires
w_member_socialscope
- The commenter tool requires a different LinkedIn app with member-level permissions
- Ensure the access token in
.env.commenterhas thew_member_socialscope
If you see "Post created but ID not available":
- The post was created successfully but LinkedIn didn't return the ID
- Comments cannot be added automatically in this case
- Check LinkedIn directly to verify the post
make testmake lint # Check code style
make format # Auto-format codemake docs-serve # Serve docs locally on random port (8000-9000)
make docs-build # Build static documentationThe documentation uses MkDocs with Material theme. When you run make docs-serve, it automatically selects a random port to avoid conflicts with other services.
src/influent/- Poster tool implementationsrc/influent_commenter/- Commenter tool implementation- Both tools share similar architecture but are independent
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests and linting
- Submit a pull request
All rights reserved. See LICENSE file for details.