Skip to main content

LinkedIn automation library - post, fetch, and search via Voyager API

Project description

linkitin

PyPI Python License Tests

Python library for LinkedIn automation via the Voyager API. Fetch posts, search content, and publish — all through an async client.

macOS onlylogin_from_browser() requires macOS and Chrome. The login_with_cookies() path works cross-platform.

Install

pip install linkitin

Requires Python 3.10+.

Development

python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

Authentication

Chrome proxy mode (recommended — requires macOS and Chrome logged into LinkedIn):

async with LinkitinClient() as client:
    await client.login_from_browser()  # routes API requests through Chrome via AppleScript

Chrome 145+ uses App-Bound Encryption for cookies, making them inaccessible to external tools. login_from_browser() works around this by executing API requests inside Chrome's LinkedIn tab, which automatically includes all session cookies. Requires "Allow JavaScript from Apple Events" enabled in Chrome (View > Developer).

Manual cookie input (if you have raw li_at and JSESSIONID values):

async with LinkitinClient() as client:
    await client.login_with_cookies(li_at="AQED...", jsessionid="ajax:123...")

Cookies from manual input are saved to disk and reused on subsequent runs via login_from_saved().

Usage

import asyncio
from linkitin import LinkitinClient

async def main():
    async with LinkitinClient() as client:
        # Authenticate
        if not await client.login_from_saved():
            await client.login_from_browser()

        # Fetch your posts
        posts = await client.get_my_posts(limit=10)
        for p in posts:
            print(p.text[:80], f"({p.likes} likes)")

        # Search posts
        results = await client.search_posts("AI startups", limit=5)

        # Get home feed
        feed = await client.get_feed(limit=20)

        # Get trending posts
        trending = await client.get_trending_posts(topic="AI", period="past-week", limit=5)

        # Create a text post
        urn = await client.create_post("Hello LinkedIn!", visibility="PUBLIC")

        # Create a post with image
        with open("chart.png", "rb") as f:
            urn = await client.create_post_with_image(
                text="Check out these metrics!",
                image_data=f.read(),
                filename="chart.png",
            )

        # Schedule a post (automatically rounded to next 15-min slot)
        from datetime import datetime, timezone, timedelta
        urn = await client.create_scheduled_post(
            text="Scheduled post — hello future!",
            scheduled_at=datetime.now(timezone.utc) + timedelta(hours=2),
        )

        # Comment on a post (feed posts always have thread_urn)
        feed = await client.get_feed(limit=5)
        comment_urn = await client.comment_post(
            feed[0].urn, "Great post!",
            thread_urn=feed[0].thread_urn or "",
        )

        # Reply to a comment (threaded)
        reply_urn = await client.comment_post(
            feed[0].urn, "Thanks!",
            parent_comment_urn=comment_urn,
            thread_urn=feed[0].thread_urn or "",
        )

        # Repost a post from the feed (requires share_urn)
        repost_urn = await client.repost(feed[0].share_urn)

        # Repost with your thoughts
        repost_urn = await client.repost(feed[0].share_urn, text="Great insights!")

        # Comment on a trending post (only works for posts with real URNs)
        trending = await client.get_trending_posts(topic="AI", period="past-week")
        for post in trending:
            if "dom:post" in post.urn:
                continue  # synthetic URN — read-only
            await client.comment_post(
                post.urn, "Interesting!",
                thread_urn=post.thread_urn or "",
            )

asyncio.run(main())

Configuration

LinkitinClient accepts optional parameters to override defaults:

client = LinkitinClient(
    cookies_path="~/.myapp/linkedin_cookies.json",  # default: ~/.linkitin/cookies.json
    timezone="America/New_York",                     # default: detected from system
    timezone_offset=-5.0,                            # default: computed from system
    display_width=1440,                              # default: 1920
    display_height=900,                              # default: 1080
    user_agent="Mozilla/5.0 ...",                    # default: modern Chrome/macOS UA
)

Rate Limiting

All requests go through a token-bucket rate limiter: 10 requests per minute with 1-5 second random jitter between requests. On 429/403 responses, exponential backoff kicks in starting at 30 seconds.

API Reference

Method Description
login_from_browser() Authenticate via Chrome proxy (AppleScript, macOS only)
login_with_cookies(li_at, jsessionid) Authenticate with manual cookies
login_from_saved() Load previously saved cookies
get_my_posts(limit=20) Fetch your posts
search_posts(keywords, limit=20) Search posts by keywords
get_feed(limit=20) Fetch home feed
get_trending_posts(topic, period, limit, from_followed, scrolls) Fetch trending posts sorted by engagement. Some posts may have synthetic URNs (read-only).
create_post(text, visibility="PUBLIC") Create a text post
upload_image(image_data, filename) Upload an image, returns media URN
create_post_with_image(text, image_data, filename, visibility="PUBLIC") Create post with image
create_scheduled_post(text, scheduled_at, visibility="PUBLIC") Schedule a text post; scheduled_at rounded to next 15-min slot
create_scheduled_post_with_image(text, image_data, filename, scheduled_at, visibility="PUBLIC") Schedule a post with image; scheduled_at rounded to next 15-min slot
comment_post(post_urn, text, parent_comment_urn="", thread_urn="") Comment on a post (or reply to a comment). Requires a real URN.
repost(share_urn, text="") Repost (reshare) an existing post. Requires share_urn (feed/my_posts only).
delete_post(post_urn) Delete a post by URN
close() Close the HTTP session

Contributing

See CONTRIBUTING.md for guidelines. PRs welcome!

  • Open issues for bugs or feature requests
  • Keep PRs focused — one change per PR
  • Run python -m pytest tests/ before submitting

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

linkitin-0.1.3.tar.gz (62.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

linkitin-0.1.3-py3-none-any.whl (36.6 kB view details)

Uploaded Python 3

File details

Details for the file linkitin-0.1.3.tar.gz.

File metadata

  • Download URL: linkitin-0.1.3.tar.gz
  • Upload date:
  • Size: 62.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for linkitin-0.1.3.tar.gz
Algorithm Hash digest
SHA256 8d92cfb90336698827b731f855e7ad41bfe433a2c441d685eded2ae4c89f1707
MD5 b42461e5bb9faf9f3d7fee11d558205c
BLAKE2b-256 b01b5f6b9e2be58819919ae4edeff3ce17a6b2d0d2861880b0f380aae0901414

See more details on using hashes here.

Provenance

The following attestation bundles were made for linkitin-0.1.3.tar.gz:

Publisher: publish.yml on ShuhaoZQGG/linkitin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file linkitin-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: linkitin-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 36.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for linkitin-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 798dc81a8348c0aa3ba1219774d412b255274105408af473baf69c55be69211c
MD5 503fdd8459941e4fdffd16a0a647cce2
BLAKE2b-256 fd192483b9e94a2ec4f15041be976242535df8f86a8104c1e0e95211168dcbd4

See more details on using hashes here.

Provenance

The following attestation bundles were made for linkitin-0.1.3-py3-none-any.whl:

Publisher: publish.yml on ShuhaoZQGG/linkitin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page