# LinkedIn Post Personalizer - AI Comment + DM Generator (`fetchcraft/linkedin-post-personalizer`) Actor

Paste a LinkedIn post and prospect info, get a personalized AI comment or DM. Optimized for B2B outbound that opens with substance (not "great post"). Tone presets: thoughtful, direct, warm, curious, contrarian. Bring your own LLM key. $0.05 to $0.10 per prospect.

- **URL**: https://apify.com/fetchcraft/linkedin-post-personalizer.md
- **Developed by:** [Emily Ward](https://apify.com/fetchcraft) (community)
- **Categories:** Lead generation, AI, Social media
- **Stats:** 3 total users, 1 monthly users, 85.7% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 Post Personalizer

Personalize LinkedIn DMs at scale without scraping LinkedIn.

You paste each prospect's LinkedIn URL, the text of their most recent (or a relevant) post, and their role. The actor generates a 2-sentence DM opener, a <300-char connection note, a fit score, and a day-3 next-touch suggestion.

### Why no scraping

LinkedIn's ToS prohibits scraping. Their bot detection is aggressive. This actor never touches LinkedIn directly. You bring the post text, the actor brings the personalization.

### Pricing

$0.10 per `dm_opener_generated` event. After Apify's 20% cut and Anthropic costs, net is approximately $0.07 per opener.

For comparison: Lavender, the dominant LinkedIn-DM-personalization tool, runs $29 to $59/month per seat. At 60 DMs/month a buyer pays $6 on this actor vs $29 on Lavender, plus they pay only for what they generate.

### How to use

1. Pull your prospect list (e.g. from a Sales Navigator export or a LinkedIn search you saved manually).
2. For each prospect, copy the post text you want to reference.
3. Drop them all into the `prospects` input as JSON.
4. Run.
5. Paste the generated `dm_opener` or `connection_note` directly into LinkedIn.

### Output per prospect

- `dm_opener`: 2 sentences, references something specific in their post
- `connection_note`: under 300 characters, follows LinkedIn's connection-request limit
- `fit_score`: 0 to 100, how well their post + role aligns with your pitch
- `post_acknowledgement`: one sentence that responds to their post without being sycophantic
- `recommended_next_touch`: day-3 follow-up suggestion if they accept the connection but don't reply

### Buyer's typical workflow

This actor pairs well with three companion actors. Cover the four highest-leverage prospecting moves with one Apify wallet:

- **[AI Sales Personalizer](https://apify.com/fetchcraft/ai-sales-personalizer)** ($0.15/result). Homepage to personalized opener.
- **[Cold Email Rewriter](https://apify.com/fetchcraft/cold-email-rewriter)** ($0.10/rewrite). Draft to predicted reply rate + 3 variants.
- **[SEO Competitor Gap](https://apify.com/fetchcraft/seo-competitor-gap)** ($0.50/competitor). Find topical gaps to reference in outbound.

### Use cases

- **SDRs and AEs**: Turn a LinkedIn Sales Navigator export into a ready-to-paste DM batch without copy-pasting individual posts.
- **Founders doing outbound**: Replace "hey I saw your profile" with a DM that actually references something they wrote.
- **Recruiters**: Personalize connection requests to passive candidates at scale.
- **Agencies**: Add LinkedIn personalization to client outreach packages without buying another SaaS seat.

### What this actor does NOT do

- It does not scrape LinkedIn. You bring the post text and prospect data.
- It does not send messages. Use your LinkedIn account, Dux-Soup, or similar to paste and send.
- It does not find prospect post text for you. Use LinkedIn Sales Navigator, manual browsing, or a LinkedIn scraper (separate actor or tool) to collect the posts.

### FAQ

**Q: Why do I need to bring the post text?**
LinkedIn prohibits automated scraping. This actor processes data you provide rather than fetching from LinkedIn directly, which keeps you compliant with LinkedIn's ToS.

**Q: What format is the input?**
An array of prospect objects, each with a `url`, `post_text`, `role`, and optionally a `company_name`. Full schema in the actor's Input tab.

**Q: Does it work for cold connection requests?**
Yes. The `connection_note` field is under 300 characters specifically to fit LinkedIn's connection-request limit.

**Q: What if I don't have a recent post for a prospect?**
Pass their "About" section text, bio text, or any other text that signals their interests. The opener quality drops slightly without a recent post but is still personalised.

---

Tags: `linkedin` `sales` `personalization` `outreach` `sdr` `b2b` `cold-outreach` `ai` `claude` `lead-generation`

Made by Emily Ward, Founder of Cancel Costs. Questions: emily@cancelcosts.com


### Integrations

This actor works out of the box with every Apify-supported integration:

- **API**: call via Apify API or any official SDK (Python, JavaScript, PHP, .NET). Returns a clean dataset URL.
- **Schedule**: set a daily, weekly, or custom cron cadence in Apify Console. Combine with `notification` for fresh feeds.
- **Webhooks**: wire `ACTOR.RUN.SUCCEEDED` to Slack, Discord, Zapier, Make, n8n, Pipedream, or any HTTPS endpoint.
- **MCP**: this actor is discoverable through Apify's hosted MCP server at `mcp.apify.com` for Claude, Cursor, Cline, Windsurf, and other MCP clients.
- **n8n / Make / Zapier**: native HTTP-Request integration. Trigger the actor on schedule, pipe results to Google Sheets, Airtable, your CRM, or any database.

### Try it free

Every Apify user gets **$5/month in free platform credits** (around 250 events at this actor's per-event price). Run preview mode first to confirm output shape before scaling.

New to Apify? [Sign up here](https://apify.com/sign-up?fpr=fetchcraft) to get free credits on signup.

### What's New

- 2026-06-03: Metadata, categories, and SEO refreshed. Latest version live on Apify Store.

### Last Updated

2026-06-03

# Actor input Schema

## `prospects` (type: `array`):

List of objects, each REQUIRING three fields: linkedin_url (the prospect's profile URL), post_text (paste their post body, minimum 20 chars), contact_role (their job title). Optional: name, company. The actor never scrapes LinkedIn - you provide the post text.
## `your_product_pitch` (type: `string`):

What you sell. Concrete beats vague. The AI uses this to compute fit score and tailor the DM.
## `tone` (type: `string`):

How the DM opener should read.
## `max_concurrency` (type: `integer`):

Number of prospects processed in parallel. Higher = faster, lower = avoids rate limits. Default 5 works for most lists.
## `llm_provider` (type: `string`):

Pick which LLM you want. Gemini is recommended (1500 free requests/day at https://aistudio.google.com/apikey). Groq also good (14400 free/day at https://console.groq.com/keys). Leave blank to use the actor owner's configured key (if any).
## `llm_api_key` (type: `string`):

Paste the API key for the provider you selected. Never leaves the Apify run, never logged. Free tier providers (Gemini, Groq) give thousands of free results per day.

## Actor input object example

```json
{
  "prospects": [
    {
      "linkedin_url": "https://www.linkedin.com/in/example/",
      "post_text": "Just shipped our new RevOps dashboard. Took 3 weeks of Postgres pain to get pipeline data clean enough to ship. Worth every hour.",
      "contact_role": "Head of RevOps"
    }
  ],
  "your_product_pitch": "We cut Postgres-heavy RevOps queries from 30 seconds to under 1 second using a usage-aware materialized-view layer. Self-serve, no DBA required.",
  "tone": "thoughtful",
  "max_concurrency": 5,
  "llm_provider": ""
}
````

# 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 = {
    "prospects": [
        {
            "linkedin_url": "https://www.linkedin.com/in/example/",
            "post_text": "Just shipped our new RevOps dashboard. Took 3 weeks of Postgres pain to get pipeline data clean enough to ship. Worth every hour.",
            "contact_role": "Head of RevOps"
        }
    ],
    "your_product_pitch": "We cut Postgres-heavy RevOps queries from 30 seconds to under 1 second using a usage-aware materialized-view layer. Self-serve, no DBA required."
};

// Run the Actor and wait for it to finish
const run = await client.actor("fetchcraft/linkedin-post-personalizer").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 = {
    "prospects": [{
            "linkedin_url": "https://www.linkedin.com/in/example/",
            "post_text": "Just shipped our new RevOps dashboard. Took 3 weeks of Postgres pain to get pipeline data clean enough to ship. Worth every hour.",
            "contact_role": "Head of RevOps",
        }],
    "your_product_pitch": "We cut Postgres-heavy RevOps queries from 30 seconds to under 1 second using a usage-aware materialized-view layer. Self-serve, no DBA required.",
}

# Run the Actor and wait for it to finish
run = client.actor("fetchcraft/linkedin-post-personalizer").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "prospects": [
    {
      "linkedin_url": "https://www.linkedin.com/in/example/",
      "post_text": "Just shipped our new RevOps dashboard. Took 3 weeks of Postgres pain to get pipeline data clean enough to ship. Worth every hour.",
      "contact_role": "Head of RevOps"
    }
  ],
  "your_product_pitch": "We cut Postgres-heavy RevOps queries from 30 seconds to under 1 second using a usage-aware materialized-view layer. Self-serve, no DBA required."
}' |
apify call fetchcraft/linkedin-post-personalizer --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=fetchcraft/linkedin-post-personalizer",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "LinkedIn Post Personalizer - AI Comment + DM Generator",
        "description": "Paste a LinkedIn post and prospect info, get a personalized AI comment or DM. Optimized for B2B outbound that opens with substance (not \"great post\"). Tone presets: thoughtful, direct, warm, curious, contrarian. Bring your own LLM key. $0.05 to $0.10 per prospect.",
        "version": "0.1",
        "x-build-id": "1PqqHZRDCIIFNoqcT"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/fetchcraft~linkedin-post-personalizer/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-fetchcraft-linkedin-post-personalizer",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/fetchcraft~linkedin-post-personalizer/runs": {
            "post": {
                "operationId": "runs-sync-fetchcraft-linkedin-post-personalizer",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/fetchcraft~linkedin-post-personalizer/run-sync": {
            "post": {
                "operationId": "run-sync-fetchcraft-linkedin-post-personalizer",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "prospects",
                    "your_product_pitch"
                ],
                "properties": {
                    "prospects": {
                        "title": "Prospects",
                        "type": "array",
                        "description": "List of objects, each REQUIRING three fields: linkedin_url (the prospect's profile URL), post_text (paste their post body, minimum 20 chars), contact_role (their job title). Optional: name, company. The actor never scrapes LinkedIn - you provide the post text."
                    },
                    "your_product_pitch": {
                        "title": "Your product pitch (one paragraph)",
                        "minLength": 20,
                        "maxLength": 2000,
                        "type": "string",
                        "description": "What you sell. Concrete beats vague. The AI uses this to compute fit score and tailor the DM."
                    },
                    "tone": {
                        "title": "Tone of DM",
                        "enum": [
                            "thoughtful",
                            "direct",
                            "warm",
                            "curious",
                            "contrarian"
                        ],
                        "type": "string",
                        "description": "How the DM opener should read.",
                        "default": "thoughtful"
                    },
                    "max_concurrency": {
                        "title": "Max parallel requests",
                        "minimum": 1,
                        "maximum": 20,
                        "type": "integer",
                        "description": "Number of prospects processed in parallel. Higher = faster, lower = avoids rate limits. Default 5 works for most lists.",
                        "default": 5
                    },
                    "llm_provider": {
                        "title": "LLM provider (bring your own key)",
                        "enum": [
                            "",
                            "gemini",
                            "groq",
                            "cerebras",
                            "openrouter",
                            "huggingface",
                            "anthropic"
                        ],
                        "type": "string",
                        "description": "Pick which LLM you want. Gemini is recommended (1500 free requests/day at https://aistudio.google.com/apikey). Groq also good (14400 free/day at https://console.groq.com/keys). Leave blank to use the actor owner's configured key (if any).",
                        "default": ""
                    },
                    "llm_api_key": {
                        "title": "Your LLM API key (paired with llm_provider above)",
                        "type": "string",
                        "description": "Paste the API key for the provider you selected. Never leaves the Apify run, never logged. Free tier providers (Gemini, Groq) give thousands of free results per day."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
