LinkedIn Post Scraper API
Our LinkedIn post scraper takes a public /posts/ URL and returns structured JSON: the full post text, engagement counts, hashtags, attached media, the author with their profile link, the post ID, and the published timestamp, all in one request.
Why LinkedIn Post data is login-walled
LinkedIn wraps the logged-out post page in the same authwall as the rest of the member surface, so a datacenter request usually gets a "Sign in to view" shell. On a clean residential egress the guest render does carry the post as structured data, and our endpoint reads that; use /posts/ URLs, since /feed/update/ links wall for guests.
Call the LinkedIn Post Scraper API in one request
curl "https://api.linkedinscraperapi.com/api/v1/linkedin/post?url=https://www.linkedin.com/posts/maryam-asim_i-studied-500-linkedin-posts-this-year-activity-7457771025557061633-pza0&api_key=$API_KEY" import requests
BASE = "https://api.linkedinscraperapi.com"
API_KEY = "YOUR_API_KEY"
# Pass a public /posts/ URL (use /posts/, not /feed/update/).
data = requests.get(
f"{BASE}/api/v1/linkedin/post",
params={
"url": "https://www.linkedin.com/posts/maryam-asim_i-studied-500-linkedin-posts-this-year-activity-7457771025557061633-pza0",
"api_key": API_KEY,
},
timeout=30,
).json()
print(data["postAuthor"]["authorName"], "-", data["postedAt"])
print("likes:", data["engagement"]["likes"], "comments:", data["engagement"]["comments"])
print(data["content"][:200]) Parameters
| Parameter | Required | Default | Notes |
|---|---|---|---|
url | required | - | A public /posts/{slug} post URL. Required. Use /posts/ links; /feed/update/ URLs wall for guests. |
add_html | optional | - | Pass true or 1 to include the post's raw HTML alongside the parsed content. |
api_key | required | - | Your API key, passed as a query parameter. Get one free at signup. |
The JSON the LinkedIn Post Scraper API returns
{
"content": "I studied 500+ LinkedIn posts this year. The viral ones all follow the same 14 hook patterns. The dead ones all make the same 14 mistakes. Here's what I found: Viral hooks name something specific. Dead hooks stay vague on purpose...",
"content_markdown": null,
"engagement": {
"likes": 517,
"comments": 97,
"shares": null,
"views": null
},
"hashtags": [],
"media": [
{
"mediaType": "image",
"mediaUrl": "https://media.licdn.com/dms/image/v2/D4D22AQHjxZGfkH6JwQ/feedshare-shrink_800/B4DZ39TOQZKkAc-/0/1778071169119?e=2147483647&v=beta&t=6aE81_-uEvV7Pj_4Q_wcWkH70JOttnoxvJRnqT4psCU",
"mediaDescription": "image"
}
],
"mentions": [],
"comments": [],
"postAuthor": {
"authorId": null,
"authorName": "Maryam Asim",
"authorProfileLink": "https://www.linkedin.com/in/maryam-asim",
"authorUsername": "maryam-asim"
},
"postId": "7457771025557061633",
"postLink": "https://www.linkedin.com/posts/maryam-asim_i-studied-500-linkedin-posts-this-year-activity-7457771025557061633-pza0",
"postedAt": "2026-05-06T12:39:31.157Z",
"socialPlatform": "linkedin"
} | Field | Type | Description |
|---|---|---|
content | string | The full post text, from the post's structured data. |
engagement | object | Engagement counts: { likes, comments, shares, views }. Each is an integer when exposed, otherwise null. |
engagement.likes | integer | Reaction count when the render exposes it, e.g. 517. |
engagement.comments | integer | Comment count when the render exposes it, e.g. 97. |
hashtags | array | Hashtags parsed from the post text, without the # prefix. Empty when the post has none. |
media | array | Attached media as { mediaType, mediaUrl, mediaDescription }, e.g. the post's image. |
mentions | array | Mentions parsed from the post. Empty when none are exposed. |
postAuthor | object | The author: { authorId, authorName, authorProfileLink, authorUsername }. |
postAuthor.authorName | string | The author's display name, e.g. "Maryam Asim". |
postAuthor.authorProfileLink | string | The author's /in/ profile URL when resolvable. |
postId | string | The post activity ID, e.g. 7457771025557061633. |
postLink | string | The canonical post URL. |
postedAt | string | The publish timestamp in ISO 8601, e.g. "2026-05-06T12:39:31.157Z", when exposed. |
socialPlatform | string | Always "linkedin", so the shape matches other social endpoints. |
Who pulls LinkedIn data, and for what
Content and engagement analytics
Creator and thought-leader tracking
Social listening
Swipe files and research
Campaign reporting
Media harvesting
Why teams build on our LinkedIn Post Scraper API
Pass a /posts/ URL and we parse the guest render into a consistent social-post shape: text, engagement, hashtags, media, and author, in the same format our other social endpoints use. Every request runs through residential proxies with anti-bot handling and retries at a 2.6s median, and a walled or removed post is reported honestly rather than returned as a bogus record.
Full post text
Engagement counts
Author and media
Consistent social shape
Residential-first routing
Honest wall reporting
LinkedIn Post Scraper API measured against the alternatives
| Our API | DIY (requests / headless) | Official LinkedIn API | |
|---|---|---|---|
| Input by URL | Yes, a /posts/ URL | Manual fetch and parse | No public post-by-URL endpoint |
| Post text and engagement | Parsed content plus counts | Parse the guest render yourself | Only your own or authorized content |
| Setup | API key only | Residential proxies, headless browser, parsers | Marketing Developer Platform approval |
| Author and media | Returned in one call | Extra selectors per field | Limited to authorized scopes |
| Anti-bot and proxies | Residential-first, built in | You build and maintain it | Not applicable |
| Consistent shape | Same schema as other socials | You normalize it yourself | Platform-specific payloads |
| Behavior when walled | Reports the authwall honestly | Silent partial or empty record | Returns only authorized fields |
Usage-based pricing, no seats
| Plan | Price | Best for |
|---|---|---|
| Free | 1,000 requests | Testing and small jobs |
| Pro | $0.60 / 1k | Production workloads |
| Pay-as-you-go | $0.90 / 1k | Spiky or one-off volume |
Median response 2.6s. You only pay for successful requests.
FAQ
A LinkedIn post scraper is a tool that reads a public post and returns it in a structured format. Our LinkedIn post scraper API takes a /posts/ URL and returns the post text, engagement counts (likes, comments, shares, views), hashtags, attached media, the author with a profile link, the post ID, and the published timestamp as JSON from a single request.
Send one GET request to our linkedin/post endpoint with the post url and your API key. We route through residential proxies, handle anti-bot checks, and parse the guest render's structured data, so you get clean JSON back without a LinkedIn login or a headless browser of your own.
Use the /posts/ URL. LinkedIn's /feed/update/ links wall for logged-out visitors, so they return an authwall rather than the post. The /posts/{slug} share URL is the one that renders public post data, and that is the input this endpoint expects.
The guest render exposes reaction and comment counts on most public posts, but share and view counts are frequently omitted. When a count is not present we return null for that field rather than guessing, so likes and comments come through as integers while shares and views may be null on a given post.
On a challenged egress, or for a removed post, LinkedIn serves an authwall or a generic "Top Content" landing with no post data. Our endpoint detects that and returns an error naming the wall and the markers it matched, so a block is distinguishable from a real post. We never emit a post assembled from a landing page.
No. You only need a linkedinscraperapi key, passed as the api_key query parameter. There is no LinkedIn login, no cookies, and no Marketing Developer Platform approval. We read the public logged-out post page. The free tier includes 1,000 requests per month.
Median end-to-end response is about 2.6 seconds, which includes residential proxy routing, anti-bot handling, retries, and parsing. One call returns the full post record: text, engagement, media, and author.