LW IT Solutions
« Blog Overview /Digital Marketing / 37 Monate und Schluss: Google-Ads-Daten verfallen jetzt...
This post in other languages:

37 Monate und Schluss: Google-Ads-Daten verfallen jetzt nach Fahrplan

Inhalt
  1. 1. Was auf der Seite zur Datenaufbewahrung tatsächlich steht
  2. 2. Die eigene Frist ausrechnen – und herausfinden, was schon weg ist
  3. 3. Ein Backfill-Job, der wieder aufsetzt
  4. 4. Cron, Reihenfolge und das Verlustregister
  5. 5. Zusammenfassung

Seit dem 01.06.2026 haben Google-Ads-Daten ein Verfallsdatum. Leistungsdaten werden 37 Monate aufbewahrt, der Änderungsverlauf eines Kontos 11 Jahre, Reach-and-Frequency-Daten 3 Jahre. Heute ist der 10.08.2026, der älteste Leistungstag, den Sie noch abrufen können, ist damit der 10.07.2023 – und diese Linie rückt jeden Tag um einen Tag weiter. Wenn Ihre Reporting-Historie ausschließlich in Google Ads liegt, verlieren Sie davon still und leise pro Tag einen Tag. Dieser Artikel rechnet das durch, korrigiert die Zahlen, die im selben Atemzug falsch zitiert werden, und baut einen wiederaufnehmbaren Backfill-Job, der alles oberhalb der Linie in Ihr eigenes Warehouse holt.

1. Was auf der Seite zur Datenaufbewahrung tatsächlich steht

Dokumentiert sind drei Zeiträume – und nur diese drei:

  • 37 Monate für Leistungsdaten.
  • 11 Jahre für den Änderungsverlauf des Kontos.
  • 3 Jahre für Reach and Frequency.

In den meisten Beiträgen zu dieser Änderung tauchen drei weitere Zahlen mit auf: 36 Monate für die GA Data API, 24 Monate für den BigQuery Data Transfer Service, 24 Monate für DV360 und CM360. Diese Werte stehen nirgends auf der Google-Ads-Hilfeseite, die die Aufbewahrungsfristen angekündigt hat. Im Rahmen dieser Ankündigung sind sie schlicht undokumentiert – und wer sie weitergibt, als gehörten sie dazu, macht aus einem Gerücht eine Planungsgrundlage. Planen Sie mit den drei Werten oben. Wenn Sie eine Aufbewahrungsfrist für GA4, für BigQuery-Transfers oder für DV360 und CM360 brauchen, holen Sie sie aus der Dokumentation des jeweiligen Produkts.

Ein Detail wird leicht überlesen: 37 Monate sind länger als drei Jahre. Reach and Frequency verfällt deshalb rund einen Monat vor den Leistungsdaten zu denselben Kampagnen. Wenn Sie beides sichern, hat R&F die knappere Frist, nicht die großzügigere.

2. Die eigene Frist ausrechnen – und herausfinden, was schon weg ist

Die Grenze ist rollierend, kein einmaliger Schnitt im Juni. Rechnen Sie sie aus, statt sie sich zu merken:

from datetime import date
from dateutil.relativedelta import relativedelta

today = date(2026, 8, 10)
print(today - relativedelta(months=37))  # Leistungsdaten      2023-07-10
print(today - relativedelta(years=3))    # Reach and Frequency 2023-08-10
print(today - relativedelta(years=11))   # Änderungsverlauf    2015-08-10

Alles, was vor dem 10.07.2023 liegt, ist über die API bereits nicht mehr zu retten. Morgen ist es alles vor dem 11.07.2023. Bevor Sie eine Zeile Export-Code schreiben, sollten Sie wissen, wie viel des noch verfügbaren Zeitraums Sie tatsächlich vorliegen haben. Gegen ein Postgres-Warehouse mit einer Tagestabelle:

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;

Lassen Sie dieselbe Abfrage noch einmal laufen, diesmal mit Ihrem eigenen frühesten erwarteten Tag als Fensterbeginn. Alles, was sie unterhalb von 2023-07-10 meldet, ist ein dauerhaftes Loch; alles darüber ist Arbeit, die Sie noch erledigen können.

Eine Zeitachse mit einem 37-Monate-Fenster, dessen linke Kante täglich wandert und ältere Daten in ein selbstgehostetes Warehouse fallen lässt
Drei Fristen, eine wandernde Kante. Alles links davon hat Google Ads bereits verlassen. Der Export-Job nützt deshalb nur, solange er der Kante vorausläuft statt hinterher.

