Rolle
Du hilfst dem Werbeverantwortlichen bei der Massen-Erstellung von creative sets in AppLovin. API-Kapselung und Anmeldedaten werden im Skript scripts/creative_tuner.py des Skills verwendet (ct.set_account() / ct.APL_MGMT_KEY / ct.APL_ACCOUNT_ID / ct.APL_MGMT_URL). Alle Tool-Skripte befinden sich in scripts/ und heißen _cs_*.py.
Installation / Konfiguration (vor erstem Gebrauch erforderlich)
- Lege das gesamte Verzeichnis
apl-creative-set/in~/.claude/skills/(oder%USERPROFILE%\.claude\skills\unter Windows). - Führe in
scripts/aus:cp config.example.json config.jsonund trage deine eigenen AppLovin-Anmeldedaten ein:accounts.<Konto-ID>.report_key= AppLovin Report Key;.mgmt_key= Management API Key.account_aliaseserlaubt Aliase für Konten (z. B."meineApp": "deineKontoID"), im Skript nutzbar mitct.set_account("meineApp").- Der Abschnitt
feishuist optional; wird nur für den Optimierungsbericht voncreative_tuner.pybenötigt – für das reine Erstellen von Creative Sets nicht nötig, kann leer bleiben.
config.jsonenthält echte Schlüssel, niemals in Git committen oder teilen (am besten zu.gitignorehinzufügen).- Alle Konstanten in den Skripten wie
ct.set_account("DEIN_KONTO"),CAMP="",PA_IDS,VIDS,PREFIX,PP,SUFFIXusw. sind TODO-Platzhalter – ersetze sie gemäß deinem aktuellen Ziel.
Dieser Skill wird von Claude durch Lesen der SKILL.md gesteuert: Du teilst Claude das Ziel mit (Kampagne, zu erstellende Videos, Benennung, CPP), und Claude ändert die Konstanten oben in den Skripten und führt sie aus.
Eiserne Regeln
- ★ Vor jedem Start muss der Agent Punkt für Punkt diese drei Dinge mit dem Benutzer abklären (iOS/Android unterscheiden sich – niemals vom vorherigen Durchlauf übernehmen):
① Benennungsregel für Sets; ② Ob ein CPP-Suffix hinzugefügt werden soll; ③ Welchen Wert
product_pagefür das CPP erhält. Selbst wenn es sich um dieselbe Produktlinie wie beim letzten Mal handelt, muss nachgefragt werden. Keine Standardwerte annehmen. - Sicherheit der Anmeldedaten: Niemals Keys/Secrets/Tokens/Open-IDs aus der
config.jsonausgeben/ausdrucken/echoen. Skripte printen niemals Anmeldedaten. - Standardmäßig PAUSED: Neue Sets erhalten immer
status:"PAUSED". Erst nach Bestätigung durch den Benutzer freigeben (Benutzer sagt „aktivieren“ → dann auf LIVE). - Nur den angeforderten Asset-Bereich bearbeiten: Benutzer schränken oft ein („nur Sets mit bestimmtem Präfix“, „nur kürzlich hochgeladene“) – strikt nach dieser Einschränkung filtern, nicht mehr erstellen.
- Rücklese-Prüfung nach jedem Schritt: Nach create/mount/CPP/Aktivierung immer mit
creative_set/listprüfen, nicht auf den Antwortcode verlassen. - Zahlen mit Quellenangabe, auf 2 Dezimalstellen genau, bei Unklarheiten vorher fragen, Schreiboperationen vorher bestätigen lassen.
★ Wichtige API-Mechanismen (Fehlerquellen, bitte genau befolgen)
- Kampagnenzuordnung immer mit add-to-campaigns durchführen – nicht darauf verlassen, dass create automatisch zuordnet.
Der
POST /creative_set/create-Body enthält das Kampagnenfeld entweder im Singular (campaign_id:"<interneID>") oder Plural (campaign_ids:["<interneID>"]), aber keines ist zuverlässig (der Plural wird oft still ignoriert). Daher ist der feste Ablauf: create → sofortadd-to-campaignsals Absicherung → Rücklesecampaign_idsprüfen. create-Body (praktische Version):{"account_id":AID,"type":"APP","name":..,"status":"PAUSED","campaign_ids":["<interneID>"],"product_page":"","languages":[],"countries":[],"assets":[{"id":".."},..]}→ Antwort:{"id":..,"version":"V2"} - Nachträgliche Kampagnenzuordnung:
POST /creative_set/add-to-campaigns, verwende Array von Ganzzahlen:{"campaign_ids":[<interneID>],"creative_set_ids":[..]}(max. 20 Kampagnen, 50 Sets pro Batch). Am zuverlässigsten. Erfolg = die Ziel-Camp-ID ist incampaign_idsenthalten. - Set ändern (Name/CPP/Status/Assets hinzufügen/entfernen):
POST /creative_set/update{"id":..,"type":"APP","status":"LIVE|PAUSED","name":..,"product_page":..,"assets":[..]}- update erzeugt eine neue Version. Die Übergabe von
assetsüberschreibt komplett (nicht hinzufügen): Löschen = ID nicht übergeben, Hinzufügen = ID in die vollständige Liste aufnehmen, weggelassene IDs werden gelöscht (also immer Videos + zu behaltende Playables mitgeben). - Nicht übergebene Felder (z. B. name/product_page/campaign-Zuordnung) bleiben laut Tests erhalten; zur Sicherheit bei Status-/Asset-Änderungen auch name + product_page + languages + countries mitschicken.
campaign_idsim update ist wirkungslos (Antwort 200 aber keine Zuordnung) – Zuordnung nur mit add-to-campaigns.
- update erzeugt eine neue Version. Die Übergabe von
- Custom Product Page (CPP): Feld
product_page.- Standard-Store-Seite (Use default product page) =
product_page:""leere Zeichenkette (kein CPP, kein Namenssuffix). - Bei CPP-Wert entsprechenden
product_page-Wert eintragen (Zeichenketten-Slug, keine UUID). Es gibt keinen Endpunkt für eine Liste; den Wert zu einem bestimmten Namen findet man durch Scannen aller Sets des Kontos:product_pagevs. Namenssuffix (siehe_cpp_map.py).
- Standard-Store-Seite (Use default product page) =
- Asset-Typ-Felder heißen in den beiden APIs unterschiedlich (Fehlerquelle):
- In
asset/list(Mediathek) heißt das Feldasset_type; - In den
assets[]-Elementen des creative_set heißt das Feldtype. - Werte: Video =
VID_LONG_P/VID_SHORT_P(oderstartswith("VID")); Playable =HOSTED_HTML.
- In
- ★ Maximal 11 Assets pro Creative Set: Sobald assets die 11 erreichen, wird ein update still ignoriert (Antwort kommt ohne Fehler, aber das Asset wird nicht hinzugefügt – nur durch Rücklesen erkennbar). Vor dem Hinzufügen eines Playables zuerst
len(assets)prüfen; bei 11 muss vorher 1 Asset gelöscht werden (Austausch), sonst wird es nicht aufgenommen. - Paginierung:
creative_set/listundasset/listhaben max. 100/200 Einträge pro Seite, manche Seiten geben ein reines Array zurück (nicht{results:[]}), die Parsing muss mitisinstancekompatibel sein.asset/listmax. 100 pro Seite: Abbruchkriterium für die nächste Seite:len(res) < 100break (wenn man 200 verwendet, stoppt die erste Seite zu früh und man bekommt nur die ersten 100 Medien).
Vor dem Start klären (außer Benutzer hat bereits angegeben)
- Zielkampagne (Name/ID) → über die in config konfigurierten Konten finden, interne ID ermitteln.
- Asset-Bereich: Welche Videos? Präfix-Filter (z. B. Produktlinien-Präfix), Upload-Zeitgrenze (upload_time≥Datum), Status (meist ACTIVE und nicht bereits von einem anderen Set verwendet).
- Feste Playables: Welche HTML-Playables sollen eingehängt werden (Benutzer gibt genaue Dateinamen an).
- Namensregel: Standard:
DE_VideoTyp(AI/3D/JJ…aus Asset-Namens-Typ-Slot)_VideoName_oben_Playable-GruppePA; mehrere Videos einer Serie in ein Set →DE_Typ_Basisname_Gruppe_oben_Playable-GruppePA(Basisname = Name ohne Endnummer). - Serien-Erkennung: Gleiches Konzept + Endnummer (Iteration 1/4) → eine Gruppe; bei Unklarheiten vorher fragen (z. B. „Basisversion/Pro-Version“ trennen?).
- CPP: Soll
product_pagegesetzt werden? Welcher Wert? Soll dem Namen ein Suffix hinzugefügt werden?
Standardablauf (Skript-Pipeline, alle in scripts/)
_apl_active_assets.py→ Holt deduplizierte ACTIVE Assets →_apl_active_assets.json._cs_plan_scan.py→ Findet IDs der festen Playables + Kandidatenvideos (Präfix + is_video + nicht von bestehenden Sets belegt + Zeitfilter) →_cs_scan.json. Vorher obenPREFIX/CAMP/targetsanpassen._cs_group.py→ Gruppiert Kandidaten nach Serie/einzelnen Assets, generiert Namen →_cs_build_plan.json. Mit_cs_plan_show.pykann man die Liste dem Benutzer zur Bestätigung anzeigen._cs_build_all.py(idempotent: überspringt bereits erstellte Sets anhand des Namens) → Erstellt nacheinander Sets (PAUSED, mit campaign_id) + absicherndes add-to-campaigns + Rücklese-Prüfung →_cs_create_result.json.- (Optional)
_cpp_apply.py all→ Setztproduct_page+ fügt Namenssuffix hinzu (vorher obenPP/SUFFIXanpassen). - Nach Bestätigung durch Benutzer:
_cs_enable.py→ status→LIVE (mit name + product_page, um Datenverlust zu vermeiden) + Rücklese. - Stichprobe:
_cs_spotcheck.py <id..>→ Zeigt Asset-Zusammensetzung (Anzahl Videos + Playables).
Leichter Pfad: Wenige spezifische Videos direkt gruppieren (Videonamen bekannt, kein vollständiger Scan erforderlich)
Geeignet: Benutzer hat ein paar neue Videos hochgeladen und möchte direkt Gruppen daraus erstellen.
_cs_find_new.py <Schlüsselwort..>→ Sucht in der Mediathek nach Videos anhand des Namens: vollständiger Name + ID + Status + Uploadzeit (nur lesend). Prüft, ob es das gewünschte Video ist und Status ACTIVE ist.- Ändere in
_cs_en_new_create.pyoben die Werte:VIDS=[(Kernname,Video-ID),..]/PA_IDS(feste Playables) /CAMP. Zuerst gemäß Regel 0 mit Benutzer Benennung + CPP klären.python _cs_en_new_create.py(dry-run: prüft auf Duplikate + zeigt Plan) →go(erstellt PAUSED + Standard-Store-Seite""+ keine Sprachzuordnung, folgt Kampagne + add-to-campaigns + Rücklese-Prüfung: Zuordnung/Assetanzahl/pp/status). - Benutzer sagt „aktivieren“ →
_cs_en_new_enable.py(liest_cs_en_new_ids.json, übergibt explizit name/product_page/languages/countries zur Sicherheit, status→LIVE + Rücklese).
Playables in einem Set hinzufügen / entfernen / ersetzen
Massenweises Hinzufügen/Entfernen eines bestimmten Playables anhand von Schlüsselwörtern im Set-Namen (update überschreibt assets komplett, bewahrt name/product_page/languages/countries/status, nach Ausführung Rücklese-Prüfung):
- Hinzufügen:
_cs_add_pa.py <Playable-ID> <Set-Name-Schlüsselwort> [enonly](dry-run) → danngo.enonly= nur Sets, die mitEN_beginnen (um sprachspezifische Gruppen auszuschließen). Idempotent: überspringt, wenn bereits enthalten; Gruppen mit 11 Assets werden automatisch gewarnt und übersprungen (muss vorher 1 Asset gelöscht werden). - Entfernen:
_cs_rm_pa.py <Playable-ID>(dry-run) →go. Sicherheitsbarriere: Nach dem Entfernen muss das Set noch ≥1 Video und ≥1 Playable enthalten, sonst rot markieren und nicht ändern. - Ersetzen = In der vollständigen Asset-Liste die alte ID durch die neue ersetzen und update ausführen.
- Playable-ID mit
_cs_find_new.py <Schlüsselwort>in der Mediathek anhand des Namens suchen (HOSTED_HTML).
Übergabe-Sprachregelung
Bericht: Anzahl erstellter Gruppen (Serie/Einzeln), Abdeckung (wie viele Videos), jede Gruppe = entsprechendes Video + N Playables, alle PAUSED + zugeordnet + CPP, Liste „Gruppenname → Video“; Hinweise auf nicht freigegebene/nicht hochgeladene Assets (mit einer vollständigen Zustandsrückschau analog _b8_leftover.py Ansatz kategorisieren: REJECTED/nicht hochgeladen). Warte auf „aktivieren“ vom Benutzer, dann Schritt 6 ausführen.