HARPA.AI
LIBRARYUSE CASESGUIDESAI COMMANDSBLOG

๐Ÿ”„ย ย Instagram Followers Auto Follow v1.3 #instagram

Automatically follows a list of profiles from a single Instagram account. Works without usernames/links - uses current page data instead.

Created by Mohammed Al-Rashid
Updated on Dec 20, 11:57
Installed 88 times
RUNS JS CODE

How to Use

IMPORT COMMAND

Content

- type: calc
  func: set
  param: result
  format: number
  value: '0'
- type: ask
  param: input
  message: >-
    Send the Instagram profile as **@username** or **username**, the link as
    **https://www.instagram.com/username/**, or start processing this tab.
  options:
    - label: โœ… USE THIS TAB
      value: tab
    - $custom
  default: ''
  vision:
    enabled: false
    mode: area
    hint: ''
    send: true
  optionsInvalid: false
  label: ASK FOR INPUT
- type: group
  steps:
    - type: js
      args: url
      code: |-
        let regex = /instagram\.com\/[\w\.]+(?:\/.*)?$/;

        let isValid = regex.test(url);
        return isValid;
      param: linkCheck
      timeout: 15000
      silent: true
    - type: say
      message: >-
        โ›”๏ธ The webpage is not suitable for processing. Please start on a new
        page or provide me with a username or link.
      condition: '{{linkCheck}} = false'
    - type: jump
      to: ASK FOR INPUT
      condition: '{{linkCheck}} = false'
    - type: js
      args: url
      code: |-
        let urlPattern = /^https:\/\/www\.instagram\.com\/([\w\.]+)/;

        let result = url.match(urlPattern)[1]; 

        return result;
      param: username
      timeout: 15000
      silent: true
    - type: jump
      to: EXTRACT STATS
  label: CHECK CURRENT TAB
  condition: '{{input}} = tab'
- type: group
  steps:
    - type: js
      args: input
      code: |-
        let urlPattern = /^https:\/\/www\.instagram\.com\/([\w\.]+)/;
        let result = input; // Default to the original value

        if (input.startsWith('@')) {
            result = input.slice(1); // Remove '@' symbol if it exists
        } else if (urlPattern.test(result)) {
            result = input.match(urlPattern)[1]; // Extract username from the URL
        }

        console.log(result);
        return result;
      param: username
      timeout: 15000
      silent: true
  condition: '{{input-option}} = $custom'
  label: EXTRACT USERNAME
- label: ASK FOR USERS
  type: ask
  param: input
  message: |-
    Send me a list of profiles either as:

    1. @usernames separated by commas, e.g.:

    ```
    @harpa.ai,  @chrome, @extension
    ```

    2. JSON with URLs, e.g.:

    ```json
    [
    {
      "url": "https://www.instagram.com/harpa.ai/"
    },
    {
      "url": "https://www.instagram.com/username/"
    }
    ]
    ```
  options: null
  default: ''
  vision:
    enabled: false
    mode: area
    send: true
    hint: ''
- type: group
  steps:
    - type: say
      message: โณ Extracting followers' profiles, wait a bit.
    - type: navigate
      url: https://www.instagram.com/{{username}}/
      waitForIdle: false
      silent: true
      onFailure: ''
    - type: wait
      for: 2s
      silent: true
    - type: js
      args: ''
      code: |-
        let text = document.querySelector('header section ul').innerText;
        let formattedText = text.replace(/\n/g, ', '); 
        return formattedText;
      param: stats
      timeout: 15000
      label: EXTRACT STATS
      silent: true
  label: NAVIGATE
