# LinkedIn Profile Posts Scraper & LinkedIn Company Posts Scraper (`steadyfetch/linkedin-posts-scraper`) Actor

LinkedIn feed of any profile or company URL as rows — post text, a real publish timestamp to the second, likes, comments, shares, the reaction breakdown, images, video and article links, and the author. No login, no cookies. A page with nothing public is never charged.

- **URL**: https://apify.com/steadyfetch/linkedin-posts-scraper.md
- **Developed by:** [Steadyfetch Team](https://apify.com/steadyfetch) (community)
- **Categories:** Lead generation, Social media, Automation
- **Features:** Limited permissions, Multi-tenant, Server interface
- **Stats:** 37 total users, 21 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 posts

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## LinkedIn Profile Posts Scraper & LinkedIn Company Posts Scraper

Paste a LinkedIn company page or a person's profile and get that page's posts as rows: what was written, when it was really published, how many likes, comments and shares it has, the reaction breakdown, the images, video, document and article links attached to it, and the author. No login, no cookies, no proxy to configure. **Your limit is exact and it is per page — set 50 and you get up to 50 from each link, never more**, and a page holding fewer says so on a row that costs nothing. A post we could not deliver is never charged, and nothing is charged for starting a run. Click Start with nothing set and you get a built-in sample: 3 posts from one public company page, served from a frozen copy rather than fetched from LinkedIn, and nothing is charged for it.

**Using an AI agent?** Pin this actor in Apify's MCP server with one link: `https://mcp.apify.com?tools=steadyfetch/linkedin-posts-scraper`

- **Actor id:** `steadyfetch/linkedin-posts-scraper`
- **Input:** `{ "startUrls": ["https://www.linkedin.com/company/microsoft/", "https://www.linkedin.com/in/<public-identifier>/"] }` — the one field you have to set. A company page and a person's profile can sit in the same list, each classified by its own path. Add `"postsPerTarget": 50` for the per-page limit and `"maxItems": 1000` for the whole run.
- **Cap the bill:** set `maxTotalChargeUsd` on the run (a run option, not Actor input), e.g. `1.00` — the run stops when it reaches it.
- **Price:** from **$1.20 per 1,000 posts** on Gold and above, $1.80 per 1,000 at the entry tier — one charged unit is one post delivered. A page your run reads fresh that has nothing new for you pays one flat $0.006 check instead. No start fee, no fee for a page with no public posts, and no second charge for the media, the article preview, the reaction breakdown or the author: they are columns on the one row you already paid for. Full table below.
- **How often it changes:** a company page posts daily to weekly and a person weekly to monthly, and like and comment counts keep moving for about 72 hours before they settle — so a daily run on a company page and a weekly one on a person is the shape that fits. A re-run skips the posts your account already had, so it pays the post fee only for what is new, plus one $0.006 check for each page it reads fresh that has nothing new.

*Unofficial. Not affiliated with, endorsed by, or sponsored by LinkedIn or Microsoft Corporation, nor with any company or person whose public posts appear in the built-in sample.*

### The publish time is the real one

Read this first, because it is the one thing that separates these rows from most of the field. Every row carries `postedAt` — the moment LinkedIn itself stamped on the post, to the millisecond — and not a reading of a "2 weeks ago" label. You can check it yourself: the timestamp is the same epoch LinkedIn encodes inside the post's own activity id. `postedAgo` carries the label too, as a second column, never as the date.

### What you get

One row per post, at one price.

| Column | What it holds |
|---|---|
| `postId` · `postUrl` · `shareUrl` · `shareUrn` | the post's own ids and its permalink |
| `text` | what was written, in full |
| `postedAt` · `postedAtTimestamp` · `postedAgo` | the real publish moment, and LinkedIn's own label beside it |
| `authorType` · `authorName` · `authorHandle` · `authorUrl` · `authorId` | who posted it, and whether that is a person or a company |
| `authorHeadline` · `authorFollowers` · `authorAvatarUrl` | the headline on a person, the follower count on a company |
| `likes` · `comments` · `shares` · `reactions[]` | the engagement, with the per-type reaction breakdown |
| `countsHidden[]` | which counts LinkedIn is hiding on this page, so a hidden total never reads as a zero |
| `imageUrls[]` · `videoUrl` · `videoThumbnailUrl` · `documentUrl` | the media attached to the post |
| `articleTitle` · `articleLink` · `articleDescription` | the link preview, when the post shares one |
| `isRepost` · `repostOfPostId` · `repostOfPostUrl` · `repostOfAuthorName` · `repostOfPostedAt` | a repost, with the original underneath it |
| `newsletterTitle` · `newsletterUrl` | when the post is a newsletter issue |
| `targetUrl` | the page you asked for |
| `charged` · `status` · `statusReason` | on every row, so the invoice reconciles from the dataset |

### Hidden counts are never zeros

LinkedIn lets a page hide its reaction, comment, repost or view counts. When it does, the number in this dataset is `null` and `countsHidden` names which one is hidden — never `0`. A zero that means "we could not see it" is the same false precision as a date reconstructed from a label, and this actor does not ship either.

### How often the data changes

- A company page posts daily to weekly; a person weekly to monthly. A daily run on a company page and a weekly one on a person is usually the right shape.
- Like and comment counts keep moving for about 72 hours after a post goes up, then settle.
- **Image, video, document and avatar links are signed by LinkedIn and expire within days.** Re-run for fresh links; do not store them and expect them to keep working.
- Re-runs skip the posts your account already had, so a repeat run pays the post fee only for what is new (a page it reads fresh with nothing new pays one check — see Price). That memory lives in the key-value store `linkedin-posts-account` in your own Apify account, and posts older than 90 days in it count as new again.
- A page that had nothing new for your account is left alone by your runs for up to 24 hours under the same "Posted after", "Posted before" and settings: the run gives it one uncharged `skipped.all_repeat` row saying when it was checked and when a run reads it again, and nothing is charged for it. How long depends on "Posted after", so that a post published after the check is still inside your dates when the next read comes: with a span shorter than two days, half the span; with `today`, until half of what is left of the UTC day has passed; with `yesterday`, 12 to 24 hours; and with either of those two, every page is read again by your first run after midnight UTC. A page that gave you a new post is always read again on your next run. This holds with "Include posts you already have" on or off, and each setting keeps its own hold: with it on, posts you already have come back marked as repeats and are not charged, and a page that gave a run with it on only those counts as nothing new, so your next runs with it on leave it alone and its row says so. Pointing "Skip posts in this dataset" at a dataset reads every page once, then holds each quiet page the same way for your runs pointed at that same dataset; a different dataset reads every page again. So an hourly schedule reads each quiet page about once a day (a few times a day with `today`), and a daily schedule is the shape that fits. Turning on "Include posts you already have" reads a page that a run with it off left alone, and changing the dates reads every page now.
- The memory is a key-value store in your own Apify account, so a run started with a scoped API token in restricted-access mode needs key-value store Read, Write and Create permission, or Actor runs set to Full access (Write is what lets the run remember what it delivered; without it every run pays again); without it the run says so on its status line and cannot skip what you already have.

### Price

One charged unit is one post delivered. The store card shows this as **from $1.20/1,000 posts** — the cheapest tier, per 1,000 posts.

| Apify plan | Per post | 1,000 posts |
|---|---|---|
| Free plan | $0.0018 | $1.80 |
| Bronze | $0.0016 | $1.60 |
| Silver | $0.0014 | $1.40 |
| Gold and above | $0.0012 | $1.20 |

**The check: one flat $0.006, the same on every plan.** Charged once per profile or company page a run reads fresh from LinkedIn that has nothing new for you: every post it read is already in your account or outside your date window. A scheduled check that finds nothing new pays this one small fee per page read, whether the pages share one run or each have their own. A page answered from your account's memory without a fresh read (a page checked in the last 24 hours, see above), a page that delivers a new post (it pays the post fee instead, never this), a page LinkedIn does not show, a page with no public posts, a page the run stopped before finishing, and the built-in sample run are never charged it. The row that closes that page says it paid the check and carries `checkCharged: true`, and the run's summary row counts them.

No start fee. No fee for a page with no public posts. No second charge for the media, the article preview, the reaction breakdown or the author — they are columns on the one row you already paid for, and a repost is one post at the same price with the original underneath it.

`maxTotalChargeUsd` is a run option, not an input field, and it is a hard ceiling: the run stops collecting when it reaches it, writes out everything already in hand, and books the rest as rows that name the cap and cost nothing.

**On the Apify free plan there is a daily allowance.** One account reads at most 25 pages of posts in any 24 hours (a page is up to 50 posts from one link, so that covers a run of 25 links at the default 50 posts each), and all accounts on the Apify free plan share a daily allowance on this actor that resets at midnight UTC. Past either, the run stops cleanly: the posts it already delivered stay delivered, nothing more is read or charged, and each link it did not reach gets an uncharged `skipped.free_plan_allowance` row naming the reset time in UTC. Paid Apify plans carry no daily allowance.

### Honest rows

Nothing below charges a post, and every one of them arrives as a row you can read rather than as a missing line. The one fee a row here can carry is the page's check (see Price): a `no_data`, `skipped_date_window` or `skipped.all_repeat` row for a page this run read fresh with nothing new says it paid one $0.006 check and carries `checkCharged: true`. The row's `status` is the first column; `statusReason` is the sentence.

| `status` | What the row says |
|---|---|
| `profile_not_found` | LinkedIn does not list a public page at this URL, or it cannot be read without a login — nothing was charged for it. |
| `page_not_found` | The same answer on a company or showcase page: LinkedIn does not list one publicly at this URL. |
| `no_data` | This page exists and LinkedIn shows no public posts on it — nothing was charged. |
| `skipped_date_window` | This page has public posts, but none of the ones LinkedIn lists fall inside your dates — widen "Posted after" or "Posted before" to collect them. Nothing was charged for the posts it did not deliver, and a run with the same dates finds the same. When your dates lie more than "Max pages per profile" pages back (5 unless you set it; a page is one screen of that profile's posts, newest first), the run reads no further for that link, this row says so, and nothing is charged for that link — not even the check. |
| `skipped.all_repeat` | The page reached posts your account already had. LinkedIn lists posts newest first, so the rest are older than those, and the run read no further page for this link. Nothing was charged for the posts it did not deliver; the row says how to collect older ones. The same status marks a page that had nothing new for your account when it was checked in the last 24 hours under the same dates and the same "Include posts you already have" setting, so it was not read again: that row says when it was checked and when a run reads it again. |
| `skipped.page_cap` | The walk reached the 200 pages this actor reads for one link and LinkedIn was still serving — that bound is this actor's own, not a verdict about the page, so one link can never spend a whole run. The row says what to change. Nothing was charged for the posts it did not deliver. |
| `input_error` | The link is not one this actor can read. A link to a single post, an old `/pub/` profile link, a Sales Navigator link, or a short link that could not be followed each says so and names what to paste instead, and every such row lists the link shapes that work. The run's record keeps the field the link arrived in and the reason, never what you typed. |
| `try_again` | LinkedIn did not answer for this page on this run. Please re-run — nothing was charged. If posts had already been delivered before it stopped answering, the row opens with how many and what they cost, and the re-run is for the rest. |
| `limit_reached` | This run reached its limit (the row says how to continue in a new run), or this actor has paused collection for now; nothing was charged. |
| `skipped_max_items` · `skipped_budget` · `skipped_deadline` | One of your own limits or the run clock stopped the run first, and the row names which. |
| `input_note` with `checkCharged: true` | With "Include posts you already have" on, a page whose repeats filled your whole limit was read fresh and had nothing new: this one row says it paid its $0.006 check. Other `input_note` rows only say how the run read your input and cost nothing. |
| `skipped.free_plan_allowance` | On the Apify free plan only: the run reached the plan's daily allowance on this actor (see Price) before this link. The row says when it resets, in UTC; paid Apify plans carry no daily allowance. |

Posts your account already had are skipped rather than delivered twice, and are never charged either. Because LinkedIn lists posts newest first, reaching them means the rest of that page's feed is older than what you already have, so the run reads no further page for that link — a re-run pays the post fee only for what is new and never for pages of posts you hold, and a page it read fresh with nothing new pays its one check. A run pointed at a dataset with "Skip posts in this dataset", the way to pick up where a stopped run left off, still reads past them to the older posts that run never reached. To collect older posts otherwise, turn on "Include posts you already have" (they come back marked as repeats, not charged, and a page that gives a run with it on nothing but repeats is not read again by your runs with it on for up to 24 hours) or set "Posted before". All of this holds unless the token that started the run cannot open key-value stores (see the scoped-token note above), and then the run says so on its status line, on a note row and on every row it charged.

### The links it reads

A person's profile (`/in/<name>/`), a company or showcase page (`/company/<name>/`, `/showcase/<name>/`) and a school page (`/school/<name>/`). A mobile link to one of those, and a `lnkd.in` short link that leads to one, are followed to that page; tracking parameters and a country subdomain make no difference.

### A link to one post is not this actor's door

This actor reads a PROFILE or a COMPANY page and returns that page's posts. A link to a single post — `/feed/update/…` or `/posts/…-activity-…` — comes back as an uncharged row telling you to paste the author's page instead.

### Use it as an API endpoint (Standby)

You can also call this actor like an API: send up to five profile or company page links and get their latest posts back in the same response, with no run to start and no dataset to read. The address is `https://steadyfetch--linkedin-posts-scraper.apify.actor`, and the actor's **Endpoints** tab lets you try it from the browser.

```bash
curl -H "Authorization: Bearer <YOUR_APIFY_TOKEN>" \
  "https://steadyfetch--linkedin-posts-scraper.apify.actor/?startUrls=https://www.linkedin.com/company/microsoft/&postsPerTarget=20"
```

| Setting | What it does |
|---|---|
| `startUrls` | A profile or company page link. Repeat it for more links: up to 5 per request (1 on the Apify free plan). `profileUrls` and `companyUrls` work as they do on a run. |
| `postsPerTarget` | How many of the latest posts to return from each link. 50 if you leave it out; at most 100 per link per request (25 on the Apify free plan). |
| `maxItems`, `postedAfter`, `postedBefore`, `maxPagesPerProfile`, `includeReposts` | The same settings as on a run, read the same way. |

A POST with the same fields as a JSON body works too. The answer is JSON: `rows` (the same rows a run writes to its dataset, the run summary last), `delivered`, `charged`, and `notes` for anything that was not returned, in plain words. Each request is charged exactly as a run with the same input: per post returned, and the per-page check where a run would charge it. If the charge for a request cannot be completed, its posts are not sent and nothing is charged.

Good to know: the endpoint has no account memory, so it does not skip posts you already have — every request returns the posts it reads. For long lists, to skip posts you already collected, or to read "Skip posts in this dataset", run the actor as usual.

### Other scrapers you might want

- Public job postings with their full descriptions: [LinkedIn jobs](https://apify.com/steadyfetch/linkedin-jobs-scraper)
- The spoken words inside a LinkedIn video ad: [LinkedIn ad transcripts](https://apify.com/steadyfetch/linkedin-ads-transcript-scraper)
- Career pages on a company's own domain: [Career sites by domain](https://apify.com/steadyfetch/company-jobs-by-domain)

### Limits and good manners

Only public pages are returned — a page behind a login is an uncharged row, not a workaround. This actor may stop working if LinkedIn changes how the data is served; if it does, items that fail are never charged.

### Support

Something off, or a column you need that is not here? Open an issue on the Issues tab — we usually reply within a couple of hours.

If it earned its keep, a rating helps other buyers find it, and saving the actor keeps it one click away.

# Changelog

This Actor's version history is a separate document: https://apify.com/steadyfetch/linkedin-posts-scraper/changelog.md

# Actor input Schema

## `startUrls` (type: `array`):

LinkedIn profile, company and school page links in one list — https://www.linkedin.com/in/<public-identifier>/, https://www.linkedin.com/company/<name>/, /showcase/<name>/ or /school/<name>/; a mobile or lnkd.in short link to one works too. A link to a single POST comes back as an uncharged row telling you to paste the author's page instead. Also answers to `urls` and `links`. Leave it empty and click Start for a small built-in sample — it collects nothing and charges nothing.

## `profileUrls` (type: `array`):

People's LinkedIn profiles, one per line — a https://www.linkedin.com/in/<public-identifier>/ link (a mobile or lnkd.in short link to a profile works too) or the bare public identifier. An old /pub/ link or a Sales Navigator link has no public address in it and comes back as an uncharged row saying what to paste; so does a profile that is not public. Use this field when your list is people only; otherwise use "LinkedIn page URLs".

## `companyUrls` (type: `array`):

LinkedIn company, showcase and school pages, one per line — a full https://www.linkedin.com/company/<name>/, /showcase/<name>/ or /school/<name>/ link or the bare universal name on its own. A page with no public posts comes back as an uncharged row. Use this field when your list is companies only; otherwise put everything in "LinkedIn page URLs".

## `postsPerTarget` (type: `integer`):

The most posts delivered for EACH page you name — three pages at 50 collect up to 150. Any number from 1 to 500 is used exactly as typed (set 2 for the latest 2 posts of each page), and only delivered posts are charged; a number above 500 is moved to 500 and one uncharged row says so. A page that runs short leaves an uncharged row saying so. Also answers to `resultsLimit`, `limit`, `count`, `maxPosts` and `maxResults`; the smallest limit present binds.

## `maxItems` (type: `integer`):

Hard ceiling across every page in the run, whatever the per-page limit says — between 1 and 100,000, and a number outside that is moved to the nearest end on an uncharged row instead of the run being refused. Leave it empty for 1,000. The smallest limit present binds, and one uncharged note row says which name was read and what it was read as.

## `postedAfter` (type: `string`):

Keep only posts published on or after this moment: a date (2026-08-01, 1 Aug 2026, or 01.08.2026 day first) or a span counted back from now (24h, 7 days, 2 weeks, 3 months, 1 year, 7d, last month, today, yesterday). The walk stops as soon as a page's oldest post is older than this, so a narrow window costs less, not more.

## `postedBefore` (type: `string`):

Keep only posts published before this moment: a date (2026-09-01, 1 Sep 2026, or 01.09.2026 day first) or a span counted back from now (24h, 7 days, 2 weeks, 3 months, 1 year, 7d, last month, today, yesterday), the same forms as "Posted after". Pair it with "Posted after" for a closed window. A post outside the window is dropped before it takes a slot, so it is never delivered and never charged.

## `maxPagesPerProfile` (type: `integer`):

With "Posted before" set, the most pages a run reads from each link before it reaches your dates — a page is one screen of this profile's posts, newest first — after which that link stops on one row saying so (1 to 200, empty for 5).

## `includeReposts` (type: `boolean`):

ON (default): a repost is delivered as a row marked `isRepost: true`, carrying the original post's id, link, author and its own publish time. OFF: reposts are dropped before they take a slot, so the page's own writing fills the count instead.

## `maxRunSeconds` (type: `integer`):

The run stops cleanly before this many seconds and reports what is left, instead of being killed by a timeout — between 30 and 7,200, and a number outside that is moved to the nearest end on an uncharged row. A time limit ends the collecting, never the delivering: posts already in hand are always written out.

## `includeSeen` (type: `boolean`):

OFF (default): posts already delivered to your account are skipped (no row, no post fee) and the link reads no older page past them (a run with resumeFromDatasetId set still reads past them, to pick up where a stopped run left off). ON: they return as `repeat: true`, no post fee, and older pages are read. Either way a link read fresh with nothing new pays one check and is not read again for up to 24 hours with the same dates and setting (its row says when). Posts held over 90 days count as new.

## `resumeFromDatasetId` (type: `string`):

The dataset ID of a previous run of this actor. Posts already in it are treated as posts you already have and are skipped, so a follow-up run collects only what is new even from a different Apify account. Selecting it here is what grants this run permission to read it.

## Actor input object example

```json
{
  "startUrls": [],
  "profileUrls": [],
  "companyUrls": [],
  "postsPerTarget": 50,
  "maxItems": 1000,
  "maxPagesPerProfile": 5,
  "includeReposts": true,
  "maxRunSeconds": 1800,
  "includeSeen": false
}
```

# Actor output Schema

## `posts` (type: `string`):

One row per post delivered from a LinkedIn profile or company page: the post's own id and permalink, the full text, the real publish timestamp LinkedIn stamps on it (to the millisecond, not a "2 weeks ago" label), likes, comments, shares and the per-type reaction breakdown, the image, video, document and article links attached to it, the author with their page link and follower count or headline, and — when the post is a repost — the original post's id, link, author and publish time. Where LinkedIn hides a count on a page, the number is null and `countsHidden` names which count is hidden, so a hidden total never reads as a zero. Every row carries `charged` and `status`, so the invoice reconciles from the dataset itself: only rows with charged = true were billed, and starting a run costs nothing.

## `misses` (type: `string`):

One uncharged row for every page that returned less than it was asked for, saying which of these happened: `profile_not_found` / `page_not_found` (LinkedIn does not list a public page at this URL, or it cannot be read without a login), `no_data` (the page is real and LinkedIn shows no public posts on it), `skipped.all_repeat` (the page reached posts your account already had, so the run read no older page for that link, or it had nothing new for your account when checked in the last 24 hours under the same dates, so it was not read again), `skipped.page_cap` (the walk reached the 200 pages this actor reads for one link while LinkedIn was still serving — this actor's own bound, never a verdict about the page), `input_error` (the link is not a LinkedIn profile or company page — a link to a single post says so and names the field), `try_again` (the read failed on this run and a re-run is the fix), `limit_reached` (this run reached its limit and a new run fetches the remaining posts, or this actor is paused for now — the row says which), `skipped_max_items` / `skipped_budget` / `skipped_deadline` (one of your own limits or the run clock stopped it first), and `skipped.free_plan_allowance` (on the Apify free plan only, the plan's daily allowance on this actor was reached — the row names the reset time in UTC). None of these charges a post. The one fee such a row can carry is the page's check (the Pricing tab): a `no_data`, `skipped_date_window` or `skipped.all_repeat` row for a page this run read fresh with nothing new says it paid the check and carries `checkCharged: true`.

## `summary` (type: `string`):

Posts delivered, what was asked for, posts your account already had, what stopped the run, and the charged-event totals.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [],
    "profileUrls": [],
    "companyUrls": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadyfetch/linkedin-posts-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "startUrls": [],
    "profileUrls": [],
    "companyUrls": [],
}

# Run the Actor and wait for it to finish
run = client.actor("steadyfetch/linkedin-posts-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [],
  "profileUrls": [],
  "companyUrls": []
}' |
apify call steadyfetch/linkedin-posts-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,steadyfetch/linkedin-posts-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/zTbTZLIBzmYQBq6P5/builds/MMcHecC5wuQVXff3S/openapi.json
