DEV Community

Cover image for I Built a Chrome Extension That Writes LinkedIn DMs Using Claude AI
Sujal Meena
Sujal Meena

Posted on

I Built a Chrome Extension That Writes LinkedIn DMs Using Claude AI

The Problem

Every time I wanted to connect with someone on LinkedIn,
I'd spend way too long staring at a blank message box.

Generic messages like "I'd love to add you to my network"
get ignored 90% of the time.

Personalized messages work — but writing them manually
for every single person is exhausting.

So I automated it.


What I Built

ConnectAI — a Chrome Extension that scrapes any
LinkedIn profile and generates 3 personalized connection
request messages using the Anthropic Claude API.

Live on Chrome Web Store: [YOUR LINK]


How It Works

1. Content Script — LinkedIn Scraper

The content script runs on any linkedin.com/in/* page
and scrapes:

  • Full name
  • Current role / headline
  • Current company
  • Top 3 skills
  • Recent activity snippet
  • Profile URL
function scrapeProfile() {
  const profileData = {};

  profileData.fullName = getMultipleTexts([
    "h1.text-heading-xlarge",
    "h1[class*='heading']",
    "h1"
  ]);

  profileData.currentRole = getMultipleTexts([
    ".text-body-medium.break-words",
    ".pv-top-card .text-body-medium"
  ]);

  // Store in chrome.storage.local
  chrome.storage.local.set({ profileData });
}
Enter fullscreen mode Exit fullscreen mode

The trickiest part? LinkedIn is a React SPA that
constantly changes its class names. I had to use
multiple selector fallbacks for every field.


2. Background Service Worker — Claude API Call

I route all API calls through the background service
worker instead of calling directly from the popup.

Why? CORS. The popup can't make direct API calls
to external URLs in MV3.

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.type === "GENERATE_MESSAGES") {
    handleGenerateMessages(message.payload)
      .then(result => sendResponse({ success: true, data: result }))
      .catch(err => sendResponse({ success: false, error: err.message }));
    return true; // Keep channel open for async
  }
});
Enter fullscreen mode Exit fullscreen mode

3. Claude Prompt Engineering

Getting Claude to return consistent JSON under
300 characters per message took some iteration.

The system prompt enforces strict rules:

  • Never use "I came across your profile"
  • Always reference something specific
  • Sound like a peer, not a fan
  • Strict JSON output format
const systemPrompt = `
You are a LinkedIn outreach specialist.

STRICT RULES:
1. Each message MUST be under 300 characters
2. NEVER use "I came across your profile"
3. Reference something SPECIFIC about the target
4. Sound human — not AI-generated

OUTPUT: strict JSON only, no markdown
`;
Enter fullscreen mode Exit fullscreen mode

4. Popup UI

The popup is 420px wide with a dark theme and shows:

  • Scraped target profile info
  • Your saved sender info (editable inline)
  • 4 purpose pills (networking, referral, etc.)
  • Generate button
  • 3 message cards with character count badges
  • One-click copy

Character count badge logic:

  • 🟢 Green = under 300 chars (LinkedIn limit)
  • 🔴 Red = over 300 chars

Tech Stack

Part Tech
Extension Manifest V3
Language Vanilla JS (no bundler)
AI Anthropic Claude API
Storage Chrome Storage API
Scraping Content Scripts
Styling Pure CSS, dark theme

Biggest Challenges

1. LinkedIn DOM Scraping
LinkedIn changes class names constantly and uses
React under the hood. Had to write multiple selector
fallbacks and re-scrape on SPA navigation using
a MutationObserver.

2. CORS in MV3
Popup can't make external API calls directly.
Solved by routing everything through the background
service worker using chrome.runtime.sendMessage.

3. Consistent JSON from Claude
Claude sometimes wraps JSON in markdown code fences.
Added a cleaning step to strip backticks before
JSON.parse() with a fallback regex extraction.


What's Next

  • [ ] Auto-detect purpose from profile context
  • [ ] Message history per profile
  • [ ] Custom tone settings
  • [ ] Firefox support

Try It

Chrome Web Store: https://chromewebstore.google.com/detail/cjfnhjpheldgcfmipcmibbmlfmpflfij?utm_source=item-share-cb
GitHub: https://github.com/sujalmeena7/Connect-AI

You need a free Anthropic API key to use it.
New accounts get $5 free credits — enough for
~500 message generations.


If you've built Chrome Extensions before, I'd love
to know how you handle LinkedIn's DOM changes.
Drop your approach in the comments 👇

Top comments (0)