LinkedIn Follow-up
by @10madh
Manage LinkedIn outreach leads from Google Sheets — search by name, read live conversation threads, update status, and send contextual follow-up messages. Use after linkedin-dm to move leads through the pipeline (Sent → Replied → Call Scheduled → Demo Done → Closed).
clawhub install linkedin-followup📖 About This Skill
name: linkedin-followup description: Manage LinkedIn outreach leads from Google Sheets — search by name, read live conversation threads, update status, and send contextual follow-up messages. Use after linkedin-dm to move leads through the pipeline (Sent → Replied → Call Scheduled → Demo Done → Closed). metadata: { "openclaw": { "emoji": "🔁", "requires": { "bins": ["gog"] }, "skills": ["gog"], "tags": ["linkedin", "crm", "outreach", "sales", "follow-up"] } }
linkedin-followup
Manage ongoing LinkedIn conversations from a central Google Sheet CRM. Read threads, draft context-aware replies, send messages, and keep the sheet updated — all from one skill.
Pre-flight Checklist
Before doing anything:
1. Sheet ID — Confirm the CRM sheet ID (from linkedin-dm setup). Default: 1eEZDGcr1dIbSC782mNkxvD7pVrF8rOFySWCVZ1RXkhM, tab: Sheet1 (or Outreach if renamed).
2. gog auth — Run gog auth list. If no tokens: see gog auth setup below.
3. Browser — Open the openclaw browser profile and confirm LinkedIn is logged in. Navigate to /feed/ first.
4. Mode — Identify which mode the user wants (see Modes).
Sheet Schema
The CRM sheet uses these columns (A–P):
| Col | Field | Notes | |---|---|---| | A | Date Sent | ISO date | | B | Person Name | Full name | | C | Role / Title | | | D | Company | | | E | LinkedIn URL | Profile URL | | F | Relationship Hook | Hook used in opener | | G | Opener Sent | Message 1 text | | H | Pitch Sent | Message 2 text | | I | Campaign | Batch label | | J | Status | Current pipeline stage | | K | Notes | Context and history | | L | Last Updated | ISO timestamp | | M | Last Reply Date | When they last replied | | N | Last Reply (preview) | First 200 chars of their last reply | | O | Conversation Log | Full thread (see format below) | | P | Next Action | What to do next (agent or human) |
Status values:
Sent → Replied → Call Scheduled → Demo Done → Follow Up Sent → No Response → Closed Won → Closed Lost
Conversation Log format (column O):
[2026-02-13 17:05 SENT] Hey Rishabh, we both had stints at CRED...
[2026-02-13 17:05 SENT] I'm building an AI calling agent...
[2026-02-15 09:30 RECEIVED] Hey! Sounds interesting, tell me more.
[2026-02-15 09:45 SENT] Happy to show you a live demo — are you free Thursday?
If columns M–P don't exist yet, add them first:
gog sheets update "Sheet1!M1:P1" \
--values-json '[["Last Reply Date","Last Reply (preview)","Conversation Log","Next Action"]]' \
--input USER_ENTERED
Modes
Mode 1 — Quick Status Update
User says: *"Mark Rishabh as Replied"* or *"Rishabh got back to me, he's interested"*
1. Find the row — Search the sheet for the person:
gog sheets get "Sheet1!A:P" --json
Match by name (col B) or LinkedIn URL (col E). Get the row number.2. Update status (col J) and last updated (col L):
gog sheets update "Sheet1!J:L" \
--values-json '[["Replied","",""]]' \
--input USER_ENTERED
3. If the user provides reply content, also update: - Col M: Last Reply Date - Col N: Last Reply preview (first 200 chars) - Col O: Append to Conversation Log - Col P: Next Action (what should happen next)
4. Confirm update to user.
Mode 2 — Full Follow-up (Read + Draft + Send)
User says: *"Follow up with Rishabh"* or *"Send a follow-up to everyone who replied"*
#### Step 1 — Load the person's data from sheet
gog sheets get "Sheet1!A:P" --json
Find their row. Load: Name, Company, Role, LinkedIn URL, Opener Sent, Pitch Sent, Status, Notes, Conversation Log, Next Action.#### Step 2 — Navigate to their LinkedIn profile
Always go to feed first (anti-detection):
https://www.linkedin.com/feed/
Wait 2–4 seconds. Then navigate to their profile URL (col E).#### Step 3 — Open message thread and read conversation
Click the Message button on their profile. Wait for the conversation bubble to load.
Scrape the full thread with JavaScript:
const events = Array.from(document.querySelectorAll('.msg-s-message-list__event'));
const messages = [];
events.forEach(el => {
const groups = el.querySelectorAll('.msg-s-event-listitem');
groups.forEach(g => {
const nameEl = g.closest('.msg-s-message-group')?.querySelector('.msg-s-message-group__profile-link');
const bodyEl = g.querySelector('.msg-s-event-listitem__body');
const timeEl = g.closest('.msg-s-message-group')?.querySelector('.msg-s-message-group__timestamp');
if (bodyEl?.textContent?.trim()) {
messages.push({
sender: nameEl?.textContent?.trim() || 'unknown',
time: timeEl?.textContent?.trim() || '',
text: bodyEl.textContent.trim()
});
}
});
});
return JSON.stringify(messages);
If the thread is empty or not loading, scroll up in the conversation bubble to load older messages.
#### Step 4 — Analyse the conversation
With the full thread loaded + their profile data, determine:
#### Step 5 — Draft the follow-up
Write a response that:
Show the draft to the user and ask for approval before sending:
> Draft reply to [Name]: > [message] > > Send this? (y / edit / skip)
#### Step 6 — Send the message
Same JS evaluate method as linkedin-dm:
const active = document.querySelector('.msg-overlay-conversation-bubble--is-active .msg-form__contenteditable');
if (active) { active.focus(); document.execCommand('insertText', false, ''); }
Then find and click Send.#### Step 7 — Update the sheet
After sending:
gog sheets update "Sheet1!J:P" \
--values-json '[["","","","","",""]]' \
--input USER_ENTERED
Mode 3 — Batch Review
User says: *"Who needs a follow-up?"* or *"Check my outreach"*
1. Load all rows from the sheet.
2. Filter by status and time:
- Sent older than 3 days → candidate for "No Response" or gentle follow-up
- Replied → needs a response
- Follow Up Sent older than 5 days → consider "No Response"
- Call Scheduled → check if call happened, update status
3. Present a table of candidates:
Name Status Last Updated Suggested Action
Rishabh Nayan Replied 2026-02-14 Reply to their message
Shorya Saini Sent 2026-02-10 Follow-up nudge (4 days)
Shantam Mohata Sent 2026-02-13 Too soon (today)
4. User picks who to action, then enter Mode 2 for each.Response Playbook
Use these as a guide — always adapt to the actual conversation:
| They said | Intent | Your move | |---|---|---| | "Sounds interesting, tell me more" | Curious | Short explanation + offer a specific demo slot | | "How does it work?" | Exploring | 2-line description + invite to a 15-min call | | "We already use [X]" | Objection | Acknowledge, explain differentiation, offer demo | | "Send me more details" | Soft interest | Share a Loom/deck/link + follow up in 2 days | | "Not relevant right now" | Soft no | Respect it, leave door open: "No worries, I'll ping you in a few months" | | "Who else is using it?" | Trust-building | Share a relevant use case, offer intro to a user | | [No reply in 4 days] | Silence | Light nudge: "Hey [Name], just checking — any thoughts?" | | [No reply in 8 days] | Cold | One final message, then mark No Response |
Anti-Detection Rules
Same rules as linkedin-dm:
/feed/ before navigating to a profilegog Auth Setup
If gog auth list returns empty, the user needs to set up Google OAuth credentials:
1. Go to console.cloud.google.com
2. Create a project (or select existing)
3. Enable Google Sheets API (APIs & Services → Library)
4. Create OAuth credentials: APIs & Services → Credentials → Create → OAuth client ID → Desktop App
5. Download client_secret_
6. Run:
gog auth credentials set /path/to/client_secret.json
gog auth add your@gmail.com --services sheets
7. A browser window will open — log in and grant access
8. Verify: gog auth listFallback (no gog): All sheet reads/writes can be done manually via browser — open the sheet in the openclaw browser and update cells directly. Less automated but functional.
Session Limits
linkedin_followup_log.json and sync to sheet next session