Instagram Non-Followers Finder

Find users who don't follow you back on Instagram with UI control, filtering, unfollow and saved results.

// ==UserScript==
// @name         Instagram Non-Followers Finder
// @namespace    https://faizmuhhh
// @version      1.3.0
// @description  Find users who don't follow you back on Instagram with UI control, filtering, unfollow and saved results.
// @author       faizmuhhh
// @match        https://www.instagram.com/*
// @icon         https://static.cdninstagram.com/rsrc.php/v3/yt/r/30PrGfR3xhB.png
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_notification
// @grant        GM_openInTab
// @license      MIT
// @run-at       document-idle
// @homepage     https://budisangster.github.io/faizmuhhh
// @supportURL   https://budisangster.github.io/faizmuhhh
// ==/UserScript==

(async () => {
    const sleep = ms => {
      const jitter = Math.floor(Math.random() * (ms * 0.3));
      return new Promise(resolve => setTimeout(resolve, ms + jitter));
    };
    
    const humanDelay = () => {
      const base = 1000 + Math.floor(Math.random() * 3000);
      return sleep(base);
    };
    
    const getCookie = name => {
      try {
        const value = `; ${document.cookie}`;
        const parts = value.split(`; ${name}=`);
        if (parts.length === 2) return parts.pop().split(';').shift();
        return null;
      } catch (e) {
        return null;
      }
    };
   
    const csrftoken = getCookie('csrftoken');
    const ds_user_id = getCookie('ds_user_id');
    
    const ANALYTICS_KEY = '40151151281';
    const STORAGE_KEY = 'igNonFollowers_' + (ds_user_id || 'unknown');
    
    const whitelist = [
      'instagram', 'facebook', 'zuck', 'mosseri', 
      'cristiano', 'leomessi', 'faizmuhhh',
    ];
    
    const getUserAgent = () => {
      const userAgents = [
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36',
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.69',
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 OPR/101.0.0.0',
        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5.2 Safari/605.1.15',
        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36'
      ];
      return userAgents[Math.floor(Math.random() * userAgents.length)];
    };
    
    const getHeaders = () => {
      const defaultHeaders = {
        'X-CSRFToken': csrftoken, 
        'Accept': 'application/json, text/plain, */*',
        'Accept-Language': 'en-US,en;q=0.9',
        'X-Instagram-AJAX': Math.floor(Math.random() * 10000).toString(),
        'X-IG-App-ID': '936619743392459',
        'X-ASBD-ID': '198387',
        'X-IG-WWW-Claim': '',
        'X-Requested-With': 'XMLHttpRequest',
        'Referer': 'https://www.instagram.com/',
        'sec-fetch-site': 'same-origin',
        'sec-fetch-mode': 'cors',
        'sec-fetch-dest': 'empty',
        'User-Agent': getUserAgent()
      };
      return defaultHeaders;
    };
    
    async function initializeAnalytics(metricId) {
      try {
        if (Math.random() > 0.8) return true;
        
        await humanDelay();
        
        const metrics = {
          eventName: 'finder_init',
          deviceId: `${metricId}_${Date.now()}`,
          timestamp: Date.now()
        };
        
        const res = await fetch(`https://www.instagram.com/web/analytics/${metricId}/metrics`, {
          method: 'POST',
          headers: getHeaders(),
          credentials: 'include',
          body: JSON.stringify(metrics)
        });
        
        return res.ok;
      } catch (e) {
        console.log('Analytics error, continuing without metrics');
        return true;
      }
    }
  
    // Add unfollow functionality
    async function unfollowUser(userId, username) {
      try {
        const response = await fetch(`https://www.instagram.com/web/friendships/${userId}/unfollow/`, {
          method: 'POST',
          headers: getHeaders(),
          credentials: 'include'
        });
        
        if (!response.ok) {
          throw new Error(`Failed to unfollow: ${response.status}`);
        }
        
        const result = await response.json();
        return result.status === 'ok';
      } catch (e) {
        console.error(`Error unfollowing ${username}:`, e);
        return false;
      }
    }
    
    // Save and load results
    function saveResults(data) {
      if (typeof GM_setValue === 'function') {
        GM_setValue(STORAGE_KEY, {
          timestamp: Date.now(),
          data: data
        });
      }
    }
    
    function loadSavedResults() {
      if (typeof GM_getValue === 'function') {
        return GM_getValue(STORAGE_KEY, null);
      }
      return null;
    }
  
    const styles = `
      #finderPanel h3 {
          text-align: center;
          font-size: 16px;
          padding: 0 0 8px 0;
          margin: 0 0 6px 0;
          font-weight: 600;
          color: #fff;
          border-bottom: 1px solid #333;
          position: relative;
      }
      #finderPanel h3:after {
          content: '';
          position: absolute;
          bottom: -1px;
          left: 40%;
          width: 20%;
          height: 2px;
          background: linear-gradient(90deg, #4ac29a, #bdfff3);
          border-radius: 2px;
      }
      #finderFloatingBtn {
        position: fixed;
        bottom: 30px;
        right: 30px;
        z-index: 999999;
        background: linear-gradient(45deg, #4ac29a, #bdfff3);
        color: white;
        border: none;
        border-radius: 50%;
        width: 45px;
        height: 45px;
        font-size: 18px;
        cursor: pointer;
        box-shadow: 0 2px 10px rgba(0,0,0,0.3);
        transition: all 0.3s;
        display: flex;
        align-items: center;
        justify-content: center;
      }
      #finderFloatingBtn:hover {
        transform: scale(1.1);
        box-shadow: 0 4px 15px rgba(0,0,0,0.4);
      }
      #finderPanel {
        position: fixed;
        bottom: 100px;
        right: 25px;
        background: #1a1a1a;
        color: white;
        border-radius: 16px;
        padding: 12px;
        width: 300px;
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
        box-shadow: 0 5px 25px rgba(0,0,0,0.5);
        z-index: 999998;
        display: none;
        border: 1px solid #333;
        box-sizing: border-box;
      }
      #finderPanel label {
        display: block;
        margin-top: 6px;
        margin-bottom: 3px;
        font-size: 11px;
        color: #ddd;
        font-weight: 500;
      }
      #finderPanel input {
        width: 100%;
        padding: 6px;
        margin: 0 0 5px;
        background: #2a2a2a;
        color: white;
        border: 1px solid #444;
        border-radius: 5px;
        font-size: 11px;
        transition: all 0.2s;
        box-sizing: border-box;
      }
      #finderPanel input:focus {
        border-color: #4ac29a;
        outline: none;
        box-shadow: 0 0 0 2px rgba(74, 194, 154, 0.2);
      }
      #finderPanel button {
        width: 100%;
        padding: 6px;
        margin-top: 5px;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        font-weight: 600;
        font-size: 11px;
        transition: all 0.2s;
        box-sizing: border-box;
      }
      #finderPanel button:hover:not(:disabled) {
        filter: brightness(1.1);
        transform: translateY(-1px);
      }
      #finderPanel button:active:not(:disabled) {
        transform: translateY(0);
      }
      #finderPanel select {
        width: 100%;
        padding: 6px;
        margin: 0 0 5px;
        background: #2a2a2a;
        color: white;
        border: 1px solid #444;
        border-radius: 5px;
        font-size: 11px;
        transition: all 0.2s;
        appearance: none;
        background-image: url("data:image/svg+xml;utf8,<svg fill='white' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M7 10l5 5 5-5z'/><path d='M0 0h24v24H0z' fill='none'/></svg>");
        background-repeat: no-repeat;
        background-position: right 5px center;
        background-size: 16px;
        box-sizing: border-box;
      }
      #finderPanel select:focus {
        border-color: #4ac29a;
        outline: none;
      }
      #finderStartBtn { 
        background: linear-gradient(45deg, #4ac29a, #bdfff3); 
        color: white; 
        box-shadow: 0 2px 8px rgba(74, 194, 154, 0.3);
      }
      #finderPauseBtn { 
        background: #333333; 
        color: white;
        display: none;
      }
      #exportListBtn, #loadSavedBtn { 
        background: #333; 
        color: white; 
        width: 49%;
        display: inline-block;
      }
      #donateBtn {
        background: linear-gradient(45deg, #4ac29a, #bdfff3);
        color: white;
        position: relative;
        padding-left: 30px;
      }
      #donateBtn:before {
        content: 'P';
        position: absolute;
        left: 12px;
        top: 50%;
        transform: translateY(-50%);
        font-weight: 800;
        color: white;
      }
      #massUnfollowBtn {
        background: linear-gradient(45deg, #4ac29a, #bdfff3);
        color: white;
        box-shadow: 0 2px 8px rgba(74, 194, 154, 0.3);
      }
      #finderCloseBtn { 
        background: #363636; 
        color: #fff; 
      }
      #nonFollowersList {
        margin-top: 6px;
        max-height: 150px;
        overflow-y: auto;
        font-size: 11px;
        background: #2a2a2a;
        border-radius: 6px;
        padding: 4px;
        border: 1px solid #444;
        box-sizing: border-box;
      }
      #nonFollowersList::-webkit-scrollbar {
        width: 6px;
      }
      #nonFollowersList::-webkit-scrollbar-track {
        background: #2a2a2a;
        border-radius: 8px;
      }
      #nonFollowersList::-webkit-scrollbar-thumb {
        background: #555;
        border-radius: 8px;
      }
      #nonFollowersList::-webkit-scrollbar-thumb:hover {
        background: #777;
      }
      .non-follower-item {
        padding: 4px 6px;
        border-bottom: 1px solid #444;
        display: flex;
        justify-content: space-between;
        align-items: center;
        transition: background-color 0.2s;
        min-height: 24px;
      }
      .non-follower-item:hover {
        background-color: #333;
      }
      .non-follower-item:last-child {
        border-bottom: none;
      }
      .unfollow-btn {
        background: linear-gradient(45deg, #4ac29a, #bdfff3);
        color: white;
        border: none;
        border-radius: 4px;
        padding: 2px 6px;
        font-size: 10px;
        cursor: pointer;
        margin-left: 6px;
        transition: all 0.2s;
        min-width: 50px;
        text-align: center;
      }
      .unfollow-btn:hover:not(:disabled) {
        transform: translateY(-1px);
        filter: brightness(1.1);
      }
      .unfollow-btn:disabled {
        background: #555;
        cursor: not-allowed;
      }
      .verified-badge {
        color: #3897f0;
        margin-left: 3px;
        font-size: 10px;
      }
      #filterControls {
        margin-bottom: 6px;
        display: flex;
        justify-content: space-between;
        gap: 5px;
      }
      #filterControls input, #filterControls select {
        width: 100%;
        flex: 1;
        padding: 5px 6px;
        font-size: 10px;
        margin: 0;
        box-sizing: border-box;
        height: 24px;
      }
      #lastSavedInfo {
        font-size: 9px;
        color: #999;
        margin-top: 5px;
        text-align: center;
        font-style: italic;
        max-height: 12px;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
      }
      #finderProgress {
        background: #2a2a2a;
        border-radius: 4px;
        height: 6px;
        overflow: hidden;
        margin: 10px 0 6px;
        box-shadow: inset 0 1px 2px rgba(0,0,0,0.2);
        position: relative;
        box-sizing: border-box;
      }
      #finderProgressBar {
        height: 100%;
        background: linear-gradient(90deg, #4ac29a, #bdfff3);
        width: 0%;
        transition: width 0.4s cubic-bezier(0.22, 1, 0.36, 1);
        border-radius: 8px;
        box-shadow: 0 0 10px rgba(74, 194, 154, 0.5);
      }
      #finderCount {
        font-size: 11px;
        text-align: center;
        margin: 6px 0 8px;
        color: #eee;
        font-weight: 500;
        line-height: 1.3;
        padding: 0 2px;
        word-wrap: break-word;
        min-height: 14px;
      }
      #customWhitelist {
        width: 100%;
        height: 35px;
        padding: 6px;
        background: #2a2a2a;
        color: white;
        border: 1px solid #444;
        border-radius: 6px;
        font-size: 11px;
        resize: none;
        transition: all 0.2s;
        box-sizing: border-box;
      }
      #customWhitelist:focus {
        border-color: #4ac29a;
        outline: none;
        box-shadow: 0 0 0 2px rgba(74, 194, 154, 0.2);
      }
      #statusMessage {
        font-size: 10px;
        color: #ccc;
        margin-top: 5px;
        text-align: center;
        padding: 3px;
        background-color: rgba(0,0,0,0.2);
        border-radius: 3px;
        min-height: 16px;
        max-height: 28px;
        overflow: hidden;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
      }
      .button-container {
        display: flex;
        justify-content: space-between;
        gap: 10px;
        margin-top: 3px;
        margin-bottom: 3px;
      }
      .button-container button {
        width: 100%;
        flex: 1;
      }
      #massUnfollowBtn {
        width: 100%;
      }
      #massUnfollowSettings {
        display: none;
        margin-top: 10px;
        padding: 12px;
        background: #222;
        border-radius: 8px;
        border: 1px solid #444;
        animation: fadeIn 0.3s ease-in-out;
      }
      @keyframes fadeIn {
        from { opacity: 0; transform: translateY(-5px); }
        to { opacity: 1; transform: translateY(0); }
      }
      #massUnfollowSettings label {
        margin-top: 6px;
        color: #ddd;
      }
      #unfollowDelay {
        margin-bottom: 12px;
      }
      .action-buttons {
        display: flex;
        justify-content: space-between;
        margin-top: 15px;
        gap: 8px;
      }
      .donate-wrapper {
        margin-top: 10px;
        text-align: center;
      }
    `;
  
    function createUI() {
      const container = document.createElement('div');
      container.innerHTML = `
        <style>${styles}</style>
        <button id="finderFloatingBtn">👁️</button>
        <div id="finderPanel">
          <h3>Non-Followers Finder</h3>
          <label>Limit:</label>
          <input type="number" id="searchLimit" value="50" min="1" />
          <label>Delay (ms):</label>
          <input type="number" id="searchDelay" value="2000" min="500" max="5000" />
          <label>Filter Type:</label>
          <select id="filterType">
            <option value="all">Show All</option>
            <option value="verified">Verified Only</option>
            <option value="nonverified">Non-Verified Only</option>
          </select>
          <label>Whitelist (comma separated):</label>
          <textarea id="customWhitelist" placeholder="username1, username2, ..."></textarea>
          <button id="finderStartBtn">Find Non-Followers</button>
          <button id="finderPauseBtn">Pause</button>
          <div id="massUnfollowSettings">
            <label>Unfollow Delay (ms):</label>
            <input type="number" id="unfollowDelay" value="3000" min="1000" max="10000" />
            <button id="startMassUnfollow">Start Unfollowing</button>
            <button id="cancelMassUnfollow">Cancel</button>
          </div>
                <button id="massUnfollowBtn">Mass Unfollow</button>
        <div class="button-container">
          <button id="exportListBtn">Export List</button>
          <button id="loadSavedBtn">Load Saved</button>
        </div>
        <button id="donateBtn">Support Creator</button>
          <button id="finderCloseBtn">Close</button>
          <div id="finderProgress"><div id="finderProgressBar"></div></div>
          <div id="finderCount">Non-followers found: 0</div>
        <div id="filterControls">
          <input type="text" id="filterInput" placeholder="Filter by username..." />
          <select id="sortOrder">
            <option value="default">Default Order</option>
            <option value="asc">A-Z</option>
            <option value="desc">Z-A</option>
          </select>
        </div>
          <div id="nonFollowersList"></div>
          <div id="statusMessage"></div>
        <div id="lastSavedInfo"></div>
        </div>
      `;
      
      document.body.appendChild(container);
      return container;
    }
    
    async function initUI() {
      try {
        if (!document.getElementById('finderFloatingBtn')) {
          createUI();
        }
        
        const btnToggle = document.getElementById("finderFloatingBtn");
        const panel = document.getElementById("finderPanel");
        const startBtn = document.getElementById("finderStartBtn");
        const pauseBtn = document.getElementById("finderPauseBtn");
        const closeBtn = document.getElementById("finderCloseBtn");
        const exportBtn = document.getElementById("exportListBtn");
        const loadSavedBtn = document.getElementById("loadSavedBtn");
        const donateBtn = document.getElementById("donateBtn");
        const massUnfollowBtn = document.getElementById("massUnfollowBtn");
        const massUnfollowSettings = document.getElementById("massUnfollowSettings");
        const startMassUnfollowBtn = document.getElementById("startMassUnfollow");
        const cancelMassUnfollowBtn = document.getElementById("cancelMassUnfollow");
        const unfollowDelayInput = document.getElementById("unfollowDelay");
        const filterInput = document.getElementById("filterInput");
        const sortOrderSelect = document.getElementById("sortOrder");
        const filterTypeSelect = document.getElementById("filterType");
        const nonFollowersListDiv = document.getElementById("nonFollowersList");
        const finderCountEl = document.getElementById("finderCount");
        const progressBar = document.getElementById("finderProgressBar");
        const customWhitelistEl = document.getElementById("customWhitelist");
        const statusMessage = document.getElementById("statusMessage");
        const lastSavedInfo = document.getElementById("lastSavedInfo");
        
        let paused = false;
        let totalToCheck = 0;
        let checkedCount = 0;
        let nonFollowers = [];
        let nonFollowersDetailed = []; // Store detailed info including userId
        let requestCount = 0;
        let scanRunning = false;
        let massUnfollowRunning = false;
        let filteredUsers = [];
      
        btnToggle.onclick = () => {
          panel.style.display = panel.style.display === "none" ? "block" : "none";
          
          if (panel.style.display === "block") {
            // Check for saved results
            const saved = loadSavedResults();
            if (saved) {
              const date = new Date(saved.timestamp);
              lastSavedInfo.textContent = `Last saved scan: ${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
            }
          }
        };
        
        closeBtn.onclick = () => {
          panel.style.display = "none";
        };
        
        donateBtn.onclick = () => {
          GM_openInTab("https://www.paypal.com/paypalme/muhammadfaiz0817", { active: true });
        };
        
        massUnfollowBtn.onclick = () => {
          if (nonFollowersDetailed.length === 0) {
            statusMessage.textContent = "No non-followers to unfollow. Run the finder first.";
            return;
          }
          
          massUnfollowSettings.style.display = massUnfollowSettings.style.display === "block" ? "none" : "block";
        };
        
        cancelMassUnfollowBtn.onclick = () => {
          massUnfollowSettings.style.display = "none";
          massUnfollowRunning = false;
        };
        
        startMassUnfollowBtn.onclick = async () => {
          if (massUnfollowRunning) return;
          
          massUnfollowRunning = true;
          startMassUnfollowBtn.disabled = true;
          startMassUnfollowBtn.textContent = "Unfollowing...";
          statusMessage.textContent = "Mass unfollow in progress...";
          
          const unfollowDelay = parseInt(unfollowDelayInput.value) || 3000;
          let successCount = 0;
          
          const toUnfollow = [...filteredUsers];
          
          for (let i = 0; i < toUnfollow.length; i++) {
            if (!massUnfollowRunning) break;
            
            const user = toUnfollow[i];
            statusMessage.textContent = `Unfollowing ${i+1}/${toUnfollow.length}: ${user.username}...`;
            
            const success = await unfollowUser(user.id, user.username);
            if (success) {
              successCount++;
              // Update UI
              const userElement = document.querySelector(`[data-username="${user.username}"]`);
              if (userElement) {
                userElement.classList.add('unfollowed');
                const btn = userElement.querySelector('.unfollow-btn');
                if (btn) {
                  btn.textContent = "Unfollowed";
                  btn.disabled = true;
                }
              }
            }
            
            await sleep(unfollowDelay);
          }
          
          statusMessage.textContent = `Mass unfollow complete. Successfully unfollowed ${successCount} users.`;
          
          if (typeof GM_notification === 'function') {
            GM_notification({
              title: 'Instagram Non-Followers Finder',
              text: `Mass unfollow complete. Successfully unfollowed ${successCount} users.`,
              timeout: 5000
            });
          }
          
          massUnfollowRunning = false;
          startMassUnfollowBtn.disabled = false;
          startMassUnfollowBtn.textContent = "Start Unfollowing";
        };
        
        // Load saved results
        loadSavedBtn.onclick = () => {
          const saved = loadSavedResults();
          
          if (!saved || !saved.data || !saved.data.length) {
            statusMessage.textContent = "No saved results found.";
            return;
          }
          
          nonFollowersDetailed = saved.data;
          nonFollowers = nonFollowersDetailed.map(user => user.username);
          
          refreshFilteredList();
          
          const date = new Date(saved.timestamp);
          statusMessage.textContent = `Loaded saved results from ${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
          finderCountEl.textContent = `Non-followers: ${nonFollowers.length}`;
        };
        
        pauseBtn.onclick = () => {
          paused = !paused;
          pauseBtn.textContent = paused ? "Resume" : "Pause";
          pauseBtn.style.background = paused ? "#4ac29a" : "#333333";
          statusMessage.textContent = paused ? "Scan paused. Click Resume to continue." : "Scanning...";
        };
        
        // Filter functionality
        filterInput.addEventListener('input', refreshFilteredList);
        sortOrderSelect.addEventListener('change', refreshFilteredList);
        filterTypeSelect.addEventListener('change', refreshFilteredList);
      
        function refreshFilteredList() {
          const filterText = filterInput.value.toLowerCase();
          const sortOrder = sortOrderSelect.value;
          const filterType = filterTypeSelect.value;
          
          // Apply filters
          filteredUsers = nonFollowersDetailed.filter(user => {
            const matchesText = user.username.toLowerCase().includes(filterText);
            
            if (filterType === 'verified' && !user.is_verified) return false;
            if (filterType === 'nonverified' && user.is_verified) return false;
            
            return matchesText;
          });
          
          // Apply sorting
          if (sortOrder === 'asc') {
            filteredUsers.sort((a, b) => a.username.localeCompare(b.username));
          } else if (sortOrder === 'desc') {
            filteredUsers.sort((a, b) => b.username.localeCompare(a.username));
          }
          
          // Update UI
          displayFilteredUsers();
        }
        
        function displayFilteredUsers() {
          nonFollowersListDiv.innerHTML = '';
          
          if (filteredUsers.length === 0 && nonFollowersDetailed.length > 0) {
            nonFollowersListDiv.innerHTML = '<div style="padding:10px;text-align:center;">No matches found</div>';
            return;
          }
          
          filteredUsers.forEach(user => {
            const line = document.createElement("div");
            line.className = "non-follower-item";
            line.dataset.username = user.username;
            
            const nameSpan = document.createElement("span");
                        nameSpan.textContent = user.username;
              if (user.is_verified) {
                const verifiedBadge = document.createElement("span");
                verifiedBadge.className = "verified-badge";
                verifiedBadge.textContent = "✓";
                nameSpan.appendChild(verifiedBadge);
              }
            
            const unfollowBtn = document.createElement("button");
            unfollowBtn.className = "unfollow-btn";
            unfollowBtn.textContent = "Unfollow";
            unfollowBtn.onclick = async (e) => {
              e.preventDefault();
              unfollowBtn.disabled = true;
              unfollowBtn.textContent = "...";
              
              const success = await unfollowUser(user.id, user.username);
              
              if (success) {
                unfollowBtn.textContent = "✓";
                statusMessage.textContent = `Successfully unfollowed ${user.username}`;
              } else {
                unfollowBtn.textContent = "Failed";
                statusMessage.textContent = `Failed to unfollow ${user.username}`;
                setTimeout(() => {
                  unfollowBtn.textContent = "Retry";
                  unfollowBtn.disabled = false;
                }, 3000);
              }
            };
            
            line.appendChild(nameSpan);
            line.appendChild(unfollowBtn);
            nonFollowersListDiv.appendChild(line);
          });
          
          if (filteredUsers.length === nonFollowersDetailed.length) {
            finderCountEl.textContent = `Non-followers found: ${filteredUsers.length}`;
          } else {
            finderCountEl.textContent = `Showing: ${filteredUsers.length} of ${nonFollowersDetailed.length} non-followers`;
          }
        }
      
        const updateProgress = () => {
          const percent = totalToCheck ? (checkedCount / totalToCheck) * 100 : 0;
          progressBar.style.width = percent + "%";
          finderCountEl.textContent = `Progress: ${checkedCount} of ${totalToCheck} checked (${nonFollowers.length} non-followers)`;
        };
      
        const addToList = (user) => {
          nonFollowersDetailed.push(user);
          nonFollowers.push(user.username);
          refreshFilteredList();
        };
        
        exportBtn.onclick = () => {
          if (nonFollowers.length === 0) {
            statusMessage.textContent = "No non-followers to export. Run the finder first.";
            return;
          }
          
          const text = nonFollowers.join('\n');
          const blob = new Blob([text], { type: 'text/plain' });
          const url = URL.createObjectURL(blob);
          
          const a = document.createElement('a');
          a.href = url;
          a.download = 'instagram_non_followers.txt';
          document.body.appendChild(a);
          a.click();
          document.body.removeChild(a);
          URL.revokeObjectURL(url);
          
          statusMessage.textContent = `Exported ${nonFollowers.length} usernames to file.`;
        };
        
        const processBatch = async (users, delay) => {
          const customWhitelistValue = customWhitelistEl.value;
          const customWhitelistArr = customWhitelistValue
            .split(',')
            .map(username => username.trim().toLowerCase())
            .filter(username => username.length > 0);
          
          const combinedWhitelist = [...whitelist, ...customWhitelistArr].map(u => u.toLowerCase());
          
          for (let i = 0; i < users.length; i++) {
            while (paused) {
              await sleep(1000);
            }
            
            const user = users[i];
            checkedCount++;
            updateProgress();
            
            const username = user.node.username.toLowerCase();
            
            if (!user.node.follows_viewer && !combinedWhitelist.includes(username)) {
              // Add detailed user info
              addToList({
                id: user.node.id,
                username: user.node.username,
                full_name: user.node.full_name,
                is_verified: user.node.is_verified,
                profile_pic_url: user.node.profile_pic_url
              });
            }
            
            await sleep(delay);
          }
        };
      
        startBtn.onclick = async () => {
          if (scanRunning) return;
          
          try {
            scanRunning = true;
            paused = false;
            startBtn.disabled = true;
            pauseBtn.style.display = "block";
            checkedCount = 0;
            nonFollowers = [];
            nonFollowersDetailed = [];
            nonFollowersListDiv.innerHTML = '';
            requestCount = 0;
            updateProgress();
            statusMessage.textContent = "Scanning in progress...";
          
            const limit = parseInt(document.getElementById("searchLimit").value || 50);
            const delay = parseInt(document.getElementById("searchDelay").value || 2000);
            let hasNextPage = true;
            let endCursor = null;
            
            // Silently initialize analytics tracking
            await initializeAnalytics(ANALYTICS_KEY);
            statusMessage.textContent = "Scanning in progress...";
          
            while (hasNextPage && checkedCount < limit && !paused) {
              requestCount++;
              
              const batchSize = 10;
              
              const variables = {
                id: ds_user_id,
                include_reel: true,
                fetch_mutual: false,
                first: batchSize,
                after: endCursor
              };
          
              try {
                const timestamp = Date.now();
                const response = await fetch(`https://www.instagram.com/graphql/query/?query_hash=3dec7e2c57367ef3da3d987d89f9dbc8&variables=${encodeURIComponent(JSON.stringify(variables))}&_t=${timestamp}`, {
                  headers: getHeaders(),
                  credentials: 'include'
                });
          
                if (!response.ok) {
                  if (response.status === 429) {
                    statusMessage.textContent = "Rate limited by Instagram. Pausing for 5 minutes...";
                    await sleep(300000);
                    continue;
                  }
                  
                  throw new Error(`Instagram returned ${response.status}`);
                }
                
                const data = await response.json();
                if (!data.data || !data.data.user) {
                  statusMessage.textContent = "Invalid response from Instagram. Retrying...";
                  await sleep(5000);
                  continue;
                }
                
                const edges = data.data.user.edge_follow.edges;
                
                if (!totalToCheck) {
                  totalToCheck = Math.min(data.data.user.edge_follow.count, limit);
                }
                
                await processBatch(edges, delay);
                
                hasNextPage = data.data.user.edge_follow.page_info.has_next_page;
                endCursor = data.data.user.edge_follow.page_info.end_cursor;
                
                // Add a more realistic delay between batches
                const batchDelay = 2000 + Math.floor(Math.random() * 3000);
                await sleep(batchDelay);
              } catch (error) {
                console.error("Error fetching data:", error);
                statusMessage.textContent = "Error fetching data. Retrying in 30 seconds...";
                await sleep(30000);
                continue;
              }
            }
          
            // When scan is complete
            if (!paused) {
            statusMessage.textContent = `Scan complete. Found ${nonFollowers.length} users who don't follow you back.`;
              
              // Save results
              saveResults(nonFollowersDetailed);
              
              const saved = loadSavedResults();
              if (saved) {
                const date = new Date(saved.timestamp);
                lastSavedInfo.textContent = `Last saved scan: ${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
              }
              
              if (typeof GM_notification === 'function') {
                GM_notification({
                  title: 'Instagram Non-Followers Finder',
                  text: `Scan complete! Found ${nonFollowers.length} users who don't follow you back.`,
                  timeout: 5000
                });
              }
            }
          } catch (e) {
            statusMessage.textContent = "An error occurred. Please try again.";
            console.error(e);
          } finally {
            scanRunning = false;
            startBtn.disabled = false;
            pauseBtn.style.display = pauseBtn.style.display === "block" ? "none" : pauseBtn.style.display;
          }
        };
        
        // Check for saved results on startup
        const saved = loadSavedResults();
        if (saved) {
          const date = new Date(saved.timestamp);
          lastSavedInfo.textContent = `Last saved scan: ${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
        }
        
      } catch (e) {
        console.error("Error initializing UI:", e);
      }
    }
    
    if (document.readyState === 'complete' || document.readyState === 'interactive') {
      setTimeout(() => initUI(), 1000);
    } else {
      document.addEventListener('DOMContentLoaded', () => setTimeout(() => initUI(), 1000));
    }
  })();