LW IT Solutions
« Blog Overview /Digital Marketing / Retencja danych Google Ads: 37 miesięcy danych...
This post in other languages:

Retencja danych Google Ads: 37 miesięcy danych o skuteczności i wznawialne zadanie backfill

Retencja danych Google Ads: 37 miesięcy danych o skuteczności i wznawialne zadanie backfill
Spis treści
  1. 1. Co naprawdę mówi strona o retencji danych Google Ads
  2. 2. Wyliczenie własnego terminu i ustalenie, co już przepadło
  3. 3. Zadanie backfill, które się wznawia
  4. 4. Cron, kolejność i rejestr strat
  5. 5. Podsumowanie
  6. Źródła

Od 1.06.2026 dane w Google Ads mają termin ważności. Dane o skuteczności są przechowywane przez 37 miesięcy, historia zmian na koncie przez 11 lat, dane Reach and Frequency przez 3 lata. Dziś jest 10.08.2026, więc najstarszy dzień z danymi o skuteczności, jaki da się jeszcze pobrać, to 10.07.2023 — a ta granica przesuwa się do przodu o jeden dzień każdego dnia. Jeżeli historia raportowania istnieje wyłącznie wewnątrz Google Ads, to po cichu ubywa jej po jednym dniu dziennie. Ten artykuł wykonuje potrzebne wyliczenia, prostuje liczby błędnie przytaczane przy okazji tej zmiany i buduje wznawialne zadanie backfill, które przenosi wszystko powyżej granicy do własnej hurtowni danych.

1. Co naprawdę mówi strona o retencji danych Google Ads

Udokumentowane są trzy okna — i tylko trzy:

  • 37 miesięcy dla danych o skuteczności.
  • 11 lat dla historii zmian na koncie.
  • 3 lata dla Reach and Frequency.

Większość omówień tej zmiany niesie ze sobą trzy dodatkowe liczby: 36 miesięcy dla GA Data API, 24 miesiące dla BigQuery Data Transfer Service, 24 miesiące dla DV360 i CM360. Tych wartości nie ma na stronie pomocy Google Ads, która ogłosiła okna retencji. W zakresie tego ogłoszenia pozostają nieudokumentowane, a powtarzanie ich tak, jakby stanowiły jego część, to dokładnie ten mechanizm, w którym plotka zamienia się w założenie planistyczne. Planowanie powinno opierać się na trzech powyższych wartościach. Jeżeli potrzebna jest wartość retencji dla GA4, dla transferów BigQuery albo dla DV360 i CM360, należy wziąć ją z dokumentacji danego produktu.

Jeden szczegół łatwo przeoczyć: 37 miesięcy to więcej niż trzy lata. Reach and Frequency wygasa zatem mniej więcej miesiąc przed danymi o skuteczności dotyczącymi tych samych kampanii. Przy zabezpieczaniu obu zbiorów to R&F ma krótszy termin, a nie dłuższy.

2. Wyliczenie własnego terminu i ustalenie, co już przepadło

Granica jest ruchoma, nie jest pojedynczym cięciem, które nastąpiło w czerwcu. Lepiej ją wyliczać, niż zapamiętywać:

from datetime import date
from dateutil.relativedelta import relativedelta

today = date(2026, 8, 10)
print(today - relativedelta(months=37))  # dane performance 2023-07-10
print(today - relativedelta(years=3))    # reach, frequency 2023-08-10
print(today - relativedelta(years=11))   # historia zmian   2015-08-10

Wszystko, co ma datę wcześniejszą niż 10.07.2023, jest już nie do odzyskania przez API. Jutro tą datą będzie 11.07.2023. Zanim powstanie jakikolwiek kod eksportu, warto ustalić, jaka część wciąż dostępnego zakresu faktycznie znajduje się w lokalnym zasobie. Dla hurtowni na Postgresie z tabelą dzienną:

WITH expected AS (
  SELECT generate_series(DATE '2023-07-10', CURRENT_DATE - 1, INTERVAL '1 day')::date AS d
)
SELECT count(*) AS missing_days, min(e.d) AS oldest_gap, max(e.d) AS newest_gap
FROM expected e
LEFT JOIN ads_daily a ON a.day = e.d
WHERE a.day IS NULL;

To samo zapytanie należy uruchomić z początkiem okna ustawionym na własny najwcześniejszy oczekiwany dzień. Wszystko, co zostanie zgłoszone poniżej 2023-07-10, to trwała dziura; wszystko powyżej to praca, którą wciąż da się wykonać.

