Mastering SEO : Free Apps Script for Bulk Audit Spreadsheet Backlinks

AppSScript Code

function onOpen() {
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('Scan and Check')
    .addItem('Scan and Check', 'scanAndCheck')
    .addToUi();
}




function scanAndCheck() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var data = sheet.getDataRange().getValues();


  var successUrls = [];
  var failedUrls = [];
  var invalidUrls = [];


  // Store visited domains to skip redundant checks
  var visitedDomains = [];


  // Add a column for "Status on Current Date" if it doesn't exist
  var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
  var statusColumnIndex = headers.indexOf("Status on Current Date");
  if (statusColumnIndex === -1) {
    statusColumnIndex = headers.length + 1;
    sheet.getRange(1, statusColumnIndex).setValue("Status on Current Date");
  }


  var currentDate = new Date();
  var year = Utilities.formatDate(currentDate, "GMT", "yyyy");
  var month = Utilities.formatDate(currentDate, "GMT", "MM");
  var day = Utilities.formatDate(currentDate, "GMT", "dd");
  var formattedDate = day + "-" + month + "-" + year;


  // Check if the date has already been set
  var dateAlreadySet = false;
  for (var i = 1; i < data.length; i++) {
    var statusValue = sheet.getRange(i + 1, statusColumnIndex).getValue();
    if (statusValue && statusValue.includes(formattedDate)) {
      dateAlreadySet = true;
      break;
    }
  }


  // Set the date at the top of the "Status on Current Date" column if not already set
  if (!dateAlreadySet) {
    sheet.getRange(1, statusColumnIndex).setValue(formattedDate);
  }


  // Add a new column for the status
  var statusTextColumnIndex = statusColumnIndex + 1;
  sheet.getRange(1, statusTextColumnIndex).setValue("Status");


  for (var i = 1; i < data.length; i++) {
    var url = data[i][0];


    // Check if the URL is empty
    if (!url) {
      continue; // Skip empty rows
    }


    // Validate the URL
    if (!isValidUrl(url)) {
      // Skip invalid URLs and mark them as "Invalid"
      invalidUrls.push(url);
      sheet.getRange(i + 1, statusTextColumnIndex).setValue("Invalid domain").setFontColor("blue");
      continue;
    }


    // Check link validity
    checkLinkValidity(url, i, statusColumnIndex, statusTextColumnIndex, sheet, successUrls, failedUrls, visitedDomains);
  }


  // Display results in an alert
  var resultMessage = "Successful URLs with outrightcrm.com backlink:\n" + successUrls.join("\n") + "\n\nFailed URLs:\n" + failedUrls.join("\n") + "\n\nInvalid URLs:\n" + invalidUrls.join("\n");


  // Show alert in the browser
  var ui = SpreadsheetApp.getUi();
  ui.alert('Scan Results', resultMessage, ui.ButtonSet.OK);
}


