Get public LinkedIn posts as JSON

A company URL returns up to 10 public posts. One post URL returns the full text and top comments.

Scraping LinkedIn posts, in practice, means the text and the reaction count on something the public can already open. Two routes cover that. Neither logs in. Both are in beta. The key is your SocialScrape x-api-key. See authentication.

Company posts#

GET /v1/linkedin/company/posts returns the latest public posts and reposts on a company page, up to 10. You get the URL, id, date, full text, media, reactions and comment counts. url is required: linkedin.com/company/<slug>.

cursor is on the parameter list. The reference says the cursor is always null. LinkedIn shows signed-out visitors only this block. The posts tab and later pages need a login. Asking for a cursor will not extend the feed.

The recorded request is a company page URL.

curl
curl -G "https://api.socialscrape.io/v1/linkedin/company/posts" \
  -H "x-api-key: $SOCIALSCRAPE_API_KEY" \
  --data-urlencode "url=https://www.linkedin.com/company/microsoft"
Python
import os
import requests

params = {
    "url": "https://www.linkedin.com/company/microsoft",
}
res = requests.get(
    "https://api.socialscrape.io/v1/linkedin/company/posts",
    headers={"x-api-key": os.environ["SOCIALSCRAPE_API_KEY"]},
    params=params,
)
body = res.json()

if body["ok"]:
    print(body["data"])
else:
    print(body["error"]["code"], body["error"]["message"])
TypeScript
const url = new URL("https://api.socialscrape.io/v1/linkedin/company/posts");
url.search = new URLSearchParams({
  "url": "https://www.linkedin.com/company/microsoft"
}).toString();
const res = await fetch(url, {
  headers: { "x-api-key": process.env.SOCIALSCRAPE_API_KEY! },
});
const body = await res.json();

if (body.ok) {
  console.log(body.data);
} else {
  console.error(body.error.code, body.error.message);
}

data.object is list. data.has_more is false when the block is complete, and cursor is null. parent describes the company page the posts came from. If you also want the company description, industry, size and follower count, that is GET /v1/linkedin/company with the same URL. The posts call does not repeat the full company profile.

Each item is a post:

  • id, url, type, text, published_at, author.
  • stats.likes is reactions. stats.comments is the comment count. stats.shares and stats.views are null when the public block does not include them.
  • media holds images or video when the post has them.
  • extra.age_label is the relative time LinkedIn printed. extra.published_at_source says where the timestamp came from. extra.author_headline is the headline next to the name. extra.reposted_by is set on a repost. extra.urn is the activity URN. extra.captions_url and extra.video_bitrate appear on video posts when LinkedIn sends them.

A null like count means the count was not in the payload. It does not mean nobody reacted.

Sample. The recorded company response is shortened. Reaction counts in it are the sample.

Errors are invalid_params, unsupported_url and not_found. A personal /in/ URL is the wrong route.

One post#

GET /v1/linkedin/post reads a public post: full text, author, date, reactions, comment counts, media (video, images or a shared article) and the top public comments. url is required. The reference accepts linkedin.com/posts/..., /feed/update/urn:li:activity:..., and Pulse article URLs (/pulse/...).

The recorded request is a public post URL.

curl
curl -G "https://api.socialscrape.io/v1/linkedin/post" \
  -H "x-api-key: $SOCIALSCRAPE_API_KEY" \
  --data-urlencode "url=https://www.linkedin.com/posts/jeffweiner08_seeing-lots-of-content-about-dolly-parton-activity-7499148115615350784-j-4g"
Python
import os
import requests

params = {
    "url": "https://www.linkedin.com/posts/jeffweiner08_seeing-lots-of-content-about-dolly-parton-activity-7499148115615350784-j-4g",
}
res = requests.get(
    "https://api.socialscrape.io/v1/linkedin/post",
    headers={"x-api-key": os.environ["SOCIALSCRAPE_API_KEY"]},
    params=params,
)
body = res.json()

if body["ok"]:
    print(body["data"])
else:
    print(body["error"]["code"], body["error"]["message"])
TypeScript
const url = new URL("https://api.socialscrape.io/v1/linkedin/post");
url.search = new URLSearchParams({
  "url": "https://www.linkedin.com/posts/jeffweiner08_seeing-lots-of-content-about-dolly-parton-activity-7499148115615350784-j-4g"
}).toString();
const res = await fetch(url, {
  headers: { "x-api-key": process.env.SOCIALSCRAPE_API_KEY! },
});
const body = await res.json();

if (body.ok) {
  console.log(body.data);
} else {
  console.error(body.error.code, body.error.message);
}

The post object matches the list item, with a few extras. extra.top_comments is the top public comments, not every comment. extra.author_followers is the follower count shown beside the author. extra.headline is the article or link headline when there is one. stats.likes and stats.comments are the counts. stats.views is null in the recorded sample.

If you started from a company list, pass items[i].url into this call only when you need top_comments or the uncut body. The company list already includes full text for those up to 10 posts, so a second call is for the comment preview and any field the list row left null.

Cost#

Each successful company page, company-post block or single post is 1 credit. You cannot spend ten credits to get ten pages of a company feed, because the later pages are not available logged out. One credit covers the block you can actually have.

All of these are cacheable for 30 days. max_age_days makes a repeat free. Failures, including not_found, cost 0. Signup is 100 credits, once, no card. See pricing and credits.

Limits#

Up to 10 company posts, then stop. No historical export. No private group posts. No full comment thread. Top comments are a preview. Person feeds are not this list. Read extra.recent_posts on the public profile, then open URLs with the single-post route.

Reposts are included on the company route and marked with extra.reposted_by. If you only want original posts, drop rows where that field is set. Do not expect a separate parameter for it. There isn't one.

Rate limits are per team. Free credits: 30 requests a minute. 429 is retryable and free. See rate limits and errors.

The API is in early access. These routes are beta.

Next#

Company posts: LinkedIn company posts API, tutorial, reference. One post: LinkedIn post API, tutorial, reference. The company profile is the LinkedIn company API. The hub is the LinkedIn API.

Person profiles are Read a public LinkedIn profile.

Questions

Can I page a company feed?

No. LinkedIn shows signed-out visitors only the latest block, up to 10 posts. The posts tab and later pages need a login, so the cursor is always null.

Does this return a person's posts?

The company route needs a linkedin.com/company/<slug> URL. A person's recent public posts are extra.recent_posts on GET /v1/linkedin/profile. One post by URL, person or company, is GET /v1/linkedin/post.

What is the like count?

stats.likes is the reaction count on the post. stats.comments is the comment count. Views are null when LinkedIn does not show them to a signed-out visitor.

Are the top comments the whole thread?

No. extra.top_comments on the single-post endpoint is the top public comments only.

Build on social data early.

Developers and agent builders get the first keys.

Get early access