LinkedIn Reactions
Reactions on any post. Full profile data per reaction.
Run as an Apify Actor. Scrape every reaction on any LinkedIn post.
Quickstart (Apify API)
# Trigger the actor with the Apify APIcurl -X POST "https://api.apify.com/v2/acts/atomus~linkedin-reactions-scraper-pro/runs?token=YOUR_APIFY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ }'What it does
Get every reaction on a LinkedIn post with the full profile of
whoever reacted. Page through up to ~1,200 reactions per post
(LinkedIn's public list cap). Optional filters tag entries via
matches_filters but never reduce the page count.
1 credit per page (100 reactions).
Endpoint
POST https://api.atomusapi.dev/v1/linkedin-reactions/extractAuthentication
Send your API key as a Bearer token in the Authorization header. Keys are scoped to a single tenant.
Authorization: Bearer atm_live_xxxxxxxxxxxxxx — or X-RapidAPI-Proxy-Secret: <secret> when calling through the RapidAPI gatewayIdempotency
Send Idempotency-Key: <uuid> to make a request safely retryable. Atomus stores the response for 24h and replays it on retries with the same key.
Input
Request body
| Field | Type | Description | |
|---|---|---|---|
| postUrl | string | required | A LinkedIn post identifier. Accepts: /feed/update/urn:li:share:... or /feed/update/urn:li:activity:... URLs, /posts/... URLs, share/activity URNs, or a raw 10+ digit activity ID. Share URNs are resolved to activity IDs upstream on first use. |
| cursor | string | null | optional | Opaque pagination cursor returned by a prior call. Omit on the first request. Pass back data.pagination.cursor verbatim to fetch the next page. |
| filters.reactionType | string | null | optional | Filter reactors by reaction type. ALL (or omitted) returns every reaction. LinkedIn types: LIKE, PRAISE (Celebrate), EMPATHY (Love), APPRECIATION (Insightful), INTEREST (Curious), ENTERTAINMENT (Funny). |
| filters.headlineKeywords | string[] | optional | Up to 20 case-insensitive keywords. A reactor matches when their headline contains at least one. Tags reactors via matches_filters; reactors are still returned regardless. |
| filters.excludeCompanies | boolean | null | optional | When true, marks company-page reactors (LinkedIn /company/ URLs) as not matching filters. They are still returned with is_company=true so you can audit the cut. |
| metadataOnly | boolean | null | optional | When true, skip reactor extraction and return only data.pagination.total_reactions_on_post. data.reactions is always [], pagination.has_more is always false, cursor and filters are ignored. Cheaper than a full extraction (RapidAPI: 1 reaction unit; Atomus: 1 credit). Use to check whether a post has new reactions before paying for a full scrape. |
Output
Response object
| Field | Type | Description | |
|---|---|---|---|
| data.reactions | object[] | required | Reactors on this page, in upstream order. Length is at most 100 (LinkedIn returns reactor pages of fixed size; the final page may be shorter). |
| data.reactions[].reaction_type | string | required | Raw reaction type from LinkedIn (LIKE, PRAISE, EMPATHY, APPRECIATION, INTEREST, ENTERTAINMENT). |
| data.reactions[].is_company | boolean | required | True when the reactor is a LinkedIn company page rather than a person. |
| data.reactions[].matches_filters | boolean | required | True when this reactor satisfies every filter you sent (reactionType, headlineKeywords, excludeCompanies). True for all reactors when no filters are sent. |
| data.reactions[].reactor.id | string | required | LinkedIn URN-style ID for the reactor. Stable across calls; use this as the dedup key when aggregating across pages or runs. |
| data.reactions[].reactor.name | string | required | Display name of the reactor. |
| data.reactions[].reactor.headline | string | required | Reactor headline (the short tagline below the name on LinkedIn). Empty string when the upstream profile has none. |
| data.reactions[].reactor.linkedinUrl | string | required | Canonical LinkedIn URL — /in/<slug>/ for people, /company/<slug>/ for company pages. Trailing path segments and query strings are stripped. |
| data.reactions[].reactor.profile_pic | string | null | required | Avatar URL when LinkedIn exposes one, null otherwise. |
| data.reactions[]._metadata.post_url | string | required | Echoes the postUrl input after share-to-activity resolution. |
| data.reactions[]._metadata.activity_id | string | required | LinkedIn activity ID for the post that this reaction belongs to. |
| data.reactions[]._metadata.extracted_at | string | required | ISO 8601 UTC timestamp recorded when this reaction was scraped. |
| data.pagination.cursor | string | null | required | Opaque token. Pass it as request.cursor to fetch the next page. null when has_more=false. |
| data.pagination.has_more | boolean | required | True while more pages remain. False on the final page. |
| data.pagination.total_reactions_on_post | number | required | Upstream-reported total reactor count on this post. May exceed what is reachable via pagination — see truncated. |
| data.pagination.truncated | boolean | required | True on the final page when LinkedIn did not expose every reactor in its public list. LinkedIn caps the public reactions list at approximately 1,200-1,250 entries per post; reactors beyond that cap are not accessible to any cookieless API. False when has_more=true (truncation can only be detected on the last page). |
| data.pagination.truncation_note | string | null | required | Human-readable explanation when truncated=true; null otherwise. Use it verbatim in support replies. |
| meta.request_id | string | required | Opaque trace ID. Include when filing a support ticket. |
| meta.api | string | required | API identifier: linkedin-reactions. |
| meta.version | string | required | API version string. |
| meta.mode | string | required | Environment mode the request ran in. live and test are Atomus Bearer authentication; rapidapi indicates the request came in via the RapidAPI gateway and is billed there, not by Atomus. |
| meta.credits_used | number | required | Credits charged for this request. Always 0 in rapidapi mode (RapidAPI bills the consumer on its side). |
| meta.credits_remaining | number | null | required | Tenant credit balance after this request. null in rapidapi mode (no Atomus credit account is debited). |
| meta.duration_ms | number | required | Server-side processing duration in milliseconds. |
Example request
curl
curl -X POST "https://api.atomusapi.dev/v1/linkedin-reactions/extract" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "postUrl": "https://www.linkedin.com/feed/update/urn:li:activity:7404946870776868864/" }'JavaScript
// Atomus Bearer auth. Pass cursor on subsequent calls to paginate.async function* extractAllReactions(postUrl) { let cursor; do { const res = await fetch( "https://api.atomusapi.dev/v1/linkedin-reactions/extract", { method: "POST", headers: { "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ postUrl, cursor }), } );
if (!res.ok) { const { error } = await res.json(); throw new Error(`${error.code}: ${error.message}`); }
const { data } = await res.json(); for (const r of data.reactions) yield r; cursor = data.pagination.cursor; } while (cursor);}
for await (const r of extractAllReactions( "https://www.linkedin.com/feed/update/urn:li:activity:7404946870776868864/")) { if (r.matches_filters) console.log(r.reactor.name, "—", r.reactor.headline);}Python
import requests
# Atomus Bearer auth. Pass cursor on subsequent calls to paginate.def extract_all_reactions(post_url, api_key): cursor = None while True: res = requests.post( "https://api.atomusapi.dev/v1/linkedin-reactions/extract", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", }, json={"postUrl": post_url, "cursor": cursor}, timeout=60, ) if not res.ok: err = res.json()["error"] raise RuntimeError(f"{err['code']}: {err['message']}") data = res.json()["data"] for r in data["reactions"]: yield r cursor = data["pagination"]["cursor"] if not cursor: break
for r in extract_all_reactions( "https://www.linkedin.com/feed/update/urn:li:activity:7404946870776868864/", "YOUR_API_KEY",): if r["matches_filters"]: print(r["reactor"]["name"], "—", r["reactor"]["headline"])curl (RapidAPI)
# RapidAPI gateway auth. Use this when calling the API through your# RapidAPI subscription instead of an Atomus account. RapidAPI bills# the consumer at the gateway; the response reports mode="rapidapi"# and credits_used=0.curl -X POST "https://api.atomusapi.dev/v1/linkedin-reactions/extract" \ -H "X-RapidAPI-Proxy-Secret: YOUR_RAPIDAPI_PROXY_SECRET" \ -H "Content-Type: application/json" \ -d '{ "postUrl": "https://www.linkedin.com/feed/update/urn:li:activity:7404946870776868864/" }'curl (metadata only)
# Metadata-only mode. Returns just the post's total reaction count# without extracting individual reactors. RapidAPI: 1 reaction unit;# Atomus: 1 credit. Useful as a cheap pre-check before committing to# a full scrape — e.g. compare against a previous total to decide# whether new reactions arrived since last run.curl -X POST "https://api.atomusapi.dev/v1/linkedin-reactions/extract" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "postUrl": "https://www.linkedin.com/feed/update/urn:li:activity:7404946870776868864/", "metadataOnly": true }'Errors & limits
{ "error": { "code": "rate_limit_exceeded", "message": "Human-readable explanation.", "retryable": true, "request_id": "req_01HXXX..." }}unauthenticatedHTTP 401 : Missing or malformed Authorization header. (do not retry)invalid_api_keyHTTP 401 : API key is not recognized or has been revoked. (do not retry)insufficient_creditsHTTP 402 : Atomus tenant credit balance is below 1. Not raised for requests authenticated via the RapidAPI gateway (those are billed by RapidAPI). (do not retry)invalid_inputHTTP 400 : Request body is not valid JSON, or the cursor is malformed (must be the opaque token returned by a prior call). (do not retry)validation_failedHTTP 422 : postUrl is missing, longer than 500 chars, or the upstream API rejected it as not a valid public LinkedIn post. (do not retry)rate_limit_exceededHTTP 429 : Sustained request rate exceeded the tenant limit. (retryable)upstream_errorHTTP 502 : Upstream provider returned a non-success response. (retryable)upstream_timeoutHTTP 504 : Upstream provider did not respond within the time budget. (retryable)internal_errorHTTP 500 : Unexpected server error. (retryable)
Rate limits
5 requests/second per account (shared across all API keys on the same account). Each request fetches one upstream page (up to 100 reactors). Bursts above the limit return 429 rate_limit_exceeded; back off using the response headers. The per-second window is enforced server-side; the per-minute, per-hour, per-day, per-week, and per-month rows are sustained-throughput derivations.
| Window | Max requests |
|---|---|
| Per second | 5 |
| Per minute | 300 |
| Per hour | 18,000 |
| Per day | 432,000 |
| Per week | 3,024,000 |
| Per month | 12,960,000 |
x-ratelimit-limit: max requests per second for the account (shared across all keys)x-ratelimit-remaining: requests remaining in the current windowx-ratelimit-reset: unix epoch (seconds) when the window resets
Billing
- $0.005 per reactor returned ($5 per 1,000) — billed as 1 Atomus credit per page (100 reactors) = $0.50 per page
Atomus mode (live): one credit reserved per call, settled at one credit on success regardless of how many reactions LinkedIn returned (filters tag entries via matches_filters but never reduce the page count). Errors before any upstream call refund the reservation. RapidAPI mode (X-RapidAPI-Proxy-Secret): RapidAPI bills the consumer at the gateway via the X-RapidAPI-Billing response header (Reactions quota object, $0.005 each); Atomus does not deduct credits and reports credits_used=0 with credits_remaining=null in the response meta.
Use the RapidAPI gateway. Per-reaction billing handled at the gateway, no Atomus account needed.
Quickstart (RapidAPI gateway)
# RapidAPI gateway authenticationcurl -X POST "https://api.atomusapi.dev/v1/linkedin-reactions/extract" \ -H "X-RapidAPI-Key: YOUR_RAPIDAPI_KEY" \ -H "X-RapidAPI-Host: api.atomusapi.dev" \ -H "Content-Type: application/json" \ -d '{ }'Running high volumes?
Skip the marketplace tiers and get unit pricing scoped to your real call volume, with a direct line to the team that runs the pipeline.
Get volume pricing