Meta Lead Ads als CSV im Postfach des Kunden, jeden Morgen
Eine Version dieses Beitrags habe ich 2024 geschrieben. Die API hat sich weiterbewegt, die Form nicht, und es ist immer noch die eine Automatisierung, für die sich Kunden am häufigsten bedanken, weil sie "ins Dashboard einloggen" durch "Mail öffnen" ersetzt.
Meta Lead Ads behalten die Formularantworten in der Plattform. Ein Kunde, der nicht im Werbeanzeigenmanager lebt, erfährt spät oder gar nicht von neuen Leads, und ein Lead, der einen Tag wartet, ist ein halber Lead. Die Lösung ist ein Skript, das jeden Morgen läuft, alles aus den letzten 24 Stunden holt und es als CSV mit Spalten in fester Reihenfolge verschickt.
Die drei Teile
Ein langlebiges Page-Access-Token mit der Berechtigung leads_retrieval, abgelegt in einer Umgebungsvariable. Die Formular-ID, die du einmal aus der URL im Werbeanzeigenmanager abliest. Und ein Mailkonto, das von deiner Domain senden darf.
Der Aufruf ist GET /{form_id}/leads mit einem filtering-Parameter auf time_created größer als der Zeitstempel von gestern, geblättert mit dem Cursor, den die Antwort zurückgibt. Jeder Lead kommt mit einer field_data-Liste aus Name-Werte-Paaren, in der Reihenfolge, die das Formular hat. Das Skript macht daraus eine Zeile pro Lead und hält die Spaltenreihenfolge über die Tage stabil, denn ein Kunde, der in Excel sortiert, merkt es, wenn die Spalten springen.
def flatten(lead, columns):
row = {"lead_id": lead["id"], "created": lead["created_time"]}
for f in lead.get("field_data", []):
row[f["name"]] = ", ".join(f.get("values", []))
return [row.get(c, "") for c in columns]
columns ist eine Liste in einer kleinen Konfiguration neben dem Skript: Lead-ID und Zeitstempel zuerst, dann die Formularfelder in der Reihenfolge, in der der Kunde sie liest. Ein Feld, das nicht in der Konfiguration steht, wird trotzdem geschrieben, am Ende, damit eine neue Formularfrage nie stillschweigend verschwindet.
Kleine Entscheidungen, die es haltbar gemacht haben
Schick die Mail auch bei null Leads. Eine Betreffzeile mit "0 Leads, Dienstag" sagt dem Kunden, dass das System gelaufen ist. Stille sagt ihm nichts, und am dritten Tag fragt er, ob es kaputt ist.
Führ eine Datei mit den bereits gesendeten Lead-IDs. Das 24-Stunden-Fenster und der Morgentermin überlappen sich um ein paar Minuten, und ohne die Datei taucht derselbe Lead an zwei Tagen auf. Mit ihr schickt das Skript jeden genau einmal, und wenn der Job an einem Morgen scheitert, holt der nächste Lauf das Versäumte nach, statt einen Tag zu verlieren.
Setz das Datum in den Dateinamen und die Anzahl in den Betreff. leads-2026-08-19.csv, "7 neue Leads, Di 19. Aug". Das ist der ganze Mailtext; die CSV ist der Inhalt.
Nimm UTF-8 mit BOM am Dateianfang. Excel unter Windows zerlegt sonst jeden Umlaut in einem Namen, und der Kunde glaubt, das Formular sei kaputt.
Plane den Lauf für 06:30 in der Zeitzone des Kunden, nicht der des Servers. Metas created_time ist UTC; rechne es vor dem Schreiben um und nenn die Zone im Spaltenkopf.
Was es nicht ist
Es ist keine CRM-Anbindung, es gleicht nicht mit einer bestehenden Kundenliste ab, und es antwortet dem Lead nicht. All das sind vernünftige nächste Schritte, und all das ist ein anderes Projekt. Dieses hier ist eine Cron-Zeile, sechzig Zeilen Python und eine Mail, und es läuft bei einem Kunden seit über einem Jahr ohne Änderung.