function checkLinkValidity(url, rowIndex, statusColumnIndex, statusTextColumnIndex, sheet, successUrls, failedUrls, visitedDomains) {
  try {
    var response = UrlFetchApp.fetch(url);
    var statusCode = response.getResponseCode();
    if (statusCode == 200) {
      // Task 1: Scan URL
      // Perform actions for scanning the URL (you can replace this with your own logic)


      // Task 2: Check if the URL is from the self website or outside website
      var isSelfWebsite = url.startsWith("https://outright") || hasBacklink(url, "outrightcrm.com");
     
      // Store the results
      if (isSelfWebsite) {
        successUrls.push(url);
        // Update the "Status on Current Date" column for success with today's date
        sheet.getRange(rowIndex + 1, statusColumnIndex).setValue("Targeted Url").setFontColor("green");
        // Update the new "Status" column with "Successful"
        sheet.getRange(rowIndex + 1, statusTextColumnIndex).setValue("backlink found").setFontColor("green");
      } else {
        failedUrls.push(url);
        // Update the "Status on Current Date" column for failure with today's date
        sheet.getRange(rowIndex + 1, statusColumnIndex).setValue("Outside Website").setFontColor("red");
        // Update the new "Status" column with "Failed"
        sheet.getRange(rowIndex + 1, statusTextColumnIndex).setValue("No backlink found").setFontColor("red");
      }


      // Mark the domain as visited
      var domain = getDomain(url);
      visitedDomains.push(domain);
    } else {
      // Handle non-200 status code
      failedUrls.push(url);
      // Update the "Status on Current Date" column for failure with today's date
      sheet.getRange(rowIndex + 1, statusColumnIndex).setValue("Failed (Non-200)").setFontColor("red");
      // Update the new "Status" column with "Failed"
      sheet.getRange(rowIndex + 1, statusTextColumnIndex).setValue("Failed (Non-200)").setFontColor("red");
    }
  } catch (error) {
    // Handle fetch error
    failedUrls.push(url);
    // Update the "Status on Current Date" column for failure with today's date
    sheet.getRange(rowIndex + 1, statusColumnIndex).setValue("Failed (Error)").setFontColor("red");
    // Update the new "Status" column with "Failed"
    sheet.getRange(rowIndex + 1, statusTextColumnIndex).setValue("Failed (Error)").setFontColor("red");
    Logger.log('An error occurred while checking the link validity: ' + error);
  }
}


// Function to extract domain from URL
function getDomain(url) {
  var match = url.match(/^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n?]+)/);
  return match ? match[1] : null;
}


// Function to check if the URL has a backlink to outrightcrm.com
function hasBacklink(url, domain) {
  // Implement logic to check if the URL has a backlink to the specified domain
  // You may use regular expressions or other methods
  var urlContent = getContentFromUrl(url);
  var regex = new RegExp('outrightcrm\\.com', 'i');
  return regex.test(urlContent);
}


// Function to get content from a URL
function getContentFromUrl(url) {
  try {
    var response = UrlFetchApp.fetch(url);
    return response.getContentText();
  } catch (e) {
    // Handle any errors or return an appropriate value
    Logger.log("Error fetching content from URL: " + url);
    return '';
  }
}


// Function to validate URLs
function isValidUrl(url) {
  var urlRegex = /^(https?|ftp):\/\/[^\s\/$.?#].[^\s]*$/i;
  return urlRegex.test(url);
}


// Function to fetch tasks from ChatGPT using its API
const OPENAI_API_KEY = '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';  // Replace with your actual API key


// Function to call OpenAI API
function callOpenAI(prompt) {
    const url = 'https://api.openai.com/v1/engines/davinci-codex/completions';
    const payload = {
        prompt: prompt,
        max_tokens: 150
    };


    const options = {
        method: 'post',
        contentType: 'application/json',
        headers: {
            'Authorization': `Bearer ${OPENAI_API_KEY}`
        },
        payload: JSON.stringify(payload)
    };


    const response = UrlFetchApp.fetch(url, options);
    const responseJson = JSON.parse(response.getContentText());
    return responseJson.choices[0].text;
}


// Function to execute script code
function executeScript(scriptCode) {
    try {
        const result = eval(scriptCode);
        return { success: true, result: result };
    } catch (error) {
        return { success: false, error: error.toString() };
    }
}


// Function to handle the web app's GET request
function doGet() {
    const htmlOutput = HtmlService.createHtmlOutputFromFile('Index');
    return htmlOutput.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}




// Main workflow function
function mainWorkflow(initialPrompt) {
    let scriptCode = callOpenAI(initialPrompt);
    let executionResult = executeScript(scriptCode);


    if (!executionResult.success) {
        Logger.log('Error encountered: ' + executionResult.error);
        // Additional error handling and feedback mechanism should be implemented here
    } else {
        Logger.log('Execution successful: ' + executionResult.result);
        // Handle successful execution
    }
}