Target oder-Non-Target
Warum genaue Zielgruppen den Profit verringern können
Im Online-Marketing ist zielgerichtete Werbung (Targeted Ads) erfolgsentscheidend – aber je spezifischer die Zielgruppe, desto stärker sinkt die Reichweite und damit poteniell die Profitabilität. Es kommt zur „Reichweitenbestrafung“. In diesem Blogbeitrag stellen wir einen einfach zu bedienendes R-Script vor, mit dessen Hilfe vorhergesagt werden kann, wann die Reichweite zu stark eingeschränkt wurde, dass eine Werbekampagne erfolgreich werden kann.
Die Kernpunkte
Die Kernpunkte
Reichweitenbestrafung
Im Online-Marketing steigern Targeted Ads häufig die Werbewirkung, da sie gezielt auf demografische Daten und Nutzerverhalten basiert. Allerdings stellt sich die Frage: Ab wann wird die Zielgruppe zu klein und wirkt sich negativ auf die Rentabilität aus? Diese sogenannte „Reichweitenbestrafung“ kann die Profitabilität stark beeinträchtigen, da Targeted Ads bei geringerer Reichweite deutlich besser performen müssen, um kostendeckend zu sein. Der Hintergrund ist, dass eine bessere Conversion-Rate nichts nützt, wenn die Nutzeranzahl erheblich sinkt. Schnell muss die Anzeige unrealistisch gut performen, lediglich um den Break Even Point zu erreichen. Um nicht in diese Falle zu treten, haben Ahmadi et al. (2024) eine Performance-Formel zur Vorhersage, bis zu welcher Reichweitenreduktion Targeted Ads rentabel bleiben, entwickelt. Auf dieser Formel basiert unser R-Script.
Zum Blogbeitrag
Dieser Blogeintrag basiert auf der Veröffentlichung von Dege (2025) „Target oder Non-Target? Wann spezifische Zielgruppen den Profit schmälern und wie dies vorhergesagt werden kann – Am Beispiel von Google Ads“ , welche im Frühjar 2025 in dem werbewissenschaftlichen Magazin „transfer“ erscheinen wird. Im Beitrag wird detailiert das Problem der Reichweitenbestrafung beschrieben und die Hintergründe sowie das Script erklärt.
Vorhersage der Bestrafung
Um die Reichweitenbestrafung vorherzusagen, haben Ahmadi et al. (2024) eine Profit-Formel entwickelt, welche die Costumer Journey nachempfindet. Sie startet mit der Anzahl der Impressionen, welche mit der CTR (Klickrate) multipliziert wird. Es wird also die Anzahl an Klicks berechnet. Die Anzahl an Klicks wird mit der Conversion-Rate multipliziert, womit die Anzahl der Conversions ergeben. Die Anzahl an Conversions wird schließlich mit dem Profit pro Conversion multipliziert. Der Profit pro Conversion wurde zuvor anhand der Kosten pro Conversion sowie des Umsatzes pro Conversion berechnet.
Profitformel:
Gesamtprofit = Impressionen * CTR * CR * ProfitProConversion
Das Ergebnis ist schließlich der Gesamtprofit einer Werbekampagne bzw. Anzeige. Dadurch, dass die Formel die gesamte Costumer Journey mit Beginn der Impressionen, sprich der Reichweite, berücksichtigt, können Änderungen der Reichweite und deren Auswirkungen auf den Profit berücksichtigt werden. Die Profit-Formel wird nun zweimal erstellt. Einmal auf Basis einer aktiven Anzeige, deren Performance-Daten bereits vorliegen und einmal anhand einer noch nicht aktivierten Targeted Anzeige, die auf der aktiven Anzeige basiert, allerdings eine geringere Reichweite aufweist aufgrund der kleineren Zielgruppe. Nun werden beide Formeln gleichgesetzt und nach der Performance-Variable gelöst, womit sich im Resultat die Performance-Formel ergibt. Anhand dieser kann schließlich vorhergesagt werden, ab welcher Reichweitenreduktion eine Targeted Ad de facto nicht profitabel sein kann.
Unser Script
R bzw. R-Studio (https://posit.co/download/rstudio-desktop/) ist eine Free Source Statistik-Software, mit deren Hilfe eine Vielzahl komplexer Berechnungen vorgenommen werden können. Unser R-Script, welches in R-Studio ausgeführt wird, nutzt die Performance Formel, um die Reichweitenbestrafung anhand von 10.000 simulierten Punktwerten zu berechnen. Auf diese Weise kann schließlich die Wahrscheinlichkeit ermittelt werden, unter welchen Umständen eine Reichweitenreduktion zu keiner Bestrafung führt. In das R-Script müssen lediglich die Performance-Daten einer aktiven Anzeige bzw. Kampagne eingefügt werden sowie die zu erwartende reduzierte Reichweite der Targeted Ads, welche auf der aktiven Anzeige basiert.
Im Anschluss kann das Script einfach ausgeführt werden. Das Script gibt die maximal zu empfehlende Reichweitenreduktion an, genauso wie die Wahrscheinlichkeit dafür, dass die Anzeige bei gewünschter Reichweitenreduktion profitabel sein wird. Zudem können spezifische Konfigurationen zur Performance der Targeted Anzeige vorgenommen werden. Dies ist dann sinnvoll, wenn einem Erfahrungswerte vorliegen, die berücksichtigt werden sollen. Ansonsten wird die Default-Konfiguration genutzt. Unser Script kann unten kopiert und direkt für die Planung von Anzeigen eingesetzt werden. In unserem Bild-Slider zeigen wir Schritt für Schritt, wie das R-Script genutzt werden kann.
Wie wird das Script verwendet
Zum Script
#Berechnung der Reicheitenbestrafung####
#Folgenden Code einmal ausführen vor Beginn der Berechnungen
install.packages(„truncnorm“)
library(truncnorm)
###
####Start###
#Block 1
#Angaben zur Anzeige ohne/weniger Targeting (hier die eigenen Daten einfügen)
kosten <- 938 #Kosten im Zeitraum X (z. B. 4 Monate)
imp <- 7249 #Impressionen im Zeitraum X (z. B. 4 Monate)
klicks <- 414 #Klicks im Zeitraum X (z. B. 4 Monate)
conv <- 8 #Konversionen im Zeitraum X (z. B. 4 Monate)
UPC <- 350 #Umsatz pro Konversion im Zeitraum X (z. B. 4 Monate)
reichweite <- 630 #Reichweite (Angaben können durch z. B. Google Keyword Planer ermittelt weden )
KostenFuerTargeting <- 0 #Extrakosten für Targeting im Zeitraum X (z. B. 4 Monate)
#Angaben zur geplanten Anzeige mit Targeting
reichweiteNeu <- 510 #Impressionen im Zeitraum X (z. B. 4 Monate)
#Block 2
#Verteilungsannahmen (nicht ändern, wenn die Default-Konfiguration beibehalten werden soll)
#Kosten pro Impression der Anzeige mit Targeting in Dezimalschreibweise
# --> (1.3 = Plus 30 Prozent; 0.9 = Minus 10 Prozent)
# –> Das Komma ist ein Punkt in der internationalen Schreibweise 1,3 = 1.3
#Die folgenden Angaben beziehen sich auf den Unterschied zwischen der Anzeigen ohne/mit wenig Targeting
#und der Anzeige mit/mit mehr Targeting. Wenn du annimmst, dass die Targeted Anzeige meistens 30 Prozent mehr
#Kosten pro Impression aufweist, dann gibst du bei der Variable kpIm (erste Variable nach diesem Absatz) 1.3 an.
#Du musst auch häufiger eine Standardabweichung angeben. Die Standardabweichung ist dein vermuteter Grad an
#Unsicherheit über deine Aussage. Wenn du dir eher sicher bist, dann gebe einen kleineren Wert an, im Vergleich
#zur aktuellen Konfiguration. Wenn du dir eher unsicher bist, dann gebe einen größeren Wert an.Bei der
#Standardabweichung KpiSD (erset Standardabweichung nach diesem Absatz) ist ber Default 0.05 eingestellt
#diesen könntest du vergrößern wenn du eher unsicher bist (z. B. 0.07) oder verkleinern, wenn du sicher bist (0.03)
kpiM <- 1 #Kosten pro Impression (kleiner 1 = niedrigerer Preis als in der #Anzeige ohne Targeting; größer 1 = höherer Preis als in der #Anzeige ohne Targeting) kpiB <- 1.3 #Maximal anzunehmender Wert für die Kosten pro Impression der Anzeige mit Targeting kpiSD <- 0.05 #Standardabweichung der Verteilung (wie breit fällt die Verteilung aus) #CTR-Veränderung der Anzeige mit Targeting ctrMean <- 1 #Mittelwert der Verteilung (Zentrum) ctrA <- 0.85 #Untere Grenze der Verteilung ctrB <- 1.15 #Obere Grenze der Verteilung ctrSD <- 0.03 #Standardabweichung der Verteilung (wie breit fällt die Verteilung aus) #CR-Veränderung der Anzeige mit Targeting crMean <- 1 #Mittelwert der Verteilung (Zentrum) crA <- 0.85 #Untere Grenze der Verteilung crB <- 1.15 #Obere Grenze der Verteilung crSD <- 0.03 #Standardabweichung der Verteilung (wie breit fällt die Verteilung aus) #Umsatz pro Konversion-Veränderung der Anzeige mit Targeting UpCMean <- 1 #Mittelwert der Verteilung (Zentrum) UpCA <- 0.85 #Untere Grenze der Verteilung UpCB <- 1.15 #Obere Grenze der Verteilung UpCSD <- 0.03 #Standardabweichung der Verteilung (wie breit fällt die Verteilung aus) #Block 3 #Der folgende Code kann komplett ausgeführt werden kpI <- kosten/imp rR <- reichweiteNeu/reichweite CTR <- rep(klicks/imp,10000) CR <- rep(conv/klicks,10000) UmsatzProConversion <- rep(UPC,10000) kostenProImp <-rep(kpI,10000) targetKosten <-rep(KostenFuerTargeting/imp,10000) kostenProImpDach <- rtruncnorm(n=10000, a=kpI, b= kpI * kpiB, mean= kpI * kpiM, sd=kpI * kpiSD) hist(kostenProImpDach, main = "Angenommene Wertverteilung der Kosten pro Impression in der Anzeige mit Targeting", xlab = "Kosten pro Impression", ylab = "Haeufigkeit", breaks = 100, ) ctr_ch <- rtruncnorm(n= 10000, a= ctrA, b= ctrB, mean= ctrMean, sd= ctrSD) hist(ctr_ch, main = "Angenommene Verteilung der Werte für CTR-Veraenderung in der Anzeige mit Targeting", xlab = "Veränderung", ylab = "Haeufigkeit", breaks = 100, ) cr_ch <- rtruncnorm(n= 10000, a=crA, b= crB, mean= crMean, sd= crSD) hist(cr_ch, main = "Angenommene Verteilung der Werte für CR-Veraenderung in der Anzeige mit Targeting", xlab = "Veränderung", ylab = "Haeufigkeit", breaks = 100, ) Umsatz_ch <- rtruncnorm(n= 10000, a= UpCA, b= UpCB, mean= UpCMean, sd= UpCSD) hist(Umsatz_ch, main = "Angenommene Verteilung der Werte für die Veraenderung des Umsatzes in der Anzeige mit Targeting", xlab = "Veränderung", ylab = "Haeufigkeit", breaks = 100, ) #Block 4 ## Berechnung CTR #### y <- (1/rR) - ((kostenProImp - (rR * (kostenProImpDach + targetKosten)))/ ( rR * CTR * CR * UmsatzProConversion)) ctr_ch <- rtruncnorm(n= 10000, a= ctrA, b= ctrB, mean= ctrMean, sd= ctrSD) cr_ch <- rtruncnorm(n= 10000, a=crA, b= crB, mean= crMean, sd= crSD) Umsatz_ch <- rtruncnorm(n= 10000, a= UpCA, b= UpCB, mean= UpCMean, sd= UpCSD) x_A <- y/(cr_ch*Umsatz_ch) sCTR_A <- y/(cr_ch*Umsatz_ch) sCR_A <- y/(ctr_ch*Umsatz_ch) sUmsatz_A <- y/(cr_ch*ctr_ch) CTRFinal_A <- sum(sCTR_A > 0.9 & sCTR_A < 1.1 )/length(x) mean_y = -1 i = 1 x = 0 limit = 0.699 CTRFinal = 0 while ( CTRFinal < limit ) { # while (i < limit) { rRChange <- rR + (i-1) * 0.01 changeReichweite <- rep(rRChange,10000) y <- (1/changeReichweite) - ((kostenProImp - (changeReichweite * (kostenProImpDach + targetKosten)))/ ( changeReichweite * CTR * CR * UmsatzProConversion)) mean_y <- mean(y) ctr_ch <- rtruncnorm(n= 10000, a= ctrA, b= ctrB, mean= ctrMean, sd= ctrSD) cr_ch <- rtruncnorm(n= 10000, a=crA, b= crB, mean= crMean, sd= crSD) Umsatz_ch <- rtruncnorm(n= 10000, a= UpCA, b= UpCB, mean= UpCMean, sd= UpCSD) x <- y/(ctr_ch*Umsatz_ch) sCTR <- y/(cr_ch*Umsatz_ch) sCR <- y/(ctr_ch*Umsatz_ch) sUmsatz <- y/(ctr_ch*cr_ch) CTRFinal <- sum(sCTR > 0.9 & sCTR < 1.1 )/length(x) i <- i+1 if( CTRFinal < limit ){ } else{ message("CTR: Empfohlene maximale Reichweitenreduktion: ", (round(1-rRChange,2))*100, " %; Wahrscheinlichkeit für realitätsnahe CTR Verbesserung: ",(CTRFinal )*100," %" ) message("CTR: Gewünschte Reichweitenreduktion: ",round(1-rR,2)*100, " %; Wahrscheinlichkeit für realitätsnahe CTR Verbesserung bei gewünschter Reichweitenreduktion: ", (CTRFinal_A )*100," %") hist(x, main = "Verteilung realitätsnahe Werte für CTR-Veraenderung", xlab = "Veränderung", ylab = "Haeufigkeit", breaks = 100) abline(v=c(0.9,1.1), col="red") hist(x_A, main = "Verteilung der Werte für CTR-Veraenderung bei gewünschter Reichweitenreduktion", xlab = "Veränderung", ylab = "Haeufigkeit", breaks = 100, ) abline(v=c(0.9,1.1), col="red") } } #Block 5 ## Berechnung CR #### y <- (1/rR) - ((kostenProImp - (rR * (kostenProImpDach + targetKosten)))/ ( rR * CTR * CR * UmsatzProConversion)) ctr_ch <- rtruncnorm(n= 10000, a= ctrA, b= ctrB, mean= ctrMean, sd= ctrSD) cr_ch <- rtruncnorm(n= 10000, a=crA, b= crB, mean= crMean, sd= crSD) Umsatz_ch <- rtruncnorm(n= 10000, a= UpCA, b= UpCB, mean= UpCMean, sd= UpCSD) x_A <- y/(cr_ch*Umsatz_ch) sCTR_A <- y/(cr_ch*Umsatz_ch) sCR_A <- y/(ctr_ch*Umsatz_ch) sUmsatz_A <- y/(cr_ch*ctr_ch) CRFinal_A <- sum(sCR_A > 0.9 & sCR_A < 1.1 )/length(x) mean_y = -1 i = 1 x = 0 limit = 0.699 CRFinal = 0 while ( CRFinal < limit ) { # while (i < limit) { rRChange <- rR + (i-1) * 0.01 changeReichweite <- rep(rRChange,10000) y <- (1/changeReichweite) - ((kostenProImp - (changeReichweite * (kostenProImpDach + targetKosten)))/ ( changeReichweite * CTR * CR * UmsatzProConversion)) mean_y <- mean(y) ctr_ch <- rtruncnorm(n= 10000, a= ctrA, b= ctrB, mean= ctrMean, sd= ctrSD) cr_ch <- rtruncnorm(n= 10000, a=crA, b= crB, mean= crMean, sd= crSD) Umsatz_ch <- rtruncnorm(n= 10000, a= UpCA, b= UpCB, mean= UpCMean, sd= UpCSD) x <- y/(ctr_ch*Umsatz_ch) sCTR <- y/(cr_ch*Umsatz_ch) sCR <- y/(ctr_ch*Umsatz_ch) sUmsatz <- y/(ctr_ch*cr_ch) CRFinal <- sum(sCR > 0.9 & sCR < 1.1 )/length(x) i <- i+1 if( CRFinal < limit ){ } else{ message("CR: Empfohlene maximale Reichweitenreduktion: ", (round(1- rRChange,2))*100, " %; Wahrscheinlichkeit für realitätsnahe CR Verbesserung: ",(CRFinal )*100," %" ) message("CR: Gewünschte Reichweitenreduktion: ",round(1-rR,2)*100, " %; Wahrscheinlichkeit für realitätsnahe CR Verbesserung bei gewünschter Reichweitenreduktion: ", (CRFinal_A )*100," %") hist(x, main = "Verteilung realitätsnahe Werte für CR-Veraenderung", xlab = "Veränderung", ylab = "Haeufigkeit", breaks = 100) abline(v=c(0.9,1.1), col="red") hist(x_A, main = "Verteilung der Werte für CR-Veraenderung bei gewünschter Reichweitenreduktion", xlab = "Veränderung", ylab = "Haeufigkeit", breaks = 100, ) abline(v=c(0.9,1.1), col="red") } } #Block 6 ##Berechnung UpC#### y <- (1/rR) - ((kostenProImp - (rR * (kostenProImpDach + targetKosten)))/ ( rR * CTR * CR * UmsatzProConversion)) ctr_ch <- rtruncnorm(n= 10000, a= ctrA, b= ctrB, mean= ctrMean, sd= ctrSD) cr_ch <- rtruncnorm(n= 10000, a=crA, b= crB, mean= crMean, sd= crSD) Umsatz_ch <- rtruncnorm(n= 10000, a= UpCA, b= UpCB, mean= UpCMean, sd= UpCSD) x_A <- y/(cr_ch*Umsatz_ch) sCTR_A <- y/(cr_ch*Umsatz_ch) sCR_A <- y/(ctr_ch*Umsatz_ch) sUmsatz_A <- y/(cr_ch*ctr_ch) UmsatzFinal_A <- sum(sUmsatz_A > 0.9 & sUmsatz_A < 1.1 )/length(x) mean_y = -1 i = 1 x = 0 limit = 0.699 UmsatzFinal = 0 while ( UmsatzFinal < limit ) { # while (i < limit) { rRChange <- rR + (i-1) * 0.01 changeReichweite <- rep(rRChange,10000) y <- (1/changeReichweite) - ((kostenProImp - (changeReichweite * (kostenProImpDach + targetKosten)))/ ( changeReichweite * CTR * CR * UmsatzProConversion)) mean_y <- mean(y) ctr_ch <- rtruncnorm(n= 10000, a= ctrA, b= ctrB, mean= ctrMean, sd= ctrSD) cr_ch <- rtruncnorm(n= 10000, a=crA, b= crB, mean= crMean, sd= crSD) Umsatz_ch <- rtruncnorm(n= 10000, a= UpCA, b= UpCB, mean= UpCMean, sd= UpCSD) x <- y/(ctr_ch*Umsatz_ch) sCTR <- y/(cr_ch*Umsatz_ch) sCR <- y/(ctr_ch*Umsatz_ch) sUmsatz <- y/(ctr_ch*cr_ch) UmsatzFinal <- sum(sUmsatz > 0.9 & sUmsatz < 1.1 )/length(x) i <- i+1 if( UmsatzFinal < limit ){ } else{ message("UpC: Empfohlene maximale Reichweitenreduktion: ", (round(1- rRChange,2))*100, " %; Wahrscheinlichkeit für realitätsnahe KpU Verbesserung: ",(UmsatzFinal)*100," %" ) message("UpC: Gewünschte Reichweitenreduktion: ",round(1-rR,2)*100, " %; Wahrscheinlichkeit für realitätsnahe KpU Verbesserung bei gewünschter Reichweitenreduktion: ", (UmsatzFinal_A )*100," %") hist(x, main = "Verteilung realitätsnahe Werte für KpU-Veraenderung", xlab = "Veränderung", ylab = "Haeufigkeit", breaks = 100) abline(v=c(0.9,1.1), col="red") hist(x_A, main = "Verteilung der Werte für KpU-Veraenderung bei gewünschter Reichweitenreduktion", xlab = "Veränderung", ylab = "Haeufigkeit", breaks = 100, ) abline(v=c(0.9,1.1), col="red") } } #ende####