Oś czasu z 37-miesięcznym oknem retencji, którego lewa krawędź przesuwa się codziennie, a starsze dane wypadają do samodzielnie hostowanego warehouse
Trzy limity, jedna ruchoma krawędź. Wszystko na lewo od niej już opuściło Google Ads. Zadanie eksportu ma więc sens tylko dopóki wyprzedza krawędź, a nie goni ją.

3. Zadanie backfill, które się wznawia

Nie będę tu drukował listy pól GAQL, ponieważ właściwa lista to ta, która jest już w użyciu. Zasób, segment daty i wybrane pola należy wziąć wprost z raportu uruchamianego dzisiaj, umieścić je w pliku konfiguracyjnym i pozostawić zadaniu wyłącznie okno dat:

{
  "customer_id": "1234567890",
  "dsn": "postgresql://ads@localhost/warehouse",
  "resource":   "<the resource your existing report reads>",
  "date_field": "<the date segment that report groups by>",
  "fields":     ["<field 1>", "<field 2>"],
  "query_template": "SELECT {fields} FROM {resource} WHERE {date_field} BETWEEN '{start}' AND '{end}'",
  "oldest_wanted": "2019-01-01"
}

Runner pobiera dokładnie jedno okno na wywołanie i je odnotowuje. Stan to cztery kolumny: customer_id, window_start, window_end, rows, zapisywane w tej samej transakcji co dane, więc awaria oznacza po prostu powtórzenie okna.

import json
from datetime import date, timedelta
from dateutil.relativedelta import relativedelta
import psycopg

CFG, CHUNK = json.load(open("/etc/ads-backfill/config.json")), timedelta(days=7)
CID = CFG["customer_id"]

def next_window(cur):
    cur.execute("SELECT max(window_end) FROM backfill_state WHERE customer_id = %s", (CID,))
    (last,) = cur.fetchone()
    floor = max(date.today() - relativedelta(months=37),
                date.fromisoformat(CFG["oldest_wanted"]))
    start = last + timedelta(days=1) if last else floor
    if start < floor:                    # zadanie stanęło, te dni wygasły
        cur.execute("INSERT INTO backfill_lost VALUES (%s, %s, %s)",
                    (CID, start, floor - timedelta(days=1)))
        start = floor
    end = min(start + CHUNK - timedelta(days=1), date.today() - timedelta(days=1))
    return (start, end) if start <= end else None

with psycopg.connect(CFG["dsn"]) as conn, conn.cursor() as cur:
    win = next_window(cur)
    if win:
        start, end = win
        rows = run_report(CID, CFG["query_template"].format(
            fields=", ".join(CFG["fields"]), resource=CFG["resource"],
            date_field=CFG["date_field"], start=start, end=end))
        cur.executemany(CFG["insert_sql"], rows)
        cur.execute("INSERT INTO backfill_state VALUES (%s, %s, %s, %s, now())",
                    (CID, start, end, len(rows)))
        conn.commit()

run_report to istniejący wrapper API, niezależnie od tego, jaką bibliotekę kliencką opakowuje. Cała reszta pliku działa po stronie lokalnej: własna konfiguracja, własna tabela, własne granice transakcji.

4. Cron, kolejność i rejestr strat

# /etc/cron.d/ads-backfill — jedno okno na godzinę, najstarsze najpierw
7 * * * * ads /opt/ads-backfill/.venv/bin/python /opt/ads-backfill/backfill.py >> /var/log/ads-backfill.log 2>&1

Dwie rzeczy w tym zadaniu są zamierzone. Idzie ono do przodu od granicy, a nie wstecz od dzisiaj, ponieważ tylko najstarsze dane mają termin; ostatnie dni mogą poczekać. A kiedy okazuje się, że granica wyprzedziła jego własny postęp, zadanie nie pomija po cichu luki, lecz zapisuje ten przedział do tabeli backfill_lost. Ta tabela jest uczciwą odpowiedzią na pytanie „których okresów już nie mamy” i warto umieścić ją na dashboardzie obok zapytania o luki z sekcji 2.

