DOŁĄCZ DO GRUPY
BEZPŁATNY AUDYT
SKRYPT PMAX
NEWSLETTER

Zaawansowane Google Ads

5,001 członków

Dołącz do naszej społeczności ekspertów Google Ads i zyskaj dostęp do zaawansowanych strategii, wsparcia specjalistów i inspirujących case studies.

Prywatna grupa - Tylko zatwierdzeni członkowie

Nie jesteś pewny, czy Twoje reklamy działają tak, jak powinny?

Umów się na bezpłatny audyt konta Google Ads

Profesjonalna analiza

Szybki kontakt i konkretne informacje zwrotne.

Analiza efektywności
Weryfikacja Strategii
Praktyczne rekomendacje
Propozycja współpracy

Chcesz lepiej zrozumieć działanie kampanii Performance Max?

PMax Channels Analyzer

Darmowy skrypt dla Google Ads

Analizuj wydatki i konwersje z poszczególnych kanałów w kampaniach Performance Max.

Podział na kanały
Szczegółowe statystyki
Łatwa instalacja
Automatyczne raporty

Zapisz się na newsletter i otrzymuj praktyczne porady oraz narzędzia, które usprawnią twoje konto reklamowe.

Skrypt Google Ads: Bingalizer

Bingalizer to skrypt Google Ads, który automatycznie analizuje dane z kampanii produktowych (Performance Max + Shopping) i znajduje produkty o najwyższym ROAS oraz największej liczbie konwersji.

Na podstawie wyników przypisuje im dedykowane etykiety (custom labels) w arkuszu Google Sheets. Tak, aby można je było szybko wyodrębnić, filtrować, tworzyć dedykowane kampanie lub wykorzystać w innych systemach reklamowych, np. Microsoft Advertising (Bing Ads – stąd też nazwa).

Dzięki temu w prosty sposób możesz:

reklama Google Ads wciąż działa najlepiej
  • wyselekcjonować najlepiej działające produkty w swoim sklepie
  • przenieść je do kampanii z wyższymi budżetami (np. jako optymalizacja poza sezonem)
  • stworzyć lustrzane kampanie w Bing Ads oparte tylko na tym, co działa w Google

Kluczowe korzyści:

Dane z kampanii Google Ads mogą być dobrym punktem wyjścia do optymalizacji także w innych kanałach sprzedaży. Produkty osiągające wysoki ROAS w Google często mają zbliżone wyniki w Bing Ads.

Jednak sam algorytm w Google Ads, moim zdaniem, działa o wiele lepiej: dużo szybciej znajduje odpowiednie produkty i efektywniej wykorzystuje budżet. Szczególnie mam tutaj na myśli automatyczne ustalanie stawek. Mam wrażenie, że w Bing Ads czas się zatrzymał i mimo upływu lat, wciąż nie widzę tam postępu.

W praktyce skrypt ten wykorzystuję również do budowania innych struktur w Google Ads – ale o tym być może w innym wpisie.

Jak działa Bingalizer?

Bingalizer pobiera dane z wybranego okresu, odfiltrowuje produkty z niską liczbą kliknięć lub wyświetleń, usuwa te bez konwersji i sortuje wyniki według ROAS oraz liczby sprzedaży. Na koniec automatycznie przypisuje etykiety „TopRoas” i „TopConv”, dzięki czemu od razu widać, które produkty warto promować dalej.

Zalecana struktura do testów w Bing Ads

Przede wszystkim rozwiązanie to można przetestować bez większych ingerencji w obecne struktury kampanii w Bing Ads. Zalecam dodanie nowej kampanii zakupowej (klasycznej, nie PMax), ustawienie w niej większego priorytetu i wybór produktów z etykietą TopRoas i TopConv.

Warto też upewnić się, czy dotychczasowe kampanie mają niższy priorytet.

Taki układ pozwoli na testy bez potrzeby wykluczania nowych produktów ze starych kampanii.
Zwykle w pierwszej kolejności testuję ręczne ustalanie stawek i obie etykiety w jednej kampanii. Dalej przechodzę do podziału na dwie kampanie (osobno TopRoas i TopConv) oraz testów automatycznych stawek.

Konfiguracja skryptu:

  1. SPREADSHEET_URL
    Podajemy link do arkusza Google Sheets, w którym mają zostać zapisane wyniki.
    Skrypt zapisze dane automatycznie na pierwszym arkuszu (sheet) w pliku.
  2. DATE_RANGE_DAY
    Określamy liczbę dni, które mają zostać przeanalizowane wstecz (np. 30).
    Dzięki temu można łatwo kontrolować zakres danych. Krótszy dla bieżących trendów, dłuższy dla analizy sezonowej.
  3. MIN_CLICKS i MIN_IMPRESSIONS
    Ustalamy minimalne progi dla liczby kliknięć i wyświetleń, aby odfiltrować produkty z małą ilością danych.
  4. MIN_CONV_FOR_ROAS
    Minimalna liczba konwersji wymagana, aby produkt został uwzględniony przy analizie ROAS. Dzięki temu unikamy przypadków z pojedynczymi transakcjami, które mogłyby generować wysoki ROAS.
  5. MIN_CONV_FOR_CONV
    Minimalna liczba konwersji, aby produkt został uwzględniony w zestawieniu TopConv.
    Domyślnie: 1, czyli skrypt automatycznie pomija pozycje z zerową liczbą konwersji.
  6. TOP_N_PER_LIST
    Określa, ile produktów ma zostać oznaczonych jako najlepsze w każdej kategorii: ROAS i CONV. Domyślnie: 70 produktów z każdej listy.
  7. LABEL_ROAS / LABEL_CONV
    Nazwy etykiet, jakie zostaną przypisane produktom w arkuszu.
  8. CUSTOM_LABEL_INDEX
    Określa, do którego pola Custom Label (0–4) ma być przypisana etykieta w feedzie produktowym.

