Multi-platform influencer engagement manager for Instagram, Threads, LinkedIn, and X (Twitter). Bulk outreach, keyword scan, DM templates, connection/follow + DM logic, tweet reply fallback, waitlist, dashboard analytics, CSV import/export. No AI, no API keys, 100% local browser automation.
Root cause: X changed their DM compose UI from a contenteditable div (data-testid="dmComposerTextInput") to a native <textarea> (data-testid="dm-composer-textarea" with placeholder="Message"). The old send button (data-testid="dmComposerSendButton") was also removed in favor of Enter key submission.
Fix: Rewrote handleTypeAndSendDM in x-content.js with:
- Textarea-first selectors (5 modern + 6 legacy fallbacks)
- Native value setter for React-controlled textarea (same technique as LinkedIn fix)
- Enter key submission when no explicit Send button exists
- Legacy contenteditable support preserved as fallback
- Visibility check (
offsetParent !== null) to skip hidden elements
Problem: When searching for a recipient on the compose page, if multiple people share the same name (e.g., "John Smith"), the extension would blindly click the first suggestion — potentially messaging the wrong person.
Fix: The extension now extracts the headline from the target's profile page (e.g., "Founder & CEO at BackScoop") and uses it to match against the suggestion dropdown. Each suggestion item contains a <dt> (name) and <dd> (headline) element, enabling precise disambiguation.
Matching priority:
- Exact headline match (strongest signal)
- Partial headline overlap (3+ shared keywords)
- First result with matching full name
- First result with matching first name
- First result overall (last resort)
Also improved: Name extraction reliability
handleGetProfileInfonow retries 15 times (7.5s) with 5 CSS selectors for the name element- Falls back to page title ("Amanda Cua | LinkedIn") then URL slug ("amanda-cua" → "Amanda Cua")
getLinkedInDisplayNamehelper retries 3 times with content script re-injection between attempts- All 5 LinkedIn DM paths updated to pass headline for disambiguation
Completely rearchitected the LinkedIn DM flow. Instead of clicking the "Message" button on a profile page and trying to type into the dynamically-rendered overlay popup (which consistently failed because LinkedIn's Ember.js renders the textarea after page load), the extension now:
- Reads the display name from the profile page
- Navigates to
linkedin.com/messaging/thread/new/(the compose page) - Searches for the recipient by name in the compose search field
- Selects the matching contact from the dropdown suggestions
- Types and sends the message in the textarea (verified to exist on this page)
This approach is used across all LinkedIn DM paths: Send DMs loop, Bulk Outreach, connect-then-DM, waitlist recheck, and cadence follow-ups.
Other fixes:
- Added reusable
linkedinComposeDM()helper function to eliminate code duplication - Changed LinkedIn DM check from
clickMessageButton(which opens the overlay) tocheckProfileActions(which only checks without clicking) - Fixed
sendToTabretry to detect platform from tab URL instead of defaulting to Instagram - UI fix: Moved outreach progress card below the "Start Outreach" button (was pinned at top of panel)
Comprehensive UX redesign focused on making the extension approachable for first-time users while keeping all advanced features accessible for power users.
Onboarding:
- Welcome card with 3-step visual guide (Create template → Add handles → Start sending) — shown only for new users, dismissible
- Starter template suggestion when no templates exist — one-click "Use This Template" to get started instantly
- Nudge card after first template creation — guides user to the Outreach tab
Clearer Labels:
- "Bulk Outreach" → "Send DMs" (mode tab)
- "Keyword Scan" → "Comment Scanner" (mode tab)
- "Reply Directions" → "Message Templates" (card header)
- "Parse & Assign" → "Review Handles" (button)
Progressive Disclosure:
- Collapsible Advanced Settings — Behavior Settings and Cadence are now hidden by default behind an "Advanced Settings" toggle
- Info tooltips on Delay and Full Automation controls explaining what they do
- "No template" hint in Outreach tab with direct link to Templates tab
Visual Improvements:
- Inline flow steps in Outreach tab (1. Paste handles → 2. Choose template → 3. Start) with active/completed states
- Rich empty states with icons and descriptions for Templates, History, Waitlist, and Dashboard
- Dashboard empty state shows guidance instead of zero-filled charts
- Card subtitles for section context
- Smooth animations on welcome card and nudge
The primary bug causing LinkedIn DMs to fail has been fixed. The root cause: LinkedIn's messaging overlay (and full messaging page) uses a <textarea role="textbox"> inside <form id="msg-form-ember*">, rendered dynamically by Ember.js after the overlay animation completes. The previous code prioritized contenteditable div selectors that no longer exist in LinkedIn's current DOM.
Changes:
- Textarea-first selector strategy — 9 textarea selectors now run before 11 contenteditable fallbacks
- Progressive retry with 4 phases — targeted selectors → contenteditable fallback → broad textarea scan → broad contenteditable scan
- 40 retry attempts (up from 30) with 500ms intervals = 20s total wait for overlay rendering
- Double-check textarea value — if native setter doesn't stick, falls back to
execCommand - Smarter Send button detection — looks inside the same
<form>first, then by proximity to input - Enhanced debug output — reports textarea count, form count, and overlay count on failure
- Fixed
sendToTabretry injection — retries now detect platform from tab URL instead of defaulting to Instagram
All LinkedIn and X content scripts have been rewritten with verified DOM selectors from real logged-in sessions. 8 bugs fixed, 6 edge cases handled, 10 improvements implemented.
- LinkedIn Connect button is an
<a>tag, not<button>— fixed selector to usearia-label="Invite X to connect" - LinkedIn "Following" false match — Follow button now uses exact text match to avoid accidentally unfollowing
- React contenteditable input — Both LinkedIn and X now use
execCommand('insertText')+ InputEvent dispatch for proper React state sync - X reply fallback navigates to tweet — Reply input only exists on tweet pages, not profiles. Now finds latest tweet URL and navigates there first
- LinkedIn keyword scan uses Connect+Note — Previously fell back to Follow (useless on LinkedIn), now sends connection request with personalized note
- Waitlist re-check is multi-platform — Previously hardcoded to Instagram, now routes to correct platform per user
- Cadence follow-ups are multi-platform — Stores and uses platform field for each cadence item
- "X: Reply to tweet when DMs closed" toggle — disable to skip users with closed DMs instead of replying
- "LinkedIn: Send connection note as message" toggle — uses DM template as connection note (max 300 chars)
- Platform-specific delay hints — LinkedIn recommends 90-120s, X recommends 60-90s
- Auto-adjusted default delay — LinkedIn defaults to 90s, others to 60s
- LinkedIn "More" dropdown for Connect button (hidden behind overflow menu)
- LinkedIn connection note 300-char truncation with warning
- X protected accounts detected before follow attempt
- X rate limit detection (429 responses)
- Graceful handling when no tweets found for reply fallback
- LinkedIn messaging page textarea vs contenteditable detection
The extension now supports 4 platforms from a single interface:
| Platform | Outreach Flow | Keyword Scan | DM Method |
|---|---|---|---|
| Follow + DM | Post comments | Direct Message | |
| Threads | Follow (DM via IG) | Post comments | Redirects to Instagram DM |
| Connect + Message (or connection note) | Post comments | LinkedIn Message overlay | |
| X (Twitter) | Follow + DM (or tweet reply fallback) | Tweet replies | DM or public reply |
- Connect + Message: Sends connection request with personalized note as the DM
- 1st-degree detection: If already connected, sends DM directly via Message button
- Pending state handling: Detects "Pending" connections and waitlists them
- Profile restriction detection: Identifies restricted/unavailable profiles
- Follow + DM: Follows user, then sends DM if their DMs are open
- Tweet Reply Fallback: If DMs are closed, automatically replies to their tweet instead
- DM availability check: Detects whether user accepts DMs before attempting
- Protected account detection: Identifies locked/protected accounts and skips them
- Keyword scan on tweet replies: Scans replies to any tweet for keyword matches
- 4-platform selector with branded colors (IG gradient, Threads black, LinkedIn blue, X black)
- Platform-specific labels and placeholders for all input fields
- Header gradient changes per platform
The automation never pauses on its own anymore. Previously, consecutive DM failures would trigger an auto-pause that required manual intervention to resume. Now the behavior is:
| Event | Old Behavior (v8) | New Behavior (v9) |
|---|---|---|
| DM send fails | Count as health failure → auto-pause after 3 | Skip user, add to waitlist, continue |
| Private profile | Skip or waitlist (fixed in v8) | Same — no impact on flow |
| Follow error | Skip (fixed in v8) | Same — no impact on flow |
| Unverified send | Logged as warning | Same — no impact on flow |
On any failure, the extension now:
- Logs the error in the progress feed
- Adds the user to the waitlist with status "Error" for later retry via Re-check
- Saves to history as an error
- Waits the normal configured delay
- Continues to the next user automatically
You can still manually pause at any time, but the extension will never stop on its own.
Removed the adaptive delay system that would slow down the extension on errors. The delay between users is now always exactly what you configure — no hidden additions.
When outreach completes, the summary now shows a clear breakdown:
"All done! 45 DMs sent. 3 waitlisted. 2 failed (added to waitlist for retry). 5 skipped."
Users that fail for any reason (message input not found, send button error, page load timeout, etc.) are automatically added to the waitlist. You can retry them later using the Re-check button on the Waitlist tab, which will revisit their profiles and attempt to send the DM again.
New "Skip private profiles entirely" behavior setting that detects private accounts before sending a follow request and skips them completely — no follow, no waitlist, just moves to the next user.
How it works:
- After navigating to a profile, the extension checks for private account indicators:
- "This account is private" text on the page
- No posts visible + Follow button present
- Private account headings or lock icons
- If private is detected and the toggle is enabled, the user is skipped instantly
- No follow request is sent, keeping your account's follow activity clean
Toggle location: Behavior Settings → "Skip private profiles entirely" (unchecked by default)
Multi-level deduplication system prevents the same user from receiving the same message twice:
| Layer | What it prevents |
|---|---|
| Pre-send history check | Re-running outreach with same handles won't re-send |
| Retry loop guard | If input was cleared (message sent), never retry |
| Cadence step check | Same follow-up step can't fire twice |
| Cross-queue dedup | Users in both waitlist and cadence won't get double messages |
Skipped users show as "skipped-dup" in the progress log.
Private profiles no longer trigger auto-pause. Previously, encountering 2 private profiles in a row would pause the entire automation. Now:
- Profile/follow errors are not counted as health failures
- Only actual DM delivery failures affect session health
- "Already Requested" profiles are detected early and handled gracefully
clickFollowButtonerrors are caught inline (waitlist + continue) instead of throwing- Health thresholds relaxed: consecutive fail max 2→3, rolling window 3/5→4/5
A new Dashboard sub-tab is now the default view when opening Bulk Outreach. It provides at-a-glance performance metrics without leaving the side panel:
| Metric | Description |
|---|---|
| DMs Today | Number of successful DMs sent in the last 24 hours |
| DMs This Week | Total DMs sent in the last 7 days |
| Success Rate | Percentage of successful sends vs total attempts (7-day window) |
| Waitlisted | Current number of users pending follow-back |
Visual Charts:
- 7-Day Activity Bar Chart — Shows DMs sent per day with gradient-filled bars
- Outcome Breakdown — Horizontal bars comparing messaged / followed / waitlisted / errors for the week
- Session Health Display — Real-time health bar showing success rate with Healthy / Fair / Degraded status indicators
The dashboard auto-refreshes whenever outreach progress or history updates are received.
Import CSV — Click the Import CSV button on the Outreach sub-tab to load handles from a .csv or .txt file. The parser automatically detects columns named handle, username, or user, and handles quoted fields, various delimiters, and plain lists.
Export CSV — Export your current handles list to a downloadable CSV file with a single click.
Export History — On the History sub-tab, export your full outreach history as a CSV with columns: username, platform, status, viewed, followed, messaged, templateName, timestamp, message, cadenceStep.
Significant improvements to DM delivery success rate:
- Post-send bubble verification — After sending each DM, the extension counts message bubbles before and after to confirm delivery actually occurred. If verification fails, it retries automatically.
- Session health monitoring — Tracks a rolling window of the last 5 send attempts. Auto-pauses outreach on 2 consecutive failures or 3 out of 5 failures to protect your account.
- Adaptive delay — Automatically increases delay by 10s per failure and decreases by 5s per success, dynamically adjusting to Instagram's rate limits.
- Default delay set to 60s — With a visible warning if you set it below 60s to reduce risk of action blocks.
- Configurable behavior settings — Always follow before DM, DM after follow for public accounts, waitlist private accounts (all toggleable).
DM templates now fully preserve line breaks. The extension uses Shift+Enter simulation to insert line breaks in Instagram's contenteditable input, so multi-paragraph messages render exactly as written in your template.
- Dashboard is now the default active sub-tab in Bulk Outreach (before Outreach, History, Waitlist, Templates)
- Sub-tab order: Dashboard → Outreach → History → Waitlist → Templates
- Pause takes effect immediately after current task completes (not after full delay)
- Back to Config button appears when paused for easy reconfiguration
Toggle between Instagram and Threads with a single click in the side panel header. The extension adapts labels, URL validation, and DOM interaction for each platform.
| Platform | Keyword Scan | Bulk Outreach (Follow) | DMs |
|---|---|---|---|
| Scan post comments | Follow on Instagram | DM via Instagram | |
| Threads | Scan thread replies | Follow on Threads | DM via Instagram (Threads web has no DM) |
Note: Threads does not support web-based DMs. When operating on Threads, the extension automatically redirects to the user's Instagram profile to send DMs.
Provide a list of handles and let the extension connect and message each one.
Smart Three-Case Logic:
| Case | Condition | Action |
|---|---|---|
| Direct DM | Message button visible | Send DM immediately |
| Follow + DM | Follow accepted instantly (public account) | Follow, then DM immediately |
| Follow + Waitlist | Follow requires approval (private account) | Follow, then add to waitlist |
Sub-tabs:
- Dashboard — At-a-glance stats, 7-day chart, outcome breakdown, session health (v7)
- Outreach — Paste handles (or import CSV), assign templates, configure delay, start outreach
- History — All past interactions with three-light status indicators, filters, and CSV export
- Waitlist — Users pending follow-back approval, with re-check functionality
- Templates — Create, edit, and delete reusable DM templates (Reply Directions)
Additional Features:
- Full Automation toggle — Skip review, go straight from parsing to sending
- Auto-cadence follow-ups — Schedule follow-up messages at 6h, 12h, and/or 24h
- Three-light status per account: Viewed (blue), Followed (orange), Messaged (green)
- Pause/Resume with immediate effect (finishes current user, then pauses)
- Back to Config button when paused
Scan an Instagram post or Threads thread for comments containing specific keywords, then DM the matching commenters.
Step-by-step flow:
- Configure — Enter post URL, keyword(s), DM template, delay
- Scan — Extension scrolls the comment area, expands replies, extracts all comments
- Review — See matched users, select/deselect who to message
- Send — Automatically navigates to each profile and sends personalized DMs
Features:
- Case-insensitive keyword matching with word-boundary detection
{{username}}personalization in DM templates- Full Automation toggle to skip the review step
- Duplicate prevention via DM history tracking
Pre-configure multiple DM templates for different outreach scenarios:
- Collaboration Invite — "Hi {{username}}, we'd love to collaborate with you..."
- Product Gifting — "Hey {{username}}, we'd like to send you our latest..."
- Event Invite — "Hi {{username}}, you're invited to our exclusive..."
Each template supports {{username}} personalization and can be assigned per-handle during bulk outreach. Templates can be created, edited, and deleted at any time.
When a user's profile requires follow approval before messaging:
- Extension sends a follow request
- User is added to the Waitlist with their assigned template
- Periodically click Re-check — the extension revisits each profile
- If they followed back (Message button now visible), sends the DM automatically
- If still pending, keeps them on the waitlist
After an initial DM is sent, schedule automatic follow-up messages:
| Interval | When it sends |
|---|---|
| 6 hours | 6h after initial DM |
| 12 hours | 12h after initial DM |
| 24 hours | 24h after initial DM |
- Select which intervals to enable per campaign
- Choose a specific follow-up template
- Background worker checks every 2 minutes for due follow-ups
- View scheduled follow-ups in the History tab
- Download or clone this repository
- Open
chrome://extensions/in Chrome - Enable Developer mode (top-right toggle)
- Click Load unpacked and select the
influencer-dm-extensionfolder - Click the extension icon to open the side panel
- Make sure you're logged into Instagram (and Threads if using Threads mode) in the same Chrome profile
An influencer posts content saying "Comment PHOTO to get the free preset pack."
- Select Keyword Scan mode
- Paste the post URL, set keyword to
photo - Write a DM template: "Hi {{username}}! Here's your free preset pack: [link]"
- Scan, review, and send DMs to all matching commenters
You have a list of 100 micro-influencers to pitch for a brand collaboration.
- Select Bulk Outreach mode
- Create templates: "Collaboration Invite", "Product Gifting"
- Paste all 100 handles, assign the right template per handle
- Enable auto-cadence (24h follow-up)
- Start outreach — the extension handles follow/DM logic per account
A brand posts the same campaign on both Instagram and Threads.
- Start with Threads platform selected
- Use Keyword Scan on the Threads post to find engaged users
- Extension scans Threads replies, then redirects to Instagram for DMs
- Switch to Instagram and repeat for the Instagram post
- History shows all interactions across both platforms
Inviting influencers to an exclusive event with reminder cadence.
- Create templates: "Event Invite" (initial) and "Event Reminder" (follow-up)
- Paste handles, assign "Event Invite" as default
- Enable 24h cadence with "Event Reminder" as follow-up template
- Start outreach — initial invites go out immediately
- 24 hours later, follow-up reminders are sent automatically
| Setting | Conservative | Moderate | Aggressive |
|---|---|---|---|
| Delay between DMs | 90s | 45s | 20s |
| DMs per session | 10–15 | 20–30 | 50+ |
| DMs per day | 30–40 | 50–70 | 80+ |
| Template variations | 3–5 | 2–3 | 1 |
Recommendations:
- Start with conservative settings and gradually increase
- Warm up new accounts over 1–2 weeks before scaling
- Run during normal business hours
- Stop immediately if you see "Action Blocked" warnings
- Maintain regular organic activity on your account
- Manifest V3 Chrome Extension with Side Panel API
- No AI, no API keys, no external servers — everything runs locally in your browser
- Architecture: Background service worker orchestrates navigation, re-injects content scripts per page, content scripts perform atomic DOM actions
- Storage:
chrome.storage.localfor templates, history, waitlist, cadence queue - Platforms: Instagram (
content.js) and Threads (threads-content.js) with platform-specific DOM selectors - DMs: Always sent through Instagram (Threads web DMs not yet available)