# 💬 LinkedIn Conversation Scraper (`api-empire/linkedin-conversation-scraper`) Actor

LinkedIn Conversation Scraper: Extract LinkedIn conversation threads with messages, senders, timestamps, participants, and conversation details. Organize messaging data for communication analysis, relationship research, workflow insights, and structured LinkedIn data management.

- **URL**: https://apify.com/api-empire/linkedin-conversation-scraper.md
- **Developed by:** [API Empire](https://apify.com/api-empire) (community)
- **Categories:** Automation, Lead generation, Social media
- **Stats:** 4 total users, 4 monthly users, 2.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.99 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## 💬 LinkedIn Conversation Scraper

> **Pull every conversation from your LinkedIn inbox into structured JSON — messages, dates, participants, headlines, distance, pronouns, and more.** No fragile API hacks. Just your own session cookie and a real Chromium tab under the hood.

***

### ✨ Why Choose Us?

- 🛡️ **Reads LinkedIn's own messaging API** — issues the same GraphQL calls the LinkedIn web app makes, through a real authenticated browser session. Immune to CSS-selector churn; `queryId`s are auto-refreshed live when LinkedIn rotates them.
- ⚡ **Live streaming** — every conversation is pushed to the dataset the moment it's parsed (crash mid-run? you still keep what was collected)
- 🌐 **Smart proxy escalation** — starts direct, then auto-falls back to **residential** when LinkedIn blocks the exit IP (datacenter IPs are blocked by LinkedIn, so they're skipped)
- 🧩 **Built-in profile enrichment** — headline, distance (1st/2nd/3rd), pronouns and picture come straight from the API response, no extra page visits, no slowdown
- 📅 **Date filters** — `today_limit` or `date_limit` to grab only what's recent
- 🎯 **Stylish, modern input UI** with emoji-rich field labels

***

### 🔑 Key Features

| Feature | What it does |
|--------|-------------|
| 📥 **Inbox sweep** | Primary, All, Other, Archive, Spam |
| 🔎 **Filters** | InMail, Starred, Unread only |
| 💬 **Per-thread depth** | Configurable max messages per conversation |
| ✨ **Profile enrichment** | Headline + distance + pronouns + picture, straight from the API |
| 🌐 **Tiered proxy fallback** | Direct → Residential (auto, on block) |
| 📅 **Date filters** | Today-only or older-than-cutoff |
| 💾 **Live saving** | `Actor.push_data` per conversation — no data loss on crash |

***

### 📥 Input

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| 🔐 `li_at` | string | **Yes** | Your `li_at` cookie from www.linkedin.com (treat as a password) |
| 📥 `list_type` | string | No | `PRIMARY_INBOX` (default), `INBOX`, `SECONDARY_INBOX`, `ARCHIVE`, `SPAM` |
| 🔎 `filter` | string | No | `""` (none), `INMAIL`, `STARRED`, `UNREAD` |
| 💬 `max_convs` | integer | No | Max conversations to scrape (`0` = unlimited) |
| 📝 `max_messages_per_conv` | integer | No | Max messages per conversation (`0` = unlimited, most-recent kept) |
| 📅 `today_limit` | boolean | No | If true, only today's conversations |
| 🗓️ `date_limit` | string | No | `YYYY-MM-DD` — skip conversations older than this date |
| ⚡ `concurrency` | integer | No | Parallel thread-message fetches (default `5`) |
| 🔁 `max_retries` | integer | No | Retries per API request on 429/5xx (default `3`) |
| 🌐 `proxyConfiguration` | object | No | Defaults to **direct**; auto-escalates to residential if LinkedIn blocks |

#### Example input

```json
{
  "li_at": "AQEDAU...your_cookie...",
  "list_type": "PRIMARY_INBOX",
  "filter": "",
  "max_convs": 10,
  "max_messages_per_conv": 25,
  "today_limit": false,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

***

### 📤 Output

Each dataset record is one conversation:

```json
{
  "participants": [
    {
      "url": "https://www.linkedin.com/in/ACoAADM...",
      "distance": "DISTANCE_1",
      "pronoun": "she/her",
      "picture": "https://media.licdn.com/.../profile.jpg",
      "firstname": "Raisul",
      "lastname": "Islam",
      "headline": "Founder @ Authentic Digital Marketing",
      "entityUrn": "ACoAADM..."
    }
  ],
  "status": "ACTIVE",
  "unread_count": 0,
  "last_read_at": null,
  "last_activity_at": "2026-05-03 15:15:00",
  "is_group_chat": false,
  "creator": "ACoAAEjB...",
  "created_at": "2026-05-03 15:15:00",
  "messages": [
    { "content": "test message", "date": "2026-05-03 15:15:00", "who": "me" }
  ],
  "total_messages": 1,
  "last_message_date": "2026-05-03 15:15:00",
  "last_message_content": "test message",
  "last_message_who": "me",
  "days_from_today": 11,
  "_conversation_id": "2-ZmExYTkx..."
}
```

#### Field reference

| Field | Description |
|-------|-------------|
| `participants` | Array of participant objects (name, URL, headline, distance, pronoun, picture, entityUrn) |
| `status` | Conversation status (`ACTIVE`) |
| `unread_count` | Number of unread messages |
| `last_activity_at` | Timestamp of the most recent message (`YYYY-MM-DD HH:MM:SS`) |
| `is_group_chat` | True if multi-person thread |
| `creator` | URN of whoever sent the first message we collected |
| `created_at` | Timestamp of the first collected message |
| `messages` | Array of `{ content, date, who }` (oldest → newest) |
| `total_messages` | Number of messages collected |
| `last_message_*` | Convenience fields for the most recent message |
| `days_from_today` | Days since the last activity |
| `_conversation_id` | LinkedIn's thread URN |

***

### 🚀 How to Use (Apify Console)

1. 🔓 Log in to [Apify Console](https://console.apify.com) → **Actors**.
2. 🔍 Find **LinkedIn Conversation Scraper** and open it.
3. 🍪 Grab your `li_at` cookie:
   - Open [linkedin.com](https://www.linkedin.com) in Chrome → press **F12** → **Application** → **Cookies** → `https://www.linkedin.com` → copy the value of `li_at`.
4. 📝 Paste it into the **🔐 LinkedIn Session Cookie (li\_at)** field.
5. ⚙️ Configure inbox type, filter, limits, and proxy if needed.
6. ▶️ Click **Start**.
7. 📺 Watch the live log — each conversation is logged as it's saved.
8. 📂 Open the **Dataset** tab when the run finishes.
9. 📤 Export to **JSON / CSV / XLSX / Excel**.

> 💡 **Tip:** Start with `max_convs = 5` to validate everything is working before launching a full sweep.

***

### 🤖 Use via API / MCP

#### Run the actor via REST

```bash
curl -X POST "https://api.apify.com/v2/acts/%3CACTOR_ID%3E/runs?token=$APIFY_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
       "li_at": "AQEDAU...",
       "list_type": "PRIMARY_INBOX",
       "max_convs": 10,
       "max_messages_per_conv": 25,
       "proxyConfiguration": { "useApifyProxy": false }
     }'
```

#### Wait for results synchronously

```bash
curl -X POST "https://api.apify.com/v2/acts/%3CACTOR_ID%3E/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"li_at":"AQEDAU...","max_convs":3}'
```

***

### 🌐 Proxy Strategy

The scraper escalates **only when LinkedIn pushes back**:

| Step | Tier | What happens |
|------|------|--------------|
| 1️⃣ | 🟢 **Direct** | Try without any proxy first |
| 2️⃣ | 🔴 **Residential** | If LinkedIn blocks the exit IP → residential proxy with up to **4 fresh-IP retries** |
| 🔧 | **Pinned** | Set `proxyConfiguration` yourself to force a specific exit instead of auto-escalation |

> Datacenter proxies are intentionally skipped — LinkedIn blocks them outright.

Every escalation step is logged so you can see what's happening:

```
🌐 Connecting via DIRECT (no proxy) — attempt 1/1…
🛑 [DIRECT (no proxy)] Could not authenticate / blocked on this exit IP — escalating.
🌐 Connecting via RESIDENTIAL — attempt 1/4…
✅ Session authenticated (feed loaded).
```

***

### 💎 Best Use Cases

- 🧑‍💼 **CRM hygiene** — sync LinkedIn DMs into HubSpot / Salesforce
- 💼 **Recruitment ops** — track candidate replies across hundreds of outreach threads
- 📞 **Sales enablement** — surface stale conversations and follow-ups
- 🗂️ **Personal archive** — back up your own messaging history before LinkedIn deletes it
- 🔬 **Research** — analyze your own DM patterns for sentiment / topic / response time

***

### 💰 Pricing

This actor runs on **pay-per-usage** — you pay only the underlying Apify platform usage (compute units, proxies if used, dataset writes). No additional per-event charges from us.

> Run-time guideline: because data comes from LinkedIn's messaging API (not page rendering) and threads are fetched in parallel, expect roughly **0.5–1 second per conversation** at the default concurrency.

***

### ❓ Frequently Asked Questions

#### Where do I find my `li_at` cookie?

Open [linkedin.com](https://www.linkedin.com), press **F12**, go to **Application → Cookies → https://www.linkedin.com**, and copy the **Value** of the `li_at` cookie. It looks like `AQEDA...`. Treat it like a password.

#### Will this work without a cookie?

No. LinkedIn's messaging endpoints all require an authenticated session. We use *your* cookie so the scraper sees the same inbox you do.

#### Why does it sometimes need a proxy?

If you run the actor often (or from a flagged IP), LinkedIn may redirect to a login wall. The actor detects this automatically and escalates to a residential proxy. **Most users will never need a proxy.**

#### Will LinkedIn ban my account?

Use sensible limits. Don't run dozens of large sweeps a day. Lower `concurrency` if you see warnings. Scraping your **own** inbox at human-realistic rates is the lowest-risk pattern.

#### Can I scrape group chats?

Yes. `is_group_chat` is reported straight from LinkedIn's API. For each thread the output participant is the first member who isn't you (the other side of the conversation); the rest of the thread's messages are still captured in full.

#### Can I scrape someone else's inbox?

No. The `li_at` cookie ties to whoever generated it. You can only scrape your own inbox.

#### How is this different from the LinkedIn API?

The official API doesn't expose messaging to third parties. This actor uses a real browser to render the page exactly as you'd see it, bypassing API restrictions while staying within your own account's permissions.

***

### ⚠️ Cautions / Legal

- 📚 You may only scrape data your account is **authorized to see** (your own inbox).
- 🔐 Never share your `li_at` cookie publicly — it grants full access to your LinkedIn account.
- 📜 You are responsible for compliance with LinkedIn's **User Agreement**, GDPR, CCPA, and any other applicable law in your jurisdiction.
- 🤝 Don't use this to spam, harass, or unsolicited-message anyone — automated outreach violates LinkedIn's rules.
- 🚦 Respect rate limits — protect your account by keeping `concurrency` modest and `max_convs` reasonable.

***

### 🛟 Support and Feedback

- 🐛 Found a bug? File an **issue** through the Actor's Issues tab.
- 💡 Have a feature request? We listen.
- 💬 Need help? Use Apify Console's **Discussion** tab.

***

**Built with ❤️ on Apify** • [Documentation](https://docs.apify.com) • [Apify Console](https://console.apify.com)

# Actor input Schema

## `list_type` (type: `string`):

Which inbox to scrape when no URLs are provided.

## `filter` (type: `string`):

Optional extra category filter applied on top of the inbox type.

## `li_at` (type: `string`):

Your `li_at` cookie from www.linkedin.com. Required for authentication. Open LinkedIn in your browser → DevTools → Application → Cookies → www.linkedin.com → copy the `li_at` value. ⚠️ Never share this cookie publicly — treat it like a password.

## `max_convs` (type: `integer`):

Maximum number of conversations to scrape. Set `0` for no limit. Higher values = longer runs.

## `max_messages_per_conv` (type: `integer`):

Maximum number of messages to extract from each conversation. Set `0` for no limit.

## `today_limit` (type: `boolean`):

If enabled, only conversations with activity **today** are included.

## `date_limit` (type: `string`):

Skip conversations older than this date. Leave empty for no date limit.

## `concurrency` (type: `integer`):

Reserved for future use. Message threads are currently fetched one at a time on a single browser page — running them in parallel corrupted results (0-message conversations) because Playwright pages aren't safe for concurrent GraphQL calls. This field has no effect yet.

## `max_retries` (type: `integer`):

How many times to retry each LinkedIn API request on transient errors (429 / 5xx).

## `proxyConfiguration` (type: `object`):

Configure Apify proxy usage for this run. Leave off to let the actor auto-escalate residential → direct.

## Actor input object example

```json
{
  "list_type": "PRIMARY_INBOX",
  "filter": "",
  "max_convs": 5,
  "max_messages_per_conv": 5,
  "today_limit": false,
  "concurrency": 2,
  "max_retries": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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 = {
    "li_at": "",
    "max_convs": 5,
    "max_messages_per_conv": 5,
    "concurrency": 2,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("api-empire/linkedin-conversation-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 = {
    "li_at": "",
    "max_convs": 5,
    "max_messages_per_conv": 5,
    "concurrency": 2,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("api-empire/linkedin-conversation-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 '{
  "li_at": "",
  "max_convs": 5,
  "max_messages_per_conv": 5,
  "concurrency": 2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call api-empire/linkedin-conversation-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,api-empire/linkedin-conversation-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/PfQ9Soq1alGTzhdTb/builds/zCSP2ibgk5nMTjhLI/openapi.json