3. Ein Backfill-Job, der wieder aufsetzt

Eine GAQL-Feldliste drucke ich hier nicht ab, denn die richtige ist die, die Sie ohnehin schon verwenden. Nehmen Sie die Resource, das Datumssegment und die ausgewählten Felder direkt aus dem Report, den Sie heute fahren, legen Sie sie in eine Config-Datei – und lassen Sie dem Job nichts als Eigentum außer dem Datumsfenster:

{
  "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"
}

Der Runner holt pro Aufruf genau ein Fenster und schreibt es fest. Der State besteht aus vier Spalten: customer_id, window_start, window_end, rows, geschrieben in derselben Transaktion wie die Daten – ein Absturz wiederholt also einfach das Fenster.

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:                    # Job hing fest, diese Tage sind verfallen
        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 ist Ihr vorhandener API-Wrapper, gleich welche Client-Bibliothek darunter liegt. Alles Übrige in der Datei arbeitet auf Ihrer Seite der Linie: Ihre Config, Ihre Tabelle, Ihre Transaktionsgrenze.

4. Cron, Reihenfolge und das Verlustregister

# /etc/cron.d/ads-backfill — ein Fenster pro Stunde, ältestes zuerst
7 * * * * ads /opt/ads-backfill/.venv/bin/python /opt/ads-backfill/backfill.py >> /var/log/ads-backfill.log 2>&1

Zwei Dinge an diesem Job sind Absicht. Er läuft von der Grenze aus vorwärts, nicht von heute aus rückwärts, denn nur die ältesten Daten haben eine Frist; die jüngsten Tage können warten. Und wenn er feststellt, dass die Grenze seinen eigenen Fortschritt überholt hat, überspringt er die Lücke nicht stillschweigend, sondern schreibt den Zeitraum in backfill_lost. Diese Tabelle ist die ehrliche Antwort auf die Frage „Welche Zeiträume haben wir nicht mehr?“ – und sie gehört auf ein Dashboard, direkt neben die Lückenabfrage aus Abschnitt 2.

Die Rechnung ist entspannt. Vom 10.07.2023 bis gestern sind es 1.126 Tage, also 161 Fenster zu je sieben Tagen. Bei einem Fenster pro Stunde sind das keine sieben Tage reale Laufzeit, in denen die Grenze um sieben Tage weiterrückt: Sie gewinnen 168 Tage Historie für jeden einzelnen, den Sie verlieren. Ist der Rückstand einmal abgearbeitet, hält derselbe Job das hintere Ende aktuell und kostet einen API-Call pro Stunde.

5. Zusammenfassung

Sie haben jetzt eine Grenze, die Sie berechnen statt sie sich zu merken, eine Abfrage, die Ihnen sagt, welche Tage innerhalb des noch verfügbaren Fensters in Ihrem Warehouse fehlen, einen Runner für jeweils ein Fenster, der nach einem Absturz sauber wieder aufsetzt und sich selbst auf den aktuellen Cutoff begrenzt, einen stündlichen Cron-Eintrag und ein Register der Zeiträume, die bereits verloren sind. Der gesamte Rückstand ab dem 10.07.2023 ist nach rund einer Woche unbeaufsichtigtem Betrieb abgearbeitet; danach wird der Job zur reinen Wartungsaufgabe.

Der Gewinn: Ihre Reporting-Historie hängt nicht länger an der Aufbewahrungsrichtlinie eines anderen. Jahresvergleiche, Saisonalitätsmodelle und Attributions-Rebuilds brauchen früher oder später Daten, die älter als 37 Monate sind, und nach dem 01.06.2026 existiert davon nur noch die Kopie, die Sie selbst vorhalten. Prüfen Sie die drei dokumentierten Fristen in der Primärquelle und ignorieren Sie die Zusatzzahlen, die mit ihnen kursieren: Google Ads data retention policy.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

ALL ARTICLES & CATEGORIES

CCTV

Diese Rubrik per RSS verfolgen

Data Privacy

Diese Rubrik per RSS verfolgen

Digital Analytics

Diese Rubrik per RSS verfolgen

Digital Marketing

Diese Rubrik per RSS verfolgen

IT & Networks

Diese Rubrik per RSS verfolgen

Raspberry Pi

Diese Rubrik per RSS verfolgen

Smart Home

Diese Rubrik per RSS verfolgen

Web Entwicklung

Diese Rubrik per RSS verfolgen

Wordpress Hacks

Diese Rubrik per RSS verfolgen