W pierwszej chwili może się wydawać, że konfiguracja jest skomplikowana.
W praktyce wystarczy tylko zmienić zakres dni (jeśli np. 30 w Twojej branży to za mało) oraz custom label, który chcemy użyć – tak, aby nie nadpisać obecnie używanych.

Na koniec dodaj ten arkusz jako dodatkowe źródło danych w Merchant Center.
Dzięki temu informacje o etykietach zostaną zapisane w Google Ads.
Będą również widoczne w Bing Ads (o ile importujesz dane bezpośrednio z Google).

Miłego testowania!

Skopiuj poniższy kod i wklej na poziomie pojedynczego konta (nie działa z poziomu MCK).

/*
Copyright 2025 Krzysztof Bycina, www.LiveAds.pl
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// =========================
// PODSTAWOWA KONFIGURACJA
// =========================
// Wypełnij tylko te pola, aby uruchomić skrypt

var SPREADSHEET_URL    = "https://docs.google.com/spreadsheets/d/12345/edit"; // link do arkusza Google Sheets
var DATE_RANGE_DAYS    = 30;    // ile dni wstecz analizować
var TOP_N_PER_LIST     = 70;    // ile top produktów z każdej listy (ROAS / CONV)
var CUSTOM_LABEL_INDEX = 4;     // DO WYBORU: 0, 1, 2, 3 lub 4 (custom label w feedzie)

// =========================
// DODATKOWA KONFIGURACJA
// =========================
// Parametry opcjonalne – możesz dostosować, jeśli chcesz precyzyjniej filtrować dane

var MIN_CLICKS         = 10;    // minimalna liczba kliknięć, by produkt był analizowany
var MIN_IMPRESSIONS    = 100;   // minimalna liczba wyświetleń
var MIN_CONV_FOR_ROAS  = 3;     // min. liczba konwersji, by liczyć ROAS
var MIN_CONV_FOR_CONV  = 1;     // min. liczba konwersji, by trafić do listy TopConv
var LABEL_ROAS         = "TopRoas"; // nazwa etykiety dla najlepszych wg ROAS
var LABEL_CONV         = "TopConv"; // nazwa etykiety dla najlepszych wg konwersji

// =========================
// KONIEC KONFIGURACJI
// =========================
// Poniżej nic nie zmieniaj

function main() {
  if (CUSTOM_LABEL_INDEX < 0 || CUSTOM_LABEL_INDEX > 4) {
    throw new Error("CUSTOM_LABEL_INDEX musi być liczbą 0–4.");
  }

  var currency = AdWordsApp.currentAccount().getCurrencyCode(); 
  var data1 = fetchData(DATE_RANGE_DAYS);
  var filtered = filterByClicksAndImpressions(data1, MIN_CLICKS, MIN_IMPRESSIONS);
  var roasSorted = getSortedROAS(filtered, MIN_CONV_FOR_ROAS);
  var convSorted = getSortedCONV(filtered, MIN_CONV_FOR_CONV);
  var combined = buildUniqueTop(roasSorted, convSorted, TOP_N_PER_LIST, LABEL_ROAS, LABEL_CONV);
  writeToSheet(combined, CUSTOM_LABEL_INDEX, currency);
}

function fetchData(daysBack) {
  var now = new Date();
  var start = new Date(now.getFullYear(), now.getMonth(), now.getDate() - daysBack);
  var tz = AdWordsApp.currentAccount().getTimeZone();
  var dStart = Utilities.formatDate(start, tz, 'yyyyMMdd');
  var dEnd = Utilities.formatDate(now, tz, 'yyyyMMdd');

  var query =
    "SELECT OfferId, Impressions, Clicks, Ctr, Cost, Conversions, ConversionValue " +
    "FROM SHOPPING_PERFORMANCE_REPORT " +
    "DURING " + dStart + "," + dEnd;

  var out = [];
  var rows = AdWordsApp.report(query).rows();
  while (rows.hasNext()) {
    var row = rows.next();
    var id = String(row['OfferId'] || '').toLowerCase();
    var cost = parseFloat(String(row['Cost']).replace(",", "").replace("€", "").trim()) || 0;
    var conv = parseFloat(String(row['Conversions']).replace(",", "")) || 0;
    var convVal = parseFloat(String(row['ConversionValue']).replace(",", "").replace("€", "").trim()) || 0;

    var cpa  = (conv > 0) ? (cost / conv) : 0;
    var roas = (cost > 0) ? (convVal / cost) : 0;

    out.push({
      id: id,
      impressions: parseInt(row['Impressions'], 10) || 0,
      clicks: parseInt(row['Clicks'], 10) || 0,
      cost: cost,
      conversions: conv,
      conversionValue: convVal,
      cpa: cpa,
      roas: roas
    });
  }
  return out;
}

function filterByClicksAndImpressions(data, minClicks, minImpressions) {
  return data.filter(function (x) {
    return x.clicks >= minClicks && x.impressions >= minImpressions;
  });
}

function getSortedROAS(data, minConv) {
  var copy = data.slice().filter(function (x) { return x.conversions >= minConv; });
  copy.sort(function (a, b) { return b.roas - a.roas; });
  return copy;
}

function getSortedCONV(data, minConvForConv) {
  var copy = data.slice().filter(function (x) { return x.conversions >= minConvForConv; });
  copy.sort(function (a, b) {
    if (b.conversions !== a.conversions) return b.conversions - a.conversions;
    if (b.roas !== a.roas) return b.roas - a.roas;
    return b.clicks - a.clicks;
  });
  return copy;
}

function buildUniqueTop(roasSorted, convSorted, topNPerList, labelROAS, labelCONV) {
  var TARGET_UNIQUE = topNPerList * 2;
  var i = 0, j = 0;
  var takenFromRoas = 0, takenFromConv = 0;
  var seen = {};
  var out = [];

  while (out.length < TARGET_UNIQUE && (i < roasSorted.length || j < convSorted.length)) {
    if (takenFromRoas < topNPerList && i < roasSorted.length) {
      var r = roasSorted[i++];
      if (!seen[r.id]) {
        seen[r.id] = true;
        var rr = Object.assign({}, r);
        rr.finalLabel = labelROAS;
        out.push(rr);
        takenFromRoas++;
        if (out.length >= TARGET_UNIQUE) break;
      }
      continue;
    }
    if (takenFromConv < topNPerList && j < convSorted.length) {
      var c = convSorted[j++];
      if (!seen[c.id]) {
        seen[c.id] = true;
        var cc = Object.assign({}, c);
        cc.finalLabel = labelCONV;
        out.push(cc);
        takenFromConv++;
        if (out.length >= TARGET_UNIQUE) break;
      }
      continue;
    }
    if (takenFromRoas >= topNPerList && j < convSorted.length) {
      var c2 = convSorted[j++];
      if (!seen[c2.id]) {
        seen[c2.id] = true;
        var cc2 = Object.assign({}, c2);
        cc2.finalLabel = labelCONV;
        out.push(cc2);
      }
      continue;
    }
    if (takenFromConv >= topNPerList && i < roasSorted.length) {
      var r2 = roasSorted[i++];
      if (!seen[r2.id]) {
        seen[r2.id] = true;
        var rr2 = Object.assign({}, r2);
        rr2.finalLabel = labelROAS;
        out.push(rr2);
      }
      continue;
    }
    break;
  }
  return out;
}

function writeToSheet(data, customLabelIndex, currency) {
  var ss = SpreadsheetApp.openByUrl(SPREADSHEET_URL);
  var sheet = ss.getSheets()[0]; // pierwszy arkusz
  var customLabelHeader = "custom label " + customLabelIndex;

  var headers = [[
    'id',
    'Impressions',
    'Clicks',
    'Cost (' + currency + ')',
    'Conversions',
    'ConversionValue (' + currency + ')',
    'CPA (' + currency + ')',
    'ROAS',
    customLabelHeader
  ]];

  var output = headers.concat(data.map(function (item) {
    var cost = Number(item.cost);
    var conv = Number(item.conversions);
    var convVal = Number(item.conversionValue);
    var cpa = Number(item.cpa);
    var roas = Number(item.roas);

    return [
      item.id,
      item.impressions,
      item.clicks,
      round2(cost),
      round2(conv),
      round2(convVal),
      round2(cpa),
      round2(roas),
      item.finalLabel || ''
    ];
  }));

  sheet.clear();
  if (output.length > 0) {
    var range = sheet.getRange(1, 1, output.length, output[0].length);
    range.setValues(output);
    if (output.length >= 2) {
      sheet.getRange(2, 4, output.length - 1, 1).setNumberFormat("0.00");
      sheet.getRange(2, 6, output.length - 1, 1).setNumberFormat("0.00");
      sheet.getRange(2, 7, output.length - 1, 1).setNumberFormat("0.00");
      sheet.getRange(2, 8, output.length - 1, 1).setNumberFormat("0.00");
    }
  }
}

function round2(n) {
  return Math.round((n + Number.EPSILON) * 100) / 100;
}

Freelancer Google Ads z doświadczeniem w e-commerce

    Sprawdzę Twoje konto i przygotuję propozycję współpracy


    Możesz też zobaczyć moją pełną
    ofertę freelancera Google Ads

    📞 Telefon: 600 631 101 lub e-mail:


    Imię

    Adres e-mail

    Wiadomość