- type: ask
  param: count
  message: >-
    **[@{{username}}](https://www.instagram.com/{{username}}/)** has {{stats}}. 


    How many followers should be extracted and followed? Pick an option or enter
    a number.
  options:
    - label: โ™ป๏ธ ALL
      value: 99999999999
    - label: 50
      value: 50
    - label: 100
      value: 100
    - label: 250
      value: 250
    - label: 500
      value: 500
    - label: 1k
      value: 1000
    - label: 5k
      value: 5000
    - label: 10k
      value: 10000
    - $custom
  default: ''
  vision:
    enabled: false
    mode: area
    hint: ''
    send: true
  optionsInvalid: false
- type: group
  steps:
    - type: navigate
      url: https://www.instagram.com/{{username}}/followers/
      waitForIdle: false
      silent: true
      onFailure: ''
    - type: control
      action: show
    - type: wait
      for: idle
      timeout: 3500
      silent: true
    - type: js
      args: ''
      code: |-
        let linkOpened = !!document.querySelector('div[role="dialog"]');

        return linkOpened;
      param: linkOpened
      timeout: 15000
      label: CHECK IF OPENED
      silent: true
    - type: js
      args: linkOpened
      code: document.querySelector('header section ul li:nth-child(2) a').click();
      param: ''
      timeout: 15000
      label: CHECK IF FAILED
      condition: '{{linkOpened}} = false'
      silent: true
    - type: wait
      for: 2s
      condition: '{{linkOpened}} = false'
      silent: true
    - type: js
      args: linkOpened
      code: |-
        let openData = !!document.querySelector('[placeholder="Search"]');

        return openData;
      param: openData
      timeout: 15000
      label: CHECK IF HIDDEN
      condition: '{{linkOpened}} = false'
      silent: true
    - type: say
      message: ๐Ÿ’ก Followers info hidden. Extracting what's accessible...
      condition: '{{openData}} = false'
    - type: js
      args: count
      code: |-
        async function extractDataWithScroll(count) {
          // Find the dialog element
          const dialog = document.querySelector('div[role="dialog"]');
          if (!dialog) {
            console.error('Dialog not found');
            return null;
          }

          const results = [];
          const uniqueUsernames = new Set();
          let retries = 0;
          const maxRetries = 10; // Limit the number of scrolling attempts

          // Function to scroll and wait for new content to load
          async function scrollAndWait() {
            const scrollableElement = document.querySelector('div[role="dialog"] div:has(> div > input) ~ div:last-child');
            if (scrollableElement) {
              console.log('Scrolling to load more users...');
              scrollableElement.scrollBy(0, 1000); // Scroll down by 1000 pixels
              await new Promise(resolve => setTimeout(resolve, 3000)); // Wait for 1 second for new elements to load
            } else {
              console.error('Error: Unable to find the scrollable element.');
            }
          }

          // Function to extract user data from the current view
          async function extractUsers() {
            const userElements = dialog.querySelectorAll('div[role="dialog"] div[style*="flex-direction: column"] > div > div > div:nth-child(1)');
            let newUsersFound = false;

            for (const userElement of userElements) {
              // Find the link element containing the username
              const linkElement = userElement.querySelector('a[href^="/"][role="link"]');
              if (!linkElement) continue;

              // Extract username from the link
              const link = linkElement.getAttribute('href');
              const username = link.slice(1).replace('/', '');

              // Skip if this username has already been processed
              if (uniqueUsernames.has(username)) continue;

              // Try to find the full name
              let fullNameElement = linkElement.nextElementSibling;
              let fullName = fullNameElement && fullNameElement.tagName === 'SPAN' 
                ? fullNameElement.textContent.trim() 
                : '';

              // If full name not found, search in other span elements
              if (!fullName) {
                const spans = userElement.querySelectorAll('span');
                for (const span of spans) {
                  const text = span.textContent.trim();
                  if (text && text !== username && text !== 'Search') {
                    fullName = text;
                    break;
                  }
                }
              }

              // If both username and full name are found, add to results
              if (username && fullName) {
                uniqueUsernames.add(username);
                results.push({
                  username: username,
                  fullName: fullName,
                  link: `https://www.instagram.com/${username}`
                });
                newUsersFound = true;
              }
            }

            return newUsersFound;
          }

          // Main loop: extract users and scroll until target count is reached or max retries hit
          while (results.length < count && retries < maxRetries) {
            const newUsersFound = await extractUsers();
            console.log(`Collected ${results.length} users so far.`);

            if (results.length < count) {
              await scrollAndWait();
              retries++;
            }

            if (!newUsersFound) {
              retries++;
            } else {
              retries = 0; // Reset the retry counter if new users were found
            }
          }

          console.log(`Total users found: ${results.length}`);
          
          // Trim the results array to the requested count
          if (results.length > count) {
            console.log(`Trimming results from ${results.length} to ${count}`);
            results.splice(count);
          }
          
          // Return the results as a JSON string, or undefined if no results
          return results.length > 0 ? JSON.stringify(results, null, 2) : undefined;
        }

        // Function call and result output
        extractDataWithScroll(count).then(data => {
          console.log(data ? data : "No data found");
        });

        // Return the promise from the function call
        return extractDataWithScroll(count);
      param: followers
      timeout: 1500000
      silent: true
    - type: calc
      func: extract-json
      to: followers
      param: followers
      index: all
    - condition: '{{followers.length}} = 0'
      label: FAIL
      steps:
        - type: say
          message: โ›”๏ธ No data on followers was extracted.
        - type: jump
          to: ASK FOR INPUT
      type: group
    - type: say
      message: โœ… Extracted {{followers.length}} followers' profiles.
  label: DATA EXTRACTION
- label: EXTRACT USERNAMES
  type: group
  steps:
    - type: js
      code: |-
        function extractUsernames(input) {
            let usernames = [];

            // Convert input to string
            const inputStr = String(input);

            // Unified regex to extract @mentions and Instagram URLs
            const usernameRegex = /@(\w+(\.\w+)*(\_\w+)*(\.\w+)*)|https:\/\/www\.instagram\.com\/([\w\.]+)/g;
            let matches;

            // Search through the string input for usernames and URLs
            while ((matches = usernameRegex.exec(inputStr)) !== null) {
                // Push the non-null match group, either mention or URL segment
                usernames.push(matches[1] || matches[5]);
            }

            return usernames;
        }

        // Using the function, assuming input is already defined
        return extractUsernames(input);
      param: list
      timeout: 15000
      args: input
      silent: true
- label: ASK SPEED
  param: delay
  message: >-
    ๐Ÿ’ก Choose an option or enter a custom delay in milliseconds (1 min = 60 sec
    = 60000 ms).
  options:
    - label: โฉ NORMAL (30 sec.)
      value: 30000
    - label: โ–ถ๏ธ SLOW (5 min.)
      value: 300000
    - label: โญ FAST (10 sec.)
      value: 10000
    - $custom
  vision:
    enabled: false
    mode: area
    hint: ''
    send: true
  type: ask
  default: ''
  optionsInvalid: false
- type: loop
  steps:
    - label: NAVIGATE
      steps:
        - message: ๐ŸŒ Navigating to **[@{{item.username}}]({{item.link}})**'s profile.
          type: say
        - type: navigate
          url: '{{item.link}}'
          waitForIdle: false
          silent: true
        - type: wait
          for: 2s
          silent: true
      type: group
    - label: FOLLOW
      steps:
        - type: click
          selectorType: ai
          selector:
            - $matches:
                - $tag: BUTTON
                - $role: button
                - $class: _acan
                - $class: _acap
                - $class: _acas
                - $class: _aj1-
                - $class: _ap30
                - $attribute: type=button
                - $style: '-apple-system:14px:600:normal'
                - $content: Follow
                - $class: x150jy0e
                  traverse: '-1'
                - $class: x1e558r4
                  traverse: '-1'
                - $class: xxz05av
                  traverse: '1:0:0:0'
                - $class: xkfe5hh
                  traverse: '1:0:0:0'
                - $class: xg1prrt
                  traverse: '0:1:0:0:0'
                - $anchor: TAGGED
                  shift: 23:-184
              min: 6
            - $size: 1
          item:
            type: element
            container:
              id: 0
              __$ht: element
            value: Follow
          silent: true
        - selector:
            - $matches:
                - $tag: BUTTON
                - $role: button
                - $class: _acan
                - $class: _acap
                - $class: _acas
                - $class: _aj1-
                - $class: _ap30
                - $attribute: type=button
                - $style: '-apple-system:14px:600:normal'
                - $content: Follow Back
                - $class: xxz05av
                  traverse: '1:0:0:0'
                - $class: xkfe5hh
                  traverse: '1:0:0:0'
                - $class: xg1prrt
                  traverse: '0:1:0:0:0'
                - $class: x1quol0o
                  traverse: '0:1:0:0:0'
                - $anchor: This account is private
                  shift: 148:-208
                - traverse: '-7:0:1:0:1:0:0:0'
                  $text: This account is private
              min: 10
            - $size: 1
          item:
            container:
              __$ht: element
              id: 1
            type: element
            value: Follow Back
          type: click
          selectorType: ai
          silent: true
        - for: 1s
          type: wait
          silent: true
        - message: '**[@{{item.username}}]({{item.link}})** followed! '
          type: say
        - type: calc
          func: increment
          param: result
          delta: 1
      type: group
    - condition: '{{action}} = unfollow'
      label: UNFOLLOW
      steps:
        - selector:
            - $matches:
                - $tag: BUTTON
                - $role: button
                - $class: _acan
                - $class: _acap
                - $class: _acat
                - $class: _aj1-
                - $class: _ap30
                - $attribute: type=button
                - $style: '-apple-system:14px:600:normal'
                - $content: Following
                - $class: x150jy0e
                  traverse: '-1'
                - $class: x1e558r4
                  traverse: '-1'
                - $class: xxz05av
                  traverse: '1:0:0:0'
                - $class: xkfe5hh
                  traverse: '1:0:0:0'
                - $class: xg1prrt
                  traverse: '0:1:0:0:0'
              min: 6
            - $size: 1
          item:
            container:
              id: 2
              __$ht: element
            type: element
            value: Following
          type: click
          selectorType: ai
          silent: true
        - type: wait
          for: 1s
          silent: true
        - selector:
            - $matches:
                - $tag: DIV
                - $class: x9f619
                - $class: xjbqb8w
                - $class: x78zum5
                - $class: x168nmei
                - $class: x13lgxp2
                - $class: x5pf9jr
                - $class: xo71vjh
                - $class: x1pi30zi
                - $class: x1swvt13
                - $class: x1l90r2v
                - $class: xyamay9
                - $class: x1uhb9sk
                - $class: x1plvlek
                - $class: xryxfnj
                - $class: x1c4vz4f
                - $class: x2lah0s
                - $class: xdt5ytf
                - $class: xqjyukv
                - $class: x1qjc9v5
                - $class: x1oa3qoh
                - $class: x1nhvcw1
                - $style: '-apple-system:14px:400:normal'
                - $content: Unfollow
                - $class: x7r02ix
                  traverse: '0:0:0:7:0'
                - $class: xf1ldfh
                  traverse: '0:0:0:7:0'
                - $class: x131esax
                  traverse: '0:0:0:7:0'
                - $class: xdajt7p
                  traverse: '0:0:0:7:0'
                - $class: xxfnqb6
                  traverse: '0:0:0:7:0'
                - $anchor: Restrict
                  shift: '0:50'
                - traverse: '-9:7:0'
                  $text: Restrict
                - $anchor: Mute
                  shift: '0:100'
              min: 24
            - $size: 1
          item:
            container:
              id: 3
              __$ht: element
            type: element
            value: Unfollow
          type: click
          selectorType: ai
          silent: true
        - type: wait
          for: 1s
          silent: true
        - message: >-
            โŽ **[@{{username}}](https://www.instagram.com/{{username}}/)**
            unfollowed! 
          type: say
      type: group
    - for: custom-delay
      delay: '{{delay}}'
      type: wait
  list: followers
- message: 'โ˜‘๏ธ {{result}} users followed. '
  type: say
Notice: Please read before using

This automation command is created by a community member. HARPA AI team does not audit community commands.

Please review the command carefully and only install if you trust the creator.

Contact us
HomeUse CasesGuidesPrivacy PolicyTerms of Service
CAN WE STORE COOKIES?
Our website uses cookies for the purposes of accessibility and security. They also allow us to gather statistics in order to improve the website for you. More info: Privacy Policy