Skip to content

Instantly share code, notes, and snippets.

@peplocanto
Last active March 12, 2024 10:01
Show Gist options
  • Save peplocanto/4ec00b1b3160011dcf4922ebd2976c94 to your computer and use it in GitHub Desktop.
Save peplocanto/4ec00b1b3160011dcf4922ebd2976c94 to your computer and use it in GitHub Desktop.
Linkedin bulk contacts removal

Description

A script to remove Linkedin contacts in bulk by searching for a query into the heading of the contact.

Script

const CARD_SELECTOR = 'li.mn-connection-card.artdeco-list';
const TEXT_TO_SEARCH_SELECTOR = '.mn-connection-card__occupation';
const DROPDOWN_TRIGGER_SELECTOR =
  '.artdeco-dropdown__trigger.artdeco-button--tertiary.artdeco-button--muted.artdeco-button--circle';
const REMOVE_CONTACT_OPTION_TEXT_SELECTOR =
  '.mn-connection-card__dropdown-option-text.ml1';
const DELETE_BUTTON_SELECTOR =
  '.artdeco-modal__confirm-dialog-btn.artdeco-button--primary';
const normalizeText = (text) =>
  text
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '')
    .toLocaleLowerCase();

const clickWithDelay = (selector, delay, searchContext = document) =>
  new Promise((resolve) => {
    setTimeout(() => {
      const element = searchContext.querySelector(selector);
      if (element) {
        element.click();
      }
      resolve();
    }, delay);
  });

function findContacts(searchCriteria) {
  const listItems = document.querySelectorAll(CARD_SELECTOR);

  return Array.from(listItems).filter((item) => {
    const occupationSpan = item.querySelector(TEXT_TO_SEARCH_SELECTOR);
    if (!occupationSpan) return false;
    const occupationText = normalizeText(occupationSpan.textContent);
    if (Array.isArray(searchCriteria)) {
      return searchCriteria.some((targetString) =>
        occupationText.includes(normalizeText(targetString))
      );
    } else if (searchCriteria instanceof RegExp) {
      return searchCriteria.test(occupationSpan.textContent);
    } else {
      return occupationText.includes(normalizeText(searchCriteria));
    }
  });
}

function highlightContact(contactElement) {
  contactElement.style.backgroundColor = 'yellow';
}

async function removeContact(contactElement) {
  await clickWithDelay(DROPDOWN_TRIGGER_SELECTOR, 0, contactElement);
  await clickWithDelay(
    REMOVE_CONTACT_OPTION_TEXT_SELECTOR,
    250,
    contactElement
  );
  await clickWithDelay(DELETE_BUTTON_SELECTOR, 250);
  console.log('Removed contact');
}

async function removeContacts(contacts) {
  for (const contact of contacts) {
    await removeContact(contact);
    await new Promise((resolve) => setTimeout(resolve, 500));
  }
  console.log('All contacts removed');
  return true;
}

function search(searchCriteria) {
  if (!searchCriteria) {
    console.log('No query provided');
    return;
  }
  if (CONTACTS && CONTACTS.length > 0) {
    CONTACTS.forEach((contact) => {
      contact.style.backgroundColor = '';
    });
  }
  CONTACTS = findContacts(searchCriteria);
  CONTACTS.forEach((contact) => {
    highlightContact(contact);
  });
  console.log(`Contacts found: ${CONTACTS.length}`);
}

async function remove() {
  if (!CONTACTS || !CONTACTS.length) {
    console.log('No contacts found');
    return;
  }
  await removeContacts(CONTACTS);
}

function reset() {
  if (CONTACTS && CONTACTS.length > 0) {
    CONTACTS.forEach((contact) => {
      contact.style.backgroundColor = '';
    });
  }
  CONTACTS = undefined;
  console.log('Done reset');
}

let CONTACTS;

Usage

  • Scroll down to load your entire contact list
  • CopyPaste the script in your console
  • Run search(query: string | string[] | RegExp)
  • If you are sure you want to remove the highlighted contacts run remove()
  • If you want to reset search and highlight run reset()

Version 1.2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment