Hoppa till innehåll
Google Marknadsföring Script

Så optimerar du Google Ads med Target ROAS för e-handel (inkl Script)

Emil Franzén
Emil Franzén |

Att använda Target ROAS (målavkastning på annonskostnad) i Google Ads för e-handel är rekommenderat – men många kämpar med långa inlärningsperioder och oväntade prestationsdippar. Här får du konkreta råd för att förbättra resultaten, stabilisera prestandan och växa hållbart!

Hur ofta och hur mycket bör du ändra din Target ROAS?

När du justerar din ROAS-målsättning tvingar du Googles algoritm att börja om sin inlärning. Därför är det bäst att:

1. Ändra max 20–30 % åt gången.

Till exempel, om din nuvarande ROAS är 400 %, ändra inte till mer än 480–520 %.

2. Låt algoritmen arbeta 2–4 veckor

Innan du gör nästa justering för att låta algoritmerna få tid på sig att justera.

Varje gång du gör en större ändring tar det tid för Google att optimera igen. Därför är det smart att gradvis och metodiskt justera snarare än att chansa stort.

Så använder du Performance Max tillsammans med sökkampanjer

En optimal kampanjstruktur för e-handel brukar bestå av tre delar:

  • Brand-kampanj: Isolerad och med låg ROAS-målsättning för maximal synlighet.

  • Generisk sökkampanj: Fokuserar på viktiga icke-varumärkesrelaterade sökord med något högre ROAS-mål.

  • Performance Max: Kompletterar och fångar upp allt annat, särskilt nya kunder över flera kanaler.

Se till att lägga till negativa sökord (framförallt varumärkestermer) i Performance Max för att undvika intern konkurrens.

Så hanterar du budgetändringar smart

För att undvika prestationsdippar när budgeten ändras:

  • Höj budgeten gradvis (10–20 % per gång).

  • Undvik att ändra både budget och ROAS-mål samtidigt.

  • Vänta alltid tills resultaten stabiliseras innan nästa justering.

 

Avancerade taktiker för ökad effektivitet

Här är några extra knep för att maximera effektiviteten:

  • Segmentera kampanjer efter marginal eller produktkategori: Anpassa ROAS-målet utifrån marginaler.

  • Använd Conversion Value Rules: Anpassa värdet på konverteringar efter kundtyp, region eller produktkategori.

  • Leverera tydliga målgruppssignaler till Performance Max med hjälp av kundlistor och anpassade segment för snabbare och bättre optimering.

  • Testa kontinuerligt annonsmaterial för att förbättra annonsrelevansen och klickfrekvensen.

Automatisera ROAS-uppdateringar med ett Google Ads-script

För att ytterligare optimera och automatisera dina Target ROAS-justeringar kan du använda följande script. Scriptet uppdaterar ROAS baserat på den frekvens och period som väljs. Ett optimalt exempel är att använda en frekvens på 30 dagar samt låta parametern lookbackPeriod vara 30 dagar. Observera att användningen sker på egen risk, och Searchbase friskriver sig allt ansvar vid användning.

Så fungerar scriptet:

  • lookbackPeriod: Bestämmer tidsperioden scriptet ska använda för att analysera data, exempelvis de senaste 30 dagarna (LAST_30_DAYS).

  • adjustmentFactor: Bestämmer hur aggressivt målet justeras mot faktisk ROAS. Ett värde på 0.1 innebär 10 % av skillnaden.

  • offsetMultiplier: Säkerställer att nya ROAS-målet aldrig är lägre än den uppmätta faktiska ROAS multiplicerat med säkerhetsmarginalen (t.ex. 1.10)

Viktigt! Det går i nuläget inte att låta ett script uppdatera Target ROAS för Shopping-kampanjer. I loggarna går det däremot att få ut en sammanställning på önskvärd Target ROAS som man istället får uppdatera manuellt. Använd scriptet på egen risk, Searchbase friskriver sig allt ansvar vid användning.


// CONFIGURATION
var CONFIG = {
  lookbackPeriod: "LAST_30_DAYS",  // e.g. LAST_7_DAYS, LAST_30_DAYS
  adjustmentFactor: 0.1,           // Adjust by 10% of the difference
  offsetMultiplier: 1.10           // Minimum target ROAS = performance ROAS * 1.10
};

function main() {
  // Get campaign performance data via AWQL report
  var reportQuery = "SELECT CampaignId, CampaignName, Cost, ConversionValue " +
                    "FROM CAMPAIGN_PERFORMANCE_REPORT " +
                    "DURING " + CONFIG.lookbackPeriod;
  var report = AdsApp.report(reportQuery);
  var rows = report.rows();
  var campaignData = {};
  
  while (rows.hasNext()) {
    var row = rows.next();
    // Remove commas from number strings before parsing
    var cost = parseFloat(row["Cost"].replace(/,/g, ""));
    var conversionValue = parseFloat(row["ConversionValue"].replace(/,/g, ""));
    
    campaignData[row["CampaignId"]] = {
      name: row["CampaignName"],
      cost: cost,
      conversionValue: conversionValue
    };
  }
  
  // Process Standard campaigns
  processCampaigns(AdsApp.campaigns().withCondition("Status = 'ENABLED'").get(), campaignData, "Standard");
  
  // Process Performance Max campaigns
  if (typeof AdsApp.performanceMaxCampaigns === "function") {
    processCampaigns(AdsApp.performanceMaxCampaigns().withCondition("Status = 'ENABLED'").get(), campaignData, "Performance Max");
  } else {
    Logger.log("Performance Max campaigns not accessible.");
  }
  
  // Process Shopping campaigns
  if (typeof AdsApp.shoppingCampaigns === "function") {
    processCampaigns(AdsApp.shoppingCampaigns().withCondition("Status = 'ENABLED'").get(), campaignData, "Shopping");
  } else {
    Logger.log("Shopping campaigns not accessible.");
  }
}

function processCampaigns(campaignIterator, campaignData, groupName) {
  var notUpdatedCampaigns = [];
  
  while (campaignIterator.hasNext()) {
    var campaign = campaignIterator.next();
    var data = campaignData[campaign.getId()];
    
    if (!data) {
      Logger.log("No data for campaign: " + campaign.getName());
      continue;
    }
    
    if (data.cost <= 0) {
      Logger.log("Skipping " + campaign.getName() + " due to zero cost.");
      continue;
    }
    
    // Calculate performance ROAS as conversionValue/cost, scaled to percentage
    var performanceRoas = (data.conversionValue / data.cost) * 100;
    
    try {
      var bidding = campaign.bidding();
      if (typeof bidding.getTargetRoas === "function") {
        var currentTargetRoas = bidding.getTargetRoas();
        // Gradually adjust target ROAS toward performance ROAS
        var newTargetRoas = currentTargetRoas + CONFIG.adjustmentFactor * (performanceRoas - currentTargetRoas);
        // Ensure new target is never below performanceRoas * offsetMultiplier
        newTargetRoas = Math.max(newTargetRoas, performanceRoas * CONFIG.offsetMultiplier);
        
        Logger.log("Campaign: " + campaign.getName() +
                   " | Performance ROAS: " + performanceRoas.toFixed(2) +
                   " | Current Target ROAS: " + currentTargetRoas.toFixed(2) +
                   " | New Target ROAS: " + newTargetRoas.toFixed(2));
        
        if (Math.abs(newTargetRoas - currentTargetRoas) > 0.01) {
          bidding.setTargetRoas(newTargetRoas);
          // Check if the update took effect by reading back the target ROAS
          var updatedTargetRoas = bidding.getTargetRoas();
          if (Math.abs(updatedTargetRoas - newTargetRoas) > 0.01) {
            notUpdatedCampaigns.push(campaign.getName());
            Logger.log("Warning: " + campaign.getName() + " may not support target ROAS updates due to locked bidding strategy.");
          } else {
            Logger.log("Updated Target ROAS for " + campaign.getName());
          }
        }
      } else {
        Logger.log("Campaign " + campaign.getName() + " doesn't support Target ROAS bidding.");
      }
    } catch (e) {
      Logger.log("Error processing " + campaign.getName() + ": " + e);
    }
  }
  
  if (notUpdatedCampaigns.length > 0) {
    Logger.log("Summary (" + groupName + "): The following campaigns might not have updated target ROAS due to bidding strategy limitations: " + notUpdatedCampaigns.join(", "));
    Logger.log("These campaigns employ a TARGET_ROAS bidding strategy that may lock out manual updates.");
  }
}

  

Får nyheter och tips direkt i mailkorgen, prenumera genom att skriva in din mail nedan:

Dela detta inlägg