> Research LinkedIn profiles and write personalized messages for any LinkedIn message type — connection requests, InMails, DMs, message requests, post comments, and comment replies. Takes LinkedIn URLs as input, researches each person (profile data + recent posts via Apify), and generates messages tailored to each lead's background, interests, and recent activity. Exports tool-ready CSVs for Dripify, Expandi, Botdog, PhantomBuster, or generic format. No LinkedIn cookies or login required.
npx skills add https://github.com/gooseworks-ai/goose-skills --skill linkedin-message-writer
Research LinkedIn leads and write personalized messages for any LinkedIn message type. Takes LinkedIn URLs, researches each person using Apify (profile + recent posts), and writes messages based on what it finds.
No LinkedIn cookies. No database setup. Just LinkedIn URLs in, personalized messages out.
Load this skill when:
Required for researching LinkedIn profiles and posts. Set in .env:
APIFY_API_TOKEN=your_token_here
No LinkedIn cookies, login, or session tokens needed. Apify handles scraping without any LinkedIn credentials.
That's it. One env var. Nothing else.
This skill writes any text-based LinkedIn message type. Each type has different constraints.
| Message Type | Who Can Receive | Character Limit | When to Use |
|-------------|----------------|-----------------|-------------|
| Connection request | 2nd/3rd degree connections | 200 (free) / 300 (premium) | First touch. Must earn the accept. No selling. |
| InMail | Anyone (requires premium credits) | Subject: 200, Body: 1,900 | Standalone pitch to people who won't accept cold connections. Senior execs, busy people. |
| DM | 1st-degree connections only | 8,000 | Follow-ups after connection accepted. Conversational, not broadcast. |
| Message request | Group members, event attendees, #OpenToWork | 8,000 | Warm context — you share a group or event. Reference the shared context. |
| Post comment | Anyone (public posts) | 1,250 | Warm-up before connecting. Show you engaged with their content. Not a pitch. |
| Comment reply | Anyone (in a thread) | 1,250 | Engage in a conversation they started. Add value, don't pitch. |
Connection request (200/300 chars):
InMail (subject 200 + body 1,900 chars):
DM (8,000 chars):
Message request (8,000 chars):
Post comment (1,250 chars):
Comment reply (1,250 chars):
Ask the user these questions. Skip any already answered.
Leads:
Message type:
Goal:
Tone:
Context:
10. Any proof points? (customer names, metrics, case studies to reference)
Output:
11. Which LinkedIn outreach tool do you use? (Dripify / Expandi / Botdog / PhantomBuster / Just give me a CSV)
Accept leads from whatever source the user provides:
linkedin_url, LinkedIn URL, LinkedIn, profile_url, url). If ambiguous, ask the user which column.Minimum required: At least one LinkedIn URL per lead.
Present the lead count to the user and confirm before proceeding to research.
Research each lead using two Apify actors. Both require only APIFY_API_TOKEN — no LinkedIn cookies.
Use harvestapi/linkedin-profile-scraper to get profile data for all leads.
API call:
curl -X POST "https://api.apify.com/v2/acts/harvestapi~linkedin-profile-scraper/runs?token=$APIFY_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"urls": [
{"url": "https://www.linkedin.com/in/PROFILE_1/"},
{"url": "https://www.linkedin.com/in/PROFILE_2/"}
]
}'
Cost: $0.003 per profile. 100 leads = $0.30.
Returns per lead:
Polling for results:
# Check run status
curl "https://api.apify.com/v2/acts/harvestapi~linkedin-profile-scraper/runs/{RUN_ID}?token=$APIFY_API_TOKEN"
# When status is SUCCEEDED, fetch results
curl "https://api.apify.com/v2/datasets/{DATASET_ID}/items?token=$APIFY_API_TOKEN"
Use harvestapi/linkedin-profile-posts to get recent posts. Run this when:
Skip this when:
API call:
curl -X POST "https://api.apify.com/v2/acts/harvestapi~linkedin-profile-posts/runs?token=$APIFY_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"profileUrls": [
"https://www.linkedin.com/in/PROFILE_1/",
"https://www.linkedin.com/in/PROFILE_2/"
]
}'
Cost: $0.002 per post. ~20 posts per profile = ~$0.04 per lead. 50 leads = $2.00.
Returns per post:
Polling: Same pattern as Step 1.
After research completes, present a summary table:
Leads researched: {count}
Profile data: {count} profiles retrieved
Posts scraped: {count} posts from {count} leads (or "skipped")
Research cost: ~${total}
Sample leads:
| Name | Title | Company | Recent Post Topic | Personalization Angle |
|------|-------|---------|-------------------|----------------------|
| Jane Smith | VP Sales | Acme Corp | Posted about AI in sales | Reference her AI post |
| ... | ... | ... | ... | ... |
If the user asked to filter/qualify leads, do that now based on profile data (title, company, industry, etc.) and present which leads made the cut.
Generate personalized messages for each lead based on the research.
Use the best available signal for each lead. In order of strength:
If the user provided reference messages that have worked, analyze those for tone, length, structure, and vocabulary. Use them as the template — don't override with defaults.
After generating any message, count the characters. If over the limit:
Generate a CSV with these columns:
linkedin_url, first_name, last_name, company, title, message_type, message_subject, message_body
For sequence-based campaigns (connection + follow-ups), use:
linkedin_url, first_name, last_name, company, title, connection_request, followup_1, followup_2, followup_3, inmail_subject, inmail_body
Dripify:
Profile URL, Note, Message 1, Message 2, Message 3Expandi:
LinkedIn URL, Connection message, Follow-up #1, Follow-up #2, Follow-up #3, InMail subject, InMail messageBotdog:
linkedin_profile_url, connection_note, message_1, message_2, message_3PhantomBuster:
profileUrl, messageGeneric CSV / Other:
Save to the current working directory:
{campaign-name}-{YYYY-MM-DD}.csv
Present final summary:
Campaign: {name}
Message type: {type}
Leads: {count}
Tool: {dripify/expandi/etc.}
Personalization: {profile-only / profile+posts}
Research cost: ~${amount}
Export file: {file_path}
Show 3-5 sample messages from the export for final review.
Do NOT mark as done without explicit user confirmation. Ask: "Messages look good? Anything to adjust before you import?"
After confirmation:
| Leads | Profile Only | Profile + Posts |
|-------|-------------|----------------|
| 10 | ~$0.03 | ~$0.43 |
| 50 | ~$0.15 | ~$2.15 |
| 100 | ~$0.30 | ~$4.30 |
| 500 | ~$1.50 | ~$21.50 |
Profile scraper: $0.003/profile. Post scraper: ~$0.04/lead (20 posts × $0.002).
| Error | Fix |
|-------|-----|
| APIFY_API_TOKEN not set | Ask user to add it to .env |
| Apify run fails or times out | Retry once. If still fails, skip that lead and note it. |
| LinkedIn URL is invalid or profile not found | Skip the lead, report it to user |
| 0 profiles returned | Check URL format — must be full LinkedIn URL with https:// |
| Post scraper returns 0 posts | Person doesn't post publicly. Use profile data only for personalization. |
Create safety-bounded draft structures and run local deterministic checks for clinical case, diagnostic, trial, safety, and aggregate research reports. Use only with synthetic, de-identified, or aggregate inputs and verified source-fact manifests; every output requires qualified review.
Build evidence-traceable market research reports and assumption-driven market sizing or forecast scenarios. Use for market definition, industry and customer evidence, competitive landscapes, TAM/SAM/SOM reconciliation, forecast sensitivity, and auditable report scaffolds.
Advanced content and topic research skill that analyzes trends across Google Analytics, Google Trends, Substack, Medium, Reddit, LinkedIn, X, blogs, podcasts, and YouTube to generate data-driven article outlines based on user intent analysis
Shopify store command center. Orders, inventory, fulfillment, analytics, and store health. Works with any Shopify store via Admin API.
Production incidents dashboard. Reads ECS health, Sentry errors, CI failures. Offers to dispatch fix agents for active fires.
YOLO mode. Spawns 4 parallel C-suite agents (CEO, CTO, CFO, COO). Each analyzes the business from their perspective using ALL available data. Produces unfiltered Hard Truths report. After user types YOLO, autonomously runs the business for a day using /loop.
Research computing toolkit for optoelectronic information science and engineering, MATLAB/Octave, Python scientific analysis, signal processing, image processing, statistics, simulation, optimization, publication figures, sensor/time-series data, citation lookup, and common scientific libraries. Use when the user asks for MATLAB code, scientific Python, data analysis, plots, simulations, formulas, statistics, machine learning, optical/physical/materials computation, or reproducible research workflows.
> Verify statistics and claims in blog posts by fetching cited source URLs and checking if the claimed data actually appears on the page. Extracts all load-bearing claims (statistics, product or policy claims, ranking and comparative claims, named sources), validates cited URLs before fetching, and scores match confidence (exact match 1.0, paraphrase 0.7-0.9, not found 0.0). Flags uncited claims as UNVERIFIED. Use when user says "fact check", "verify statistics", "check sources", "validate claims", "factcheck", "source verification".
Take gooseworks-ai/linkedin-message-writer from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.