Automatic bidding adjustments

1. Overview

What It Is: The Automatic Bidding Adjustments script is designed to optimize keyword bids based on performance data from yesterday. It evaluates each keyword’s cost per conversion against a defined conversion threshold and adjusts the bid accordingly:
  • If the cost per conversion is higher than the threshold, the bid is decreased.
  • If it is significantly lower than the threshold, the bid is increased.
  • If there are zero conversions and a high cost, the bid is lowered.
The script only processes keywords that have received a minimum number of impressions (to avoid adjustments based on insufficient data). Additionally, it logs bid adjustments and can send an email summary and/or log details to a Google Sheet.
Why It’s Important:
  • Cost Efficiency: Automatically adjusts bids to help maintain an acceptable cost per conversion, preventing overspending on underperforming keywords.
  • Performance Optimization: Enhances keyword performance by ensuring that high-performing keywords receive a bid boost, while underperforming keywords are bid down.
  • Automation: Saves time by removing the need for manual bid management, allowing for more agile campaign optimization.
  • Data-Driven Decisions: Provides a systematic, rule-based approach to bid adjustments using yesterday’s performance data..

2. How the Script Works Workflow Overview

1- Configuration: The script is configured with:
  • A conversion threshold (maximum acceptable cost per conversion).
  • Bid adjustment percentages for both increases and decreases.
  • Minimum and maximum bid limits.
  • An impression minimum to ensure enough data is available
  • (Optional) A Google Sheet ID for logging bid adjustments
  • An email recipient for summary notifications.
2- Keyword Iteration and Data Extraction:
  • The script iterates over all active keywords.
  • It retrieves performance data from “YESTERDAY” (impressions, clicks, cost, and conversions).
  • Keywords with fewer than a defined number of impressions are skipped to avoid noise.
3- Bid Adjustment Logic:
  • With Conversions:
    • Calculates cost per conversion.
    • If the cost per conversion exceeds the threshold, the bid is decreased by a defined percentage.
    • If it is significantly lower than the threshold (less than 80% of the threshold), the bid is increased by a defined percentage.
  • Without Conversions:
    • If the cost is very high relative to the threshold, the bid is decreased.
  • The new bid is then capped between defined minimum and maximum bid values.
  • Bid changes are applied only if the adjustment is significant (at least a 5% change from the current bid).
4- Logging and Notification:
  • All bid adjustments are logged, with details including campaign, ad group, keyword text, old bid, new bid, and the reason for adjustment.
  • A summary email is sent to a designated recipient.
  • Optionally, the adjustments are logged to a Google Sheet if a SPREADSHEET_ID is provided.

3. Implementation Instructions

Step 1: Configure the Script Set Configuration Variables:
  • CONVERSION_THRESHOLD: Maximum acceptable cost per conversion.
  • BID_INCREASE_PERCENT / BID_DECREASE_PERCENT: The percentage to adjust bids.
  • MIN_BID / MAX_BID: Allowed bid boundaries.
  • IMPRESSION_MIN: Minimum impressions required for bid adjustments.
  • SPREADSHEET_ID: (Optional) Set this to your Google Sheet ID for logging; leave as an empty string if not used.
  • EMAIL_RECIPIENT: The email address that will receive the summary report.
Step 2: Set Up the Optional Google Sheet for Logging If you choose to log bid adjustments:
  • Create a New Google Sheet:
    • Open Google Sheets and create a new blank spreadsheet.
    • Name it (e.g., “Bid Adjustments Log“).
  • Set Up Headers in Row 1:
    • A1: Date
    • B1: Campaign
    • C1: Ad Group
    • D1: Keyword
    • E1: Old Bid
    • F1: New Bid
    • G1: Reason
  • Copy the Spreadsheet ID:
    • Extract the Spreadsheet ID from the URL and update SPREADSHEET_ID in the script.
Step 3: Set Up the Script in Google Ads
  • Access the Script Editor:
    • Log in to your Google Ads account.
    • Navigate to Tools and Settings → Bulk Actions → Scripts.
    • Click the “+” button to create a new script.
  • Paste the Code:
    • Copy the code provided below and paste it into the script editor.
  • Save and Authorize:
    • Save the script.
    • Click Preview to run the authorization flow and grant necessary permissions.
Step 4: Test the Script
  • Run in Preview Mode:
    • Execute the script with your current configuration.
    • Check the logs (using Logger.log()) to verify that:
      • Keywords with sufficient impressions are being processed.
      • Bid adjustments are calculated and logged correctly.
    • Confirm that the summary email is sent (if configured).
  • Verify in Google Ads:
    • Check your account to ensure that keyword bids are updated as expected.
  • Troubleshoot:
    • Review log outputs and adjust configuration values if necessary.
Step 5: Schedule the Script (Optional)
  • Automation:
    • Use the scheduling feature in the Google Ads Scripts interface to run the script automatically (e.g., daily) to continuously optimize keyword bids.

4. The Automatic Bidding Adjustments Script Code

    function main() {
  // *************** CONFIGURATION *********************
  var CONVERSION_THRESHOLD = 20; // Maximum acceptable cost per conversion
  var BID_INCREASE_PERCENT = 10;  // Increase bid by 10% if performing well
  var BID_DECREASE_PERCENT = 10;  // Decrease bid by 10% if underperforming
  var MIN_BID = 0.1;              // Minimum allowed bid (in account currency)
  var MAX_BID = 10;               // Maximum allowed bid (in account currency)
  var IMPRESSION_MIN = 100;       // Only adjust keywords with at least this many impressions (to avoid noise)
  var SPREADSHEET_ID = "your-spreadsheet-id"; // Google Sheet ID for logging; set to "" if not used
  // *************** END CONFIGURATION *********************

  var adjustmentsLog = [];
  
  // Iterate through all active keywords in the account
  var keywordIterator = AdsApp.keywords()
    .withCondition("Status = ENABLED")
    .get();
  
  while (keywordIterator.hasNext()) {
    var keyword = keywordIterator.next();
    var stats = keyword.getStatsFor("YESTERDAY");
    var impressions = stats.getImpressions();
    
    // Only adjust if the keyword has enough data
    if (impressions < IMPRESSION_MIN) continue;
    
    var conversions = stats.getConversions();
    var cost = stats.getCost();
    var currentBid = keyword.bidding().getCpc();
    var newBid = currentBid;
    var reason = "";
    
    // If there are conversions, calculate cost per conversion
    if (conversions > 0) {
      var costPerConversion = cost / conversions;
      if (costPerConversion > CONVERSION_THRESHOLD) {
        // Underperforming: decrease bid
        newBid = currentBid * (1 - BID_DECREASE_PERCENT / 100);
        reason = "High cost per conversion (" + costPerConversion.toFixed(2) + ")";
      } else if (costPerConversion < CONVERSION_THRESHOLD * 0.8) {
        // Strong performance: increase bid
        newBid = currentBid * (1 + BID_INCREASE_PERCENT / 100);
        reason = "Low cost per conversion (" + costPerConversion.toFixed(2) + ")";
      }
    } else {
      // If there are zero conversions but a high cost, lower the bid
      if (cost > CONVERSION_THRESHOLD * 2) {
        newBid = currentBid * (1 - BID_DECREASE_PERCENT / 100);
        reason = "Zero conversions with high cost (" + cost.toFixed(2) + ")";
      }
    }
    
    // Ensure the new bid is within allowed boundaries
    newBid = Math.max(MIN_BID, Math.min(newBid, MAX_BID));
    newBid = parseFloat(newBid.toFixed(2));
    
    // Update the bid only if the change is significant (e.g. 5% or more)
    if (Math.abs(newBid - currentBid) / currentBid >= 0.05) {
      keyword.bidding().setCpc(newBid);
      adjustmentsLog.push({
        campaignName: keyword.getCampaign().getName(),
        adGroupName: keyword.getAdGroup().getName(),
        keywordText: keyword.getText(),
        oldBid: currentBid.toFixed(2),
        newBid: newBid.toFixed(2),
        reason: reason
      });
      Logger.log("Adjusted bid for keyword '" + keyword.getText() + "' from " +
                 currentBid.toFixed(2) + " to " + newBid.toFixed(2) + ". " + reason);
    }
  }
  
  // Optionally log adjustments to a Google Sheet
  if (SPREADSHEET_ID && adjustmentsLog.length > 0) {
    try {
      var sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getActiveSheet();
      // Add header row if the sheet is empty
      if (sheet.getLastRow() === 0) {
        sheet.appendRow(["Date", "Campaign", "Ad Group", "Keyword", "Old Bid", "New Bid", "Reason"]);
      }
      var now = new Date();
      var dateString = now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate();
      
      adjustmentsLog.forEach(function(item) {
        sheet.appendRow([dateString, item.campaignName, item.adGroupName, item.keywordText, item.oldBid, item.newBid, item.reason]);
      });
      Logger.log("Bid adjustments successfully logged to Google Sheet.");
    } catch (e) {
      Logger.log("Error logging bid adjustments: " + e);
    }
  }
}
   
            
                    
        

5. Final Notes and Best Practices

  • Configuration:
    • Double-check that all configuration values (conversion threshold, bid percentages, impression minimum, min/max bid, etc.) are set appropriately for your account.
  • Testing:
    • Run the script in Preview mode and review the logs to confirm that bid adjustments are being calculated and applied correctly.
  • Boundaries:
    • Ensure that the new bid is always within your defined minimum and maximum bid limits.
  • Scheduling:
    • Schedule the script to run at regular intervals (e.g., daily) to continuously optimize bids based on the latest performance data.
  • Monitoring:
    • Regularly monitor your campaign performance after the adjustments are made to verify that the changes are improving your CPA.
  • Documentation:
    • Keep a version history of your script to track changes and facilitate future updates.