Created
November 13, 2025 17:40
-
-
Save benjaminjackson/21fc2c1a135dca617ef1282285418c0e to your computer and use it in GitHub Desktop.
Unfollow Everyone on LinkedIn (No Confirmation, Nukes Everyone)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // LinkedIn Auto-Unfollow Script | |
| // Automatically unfollows everyone without confirmation | |
| // WARNING: This will unfollow people automatically without asking for confirmation | |
| (() => { | |
| let count = 0; | |
| const processedPeople = new Set(); // Track who we've already unfollowed | |
| function getAllFollowingButtons() { | |
| return Array.from(document.querySelectorAll('button.artdeco-button--muted.artdeco-button--secondary')) | |
| .filter(btn => { | |
| const buttonText = btn.querySelector('.artdeco-button__text')?.innerText; | |
| const ariaLabel = btn.getAttribute('aria-label'); | |
| // Only include buttons we haven't processed yet | |
| return buttonText === "Following" && !processedPeople.has(ariaLabel); | |
| }); | |
| } | |
| function waitForModal() { | |
| return new Promise((resolve) => { | |
| const checkInterval = setInterval(() => { | |
| const modal = document.querySelector('.artdeco-modal'); | |
| if (modal) { | |
| clearInterval(checkInterval); | |
| resolve(modal); | |
| } | |
| }, 100); | |
| }); | |
| } | |
| function waitForModalToClose() { | |
| return new Promise((resolve) => { | |
| const checkInterval = setInterval(() => { | |
| const modal = document.querySelector('.artdeco-modal'); | |
| if (!modal) { | |
| clearInterval(checkInterval); | |
| resolve(); | |
| } | |
| }, 500); | |
| }); | |
| } | |
| async function unfollowNext() { | |
| const buttons = getAllFollowingButtons(); | |
| console.log(`Found ${buttons.length} unprocessed "Following" buttons`); | |
| if (buttons.length === 0) { | |
| // Try multiple times to load more content | |
| let loadAttempts = 0; | |
| const maxAttempts = 3; | |
| while (loadAttempts < maxAttempts) { | |
| loadAttempts++; | |
| console.log(`Load attempt ${loadAttempts}/${maxAttempts}...`); | |
| // Click "Show more results" button if it exists | |
| const showMoreButton = document.querySelector('.scaffold-finite-scroll__load-button'); | |
| if (showMoreButton && !showMoreButton.disabled) { | |
| console.log("Clicking 'Show more results' button..."); | |
| showMoreButton.click(); | |
| await new Promise((resolve) => setTimeout(resolve, 5000)); | |
| } else { | |
| // Otherwise try scrolling | |
| console.log("Scrolling to bottom..."); | |
| window.scrollTo(0, document.body.scrollHeight); | |
| await new Promise((resolve) => setTimeout(resolve, 5000)); | |
| } | |
| // Check for new buttons | |
| const newButtons = getAllFollowingButtons(); | |
| console.log(`After attempt ${loadAttempts}: found ${newButtons.length} new buttons`); | |
| if (newButtons.length > 0) { | |
| console.log("Found new buttons, continuing..."); | |
| return unfollowNext(); | |
| } | |
| if (loadAttempts < maxAttempts) { | |
| console.log("No new buttons yet, waiting before next attempt..."); | |
| await new Promise((resolve) => setTimeout(resolve, 2000)); | |
| } | |
| } | |
| // After all attempts, we're done | |
| console.log("Could not find more content after multiple attempts - reached the end"); | |
| console.log(`All done! Unfollowed ${count} people total.`); | |
| console.log(`Successfully unfollowed: ${processedPeople.size}`); | |
| return; | |
| } | |
| // Get the first unprocessed button | |
| const button = buttons[0]; | |
| const ariaLabel = button.getAttribute("aria-label"); | |
| // Extract person's name from aria-label (format: "Click to stop following [Name]") | |
| const personName = ariaLabel.replace('Click to stop following ', ''); | |
| count++; | |
| console.log(`${count}. Unfollowing: ${personName}`); | |
| // Scroll button into view | |
| button.scrollIntoView({ behavior: 'smooth', block: 'center' }); | |
| await new Promise((resolve) => setTimeout(resolve, 300)); | |
| // Click to open modal | |
| button.click(); | |
| // Wait for modal to appear | |
| await waitForModal(); | |
| await new Promise((resolve) => setTimeout(resolve, 300)); | |
| // Find and click the "Unfollow" button in the modal | |
| // It's the primary button with text "Unfollow" | |
| const unfollowButton = Array.from(document.querySelectorAll('.artdeco-modal button')) | |
| .find(btn => btn.innerText.trim() === 'Unfollow'); | |
| if (unfollowButton) { | |
| unfollowButton.click(); | |
| } else { | |
| console.log(`⚠️ Could not find Unfollow button in modal for ${personName}`); | |
| } | |
| // Wait for modal to close | |
| await waitForModalToClose(); | |
| // Delay to let the button update (LinkedIn needs time to re-render) | |
| await new Promise((resolve) => setTimeout(resolve, 1000)); | |
| // Re-query for buttons with this person's name to verify unfollow | |
| const updatedButton = Array.from(document.querySelectorAll('button.artdeco-button--secondary')) | |
| .find(btn => { | |
| const label = btn.getAttribute('aria-label'); | |
| return label && ( | |
| label === ariaLabel || // Still has old label (failed?) | |
| label === `Click to follow ${personName}` // Changed to new label (success) | |
| ); | |
| }); | |
| if (!updatedButton || updatedButton.querySelector('.artdeco-button__text')?.innerText === "Follow") { | |
| // Successfully unfollowed | |
| processedPeople.add(ariaLabel); | |
| console.log(`✓ Unfollowed ${personName}`); | |
| } else { | |
| // Something went wrong, mark as processed to avoid infinite loop | |
| processedPeople.add(ariaLabel); | |
| console.log(`⚠️ Could not verify unfollow for ${personName}`); | |
| } | |
| // Small delay before next person | |
| await new Promise((resolve) => setTimeout(resolve, 500)); | |
| // Continue to next | |
| unfollowNext(); | |
| } | |
| console.log("⚠️ Starting AUTOMATIC unfollow - will unfollow everyone without confirmation!"); | |
| unfollowNext(); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment