LinkedIn Conversation Scraper with Named Senders & Thread Members extracts LinkedIn conversation data, including sender names, thread members, message text, timestamps, attachments, and conversation details. Ideal for CRM migration, communication analysis, workflow automation, and data backup.
Ported the base actor's finalize-pass fixes so this variant's shared engine and
shared output fields stay in sync with the base (see the base's own CHANGELOG
0.3 entry and Reports/LinkedIn Conversation Scraper/BUILD-REPORT-...md §
finalize):
list_type: INBOX ("All Inbox") now queries PRIMARY_INBOX + OTHER together
instead of silently aliasing to PRIMARY_INBOX alone.
api_get()'s retry logic no longer swallows-and-retries permanent HTTP errors
(400/401/403/…) — those now raise immediately; only 429/5xx and network
exceptions retry with backoff.
get_self_urn()'s AuthFailed detection now also recognizes HTTP 400 (the
actual status LinkedIn returns for an unauthenticated /me call), not just
401/403/302.
creator_name / creator_profile_url are now unconditional — previously
gated behind include_thread_members, they now always match the base's own
(also newly-added) value for the same input, regardless of the toggle.
thread_members / thread_title / thread_url remain correctly gated behind
include_thread_members (variant-only fields, no base equivalent).
created_at now falls back to the conversation's own createdAt when the
first message's own date fails to parse, instead of silently emitting null
— matches the base's fixed value for equivalent input.
0.1 — 2026-08-16 (this variant)
New variant: named senders & thread members. Added include_thread_members,
name_message_senders, only_with_participants inputs (all superset-compatible
with the base's 10 inputs, unchanged, in order).
Every conversationParticipants[] entry is now mapped (not just the base's
single pick_other_participant() pick) into a new thread_members[] field,
plus thread_title, thread_url, creator_name, creator_profile_url.
Every message gains sender_name / sender_profile_url / sender_urn, joined
from message.sender.hostIdentityUrn against the roster — zero extra requests.
last_message_sender_name / last_message_sender_url mirror the same join.
All 15 base output keys, participants (still one element) and who /
last_message_who (still "me"/"her/him") kept byte-for-byte unchanged for
backward compatibility — the new fields are additive only.
only_with_participants filters conversations client-side against the full
roster, after messages are fetched — same behavior/consequence as the base's
own date filter (not saved ⇒ not charged).
PPE row_result charging mechanics untouched.
0.2 — 2026-06-24
New engine — LinkedIn Voyager messaging API. Replaced the fragile
DOM-scraping engine with calls to LinkedIn's own messaging GraphQL endpoints
(the same the web app makes), issued through an authenticated headless-browser
request context. This is immune to CSS-selector churn and the "conversation
cards never rendered → failed run" blocks that previously caused repeated
"under maintenance" flags. queryIds are extracted live when the pinned
fallbacks return nothing.
Fixed the recurring "under maintenance" root cause. A missing/invalid
li_at, or LinkedIn blocking every proxy tier, now ends the run successfully
with an empty dataset and a clear log — never a FAILED run. Apify's
automated Store health check runs the default (empty) li_at, and failing it
there is exactly what kept flipping the Actor to "under maintenance".
Participant headline / distance / pronoun / picture now come directly from
the API response — no extra profile-page visits, much faster.
Proxy plan simplified to direct → residential (datacenter IPs are blocked
by LinkedIn); explicit user proxy config is still honored.
Added concurrency and max_retries inputs; filter now maps to LinkedIn
categories (INMAIL / STARRED / UNREAD).
PPE row_result charging unchanged (per saved conversation, stops cleanly on
spend-limit).
0.1 — 2026-06-10
Fixed build: renamed requirements.txt.txt → requirements.txt so the
Dockerfile COPY requirements.txt ./ resolves.
Hardened pay-per-event charging: per-conversation row_result charge now
inspects ChargeResult.event_charge_limit_reached and stops the run
gracefully when the user's spend limit is hit (no crash, partial data kept).
Charging is best-effort — dataset writes still succeed when charging is
unavailable (e.g. local runs).