Arytmetyka jest wygodna. Od 10.07.2023 do wczoraj mija 1126 dni, czyli 161 okien po siedem dni. Przy jednym oknie na godzinę daje to niecałe siedem dni czasu rzeczywistego, w trakcie których granica przesuwa się o siedem dni: na każdy utracony dzień historii przypada 168 dni zyskanych. Po zamknięciu zaległości to samo zadanie utrzymuje bieżący koniec zakresu w aktualności i kosztuje jedno wywołanie API na godzinę.

5. Podsumowanie

Powstała granica, którą się wylicza zamiast zapamiętywać, zapytanie wskazujące, których dni z wciąż dostępnego okna brakuje w hurtowni, runner obsługujący jedno okno, który czysto wznawia się po awarii i sam dostosowuje się do bieżącego odcięcia, godzinowy wpis w cronie oraz rejestr okresów będących już poza zasięgiem. Całe zaległości od 10.07.2023 zamykają się w mniej więcej tydzień pracy bez nadzoru, po czym zadanie przechodzi w tryb utrzymaniowy.

Zyskiem jest to, że historia raportowania przestaje być cudzą polityką retencji. Porównania rok do roku, modele sezonowości i przebudowy atrybucji prędzej czy później potrzebują danych starszych niż 37 miesięcy, a po 1.06.2026 jedyną wciąż istniejącą kopią będzie ta przechowywana lokalnie. Trzy udokumentowane okna warto potwierdzić w źródle pierwotnym i zignorować krążące obok nich dodatkowe liczby: polityka retencji danych Google Ads.

Lukas Wojcik

Lukas Wojcik

Systems architect and technology enthusiast specializing in scalable tracking solutions, GMP Stack (GA4 & GTM), and robust backend architectures. Advocate for clean code and privacy-first design.

Get in Touch

Briefly describe your project or inquiry for a tailored response. This site is protected by reCAPTCHA.

Komentarze: 2

  1. Torsten Bahlmann

    Rachunek na końcu jest przekonujący: sto sześćdziesiąt osiem dni historii zyskanych na każdy jeden utracony to argument, który kończy dyskusję o priorytetach.

    Skoro jednak granica przesuwa się codziennie, dlaczego zadanie pobiera tylko jedno okno na godzinę? Uruchomienie go w pętli skończyłoby zaległości w jedną noc.

    1. Lukas Wojcik Autor

      Skończyłoby, i właśnie dlatego to niepotrzebne — z rachunku wynika, że wyścigu nie ma. Przy jednym oknie na godzinę zaległości domykają się w niecały tydzień, a granica przesuwa się w tym czasie o siedem dni. Nic nie ucieka.

      Powolne tempo kupuje natomiast dwie rzeczy. Nie zużywa limitów API na tyle, żeby przeszkodzić raportom, które i tak działają w tle — a to one zwykle padają pierwsze, gdy ktoś uruchomi masowe pobieranie. I daje czas na zauważenie błędu: jeżeli okno pobiera się z niepełnymi polami albo z pomyłką w konfiguracji, przy jednym oknie na godzinę problem obejmuje kilka dni historii, a nie cztery lata.

      Warto tylko obserwować jedną liczbę: rosnącą tabelę utraconych zakresów. Jeżeli zadanie stanie na kilka dni — z powodu wygasłego tokenu albo restartu serwera — granica dogoni jego postęp i wtedy tempo przestaje być wystarczające. To jedyny scenariusz, w którym warto przyspieszyć, i wtedy widać go w danych, a nie w domysłach.

Napisanie komentarza

Adres e-mail nie jest publikowany. Pola obowiązkowe oznaczono gwiazdką.

ALL ARTICLES & CATEGORIES

CCTV

Śledź tę kategorię przez RSS

Cloud & AI

Śledź tę kategorię przez RSS

Data Privacy

Wszystkie artykuły w tej kategorii (11) Śledź tę kategorię przez RSS

Digital Analytics

Wszystkie artykuły w tej kategorii (43) Śledź tę kategorię przez RSS

Digital Marketing

Wszystkie artykuły w tej kategorii (25) Śledź tę kategorię przez RSS

IT & Networks

Wszystkie artykuły w tej kategorii (15) Śledź tę kategorię przez RSS

Raspberry Pi

Śledź tę kategorię przez RSS

Smart Home

Wszystkie artykuły w tej kategorii (11) Śledź tę kategorię przez RSS

Tworzenie stron internetowych

Śledź tę kategorię przez RSS

Wtyczki i triki WordPress

Śledź tę kategorię przez RSS