npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@osanoai/linkedin

v0.1.1

Published

Zero-dependency CLI to authenticate with LinkedIn and create posts on behalf of the authenticated member: text, article/URL shares, images, video, and @-mentions.

Readme

@osanoai/linkedin

A zero-dependency command-line tool for posting to LinkedIn as the authenticated member. It does two things and does them well:

  1. Auth — LinkedIn OAuth 2.0 (3-legged, browser-based) or direct access-token auth for headless use.
  2. Post — text posts, article/URL shares, image posts (up to 9 images), video posts, member/company @-mentions, and public/connections visibility.

Built on LinkedIn's documented Share on LinkedIn (UGC Posts + Assets) and OAuth 2.0 APIs.

Install

npm install -g @osanoai/linkedin
linkedin --help

Requires Node.js >= 18.17.

Prerequisites (one-time LinkedIn app setup)

  1. Create an app at https://www.linkedin.com/developers/apps.
  2. On the Products tab, add Share on LinkedIn (grants w_member_social) and Sign In with LinkedIn using OpenID Connect (grants openid profile, used to resolve your member URN).
  3. For browser login: on the Auth tab, add http://localhost:8914/callback as an authorized redirect URL (or another port — pass --port to match).

Authenticate

Option A — browser OAuth flow:

linkedin auth login --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET

Your browser opens LinkedIn's consent page; after you click Allow, the CLI captures the callback, exchanges the code for a ~60-day access token, resolves your urn:li:person:..., and stores everything in ~/.config/linkedin-cli/credentials.json (mode 0600). LINKEDIN_CLIENT_ID / LINKEDIN_CLIENT_SECRET env vars work too.

Option B — paste a token (headless/CI/agents):

# from https://www.linkedin.com/developers/tools/oauth/token-generator
linkedin auth token ACCESS_TOKEN
# or keep it entirely in the environment:
export LINKEDIN_ACCESS_TOKEN=...        # overrides stored credentials
export LINKEDIN_PERSON_URN=urn:li:person:...   # optional; skips profile lookup

Check state anytime:

linkedin auth status   # exit 0 = authenticated, 3 = not
linkedin whoami        # verifies the token against the live API
linkedin auth logout

Post

# Text
linkedin post "Hello LinkedIn!"

# Article / URL share
linkedin post "Worth a read:" \
  --article https://example.com/report \
  --article-title "2026 Privacy Report" \
  --article-description "Key findings on consent trends."

# Images (repeat --image, up to 9; --alt/--image-title apply to the preceding image)
linkedin post "Highlights from the summit" \
  --image day1.jpg --alt "Keynote stage" \
  --image day2.jpg --alt "Panel discussion"

# Video
linkedin post "Feature demo" --video demo.mp4 --video-title "Demo"

# Mentions — inline anywhere in the text
linkedin post 'Kudos to @[Jane Doe](urn:li:person:AbC_123) and @[Osano](urn:li:organization:17959845)!'

# Connections-only, machine-readable output
linkedin post "Inner circle" --visibility connections --json

# Preview the exact API payload without posting
linkedin post "test" --image pic.png --dry-run

On success the CLI prints the post URN and URL:

Posted to LinkedIn ✔
URN: urn:li:share:7123456789012345678
URL: https://www.linkedin.com/feed/update/urn:li:share:7123456789012345678/

Mention syntax

@[Display Name](urn) renders as a real, linked mention. Supported URNs:

  • Members: urn:li:person:{id} (find your own via linkedin whoami)
  • Companies/schools: urn:li:organization:{id} (urn:li:company:{id} is auto-normalized)

LinkedIn offers no public API to look up an arbitrary member's URN by name, so you must already know the URN of anyone you mention.

Reference

| Env var | Purpose | | --- | --- | | LINKEDIN_ACCESS_TOKEN | Access token; takes precedence over stored credentials | | LINKEDIN_PERSON_URN | Author URN; skips the profile lookup | | LINKEDIN_CLIENT_ID / LINKEDIN_CLIENT_SECRET | OAuth app credentials for auth login | | LINKEDIN_CLI_CONFIG_DIR | Credentials directory (default ~/.config/linkedin-cli) | | LINKEDIN_API_BASE / LINKEDIN_OAUTH_BASE | Endpoint overrides (used by the e2e tests to target a mock server) |

Exit codes: 0 success · 1 API/runtime error · 2 invalid usage · 3 not authenticated.

Rate limits (LinkedIn-enforced): 150 posts per member per day, 100,000 per app per day.

Development

pnpm install --frozen-lockfile
pnpm test   # full e2e suite: real CLI processes against a mock LinkedIn API

pnpm is the pinned package manager (packageManager in package.json); .npmrc enforces a 7-day minimum release age for dependencies. See AGENTS.md for repo conventions and the CI/CD release flow (merges to main auto-publish to npm with provenance).

The suite in test/e2e.test.js spawns the actual binary and exercises the complete OAuth flow (including CSRF rejection), token auth, every post type, mention annotation ranges, byte-exact media uploads, and all error paths against test/mock-linkedin.js, which faithfully implements the documented LinkedIn contracts.

License

MIT