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 potenziell die Profitabilität. Es kommt zur „Reichweitenbestrafung“. In diesem Blogbeitrag stellen wir ein einfach zu bedienendes R-Script vor, mit dessen Hilfe vorhergesagt werden kann, wann die Reichweite so stark eingeschränkt wurde, dass eine Werbekampagne nicht mehr erfolgreich sein kann.
Unser R-Script bieten wir zudem als R-Shiny-App an. Diese kann für den heimischen gebrauch hier heruntergeladen werden oder im Browser unter https://klicklautapps.shinyapps.io/reichweitenbestrafung/ genutzt werden.
Die Kernpunkte
Die Kernpunkte
Reichweitenbestrafung
Im Online-Marketing steigern Targeted Ads häufig die Werbewirkung, da sie gezielt auf demografischen Daten und dem Nutzerverhalten basieren. 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 Break-Even-Formel zur Vorhersage entwickelt, bis zu welcher Reichweitenreduktion Targeted Ads rentabel bleiben. 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ühjahr 2025 in dem werbewissenschaftlichen Magazin „transfer“ erscheinen wird. Im Beitrag wird detailliert das Problem der Reichweitenbestrafung beschrieben sowie die Hintergründe und das Script erklärt.

Vorhersage der Bestrafung
Um die Reichweitenbestrafung vorherzusagen, haben Ahmadi et al. (2024) eine Profit-Formel entwickelt, welche die Customer Journey nachempfindet. Sie startet mit der Anzahl der Impressionen, die mit der CTR (Klickrate) multipliziert wird. So wird die Anzahl der Klicks berechnet. Die Anzahl der Klicks wird wiederum mit der Conversion-Rate multipliziert, wodurch sich die Anzahl der Conversions ergibt. Schließlich wird die Anzahl der Conversions 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. Da die Formel die gesamte Customer Journey mit Beginn der Impressionen, sprich der Reichweite, berücksichtigt, können Änderungen der Reichweite und deren Auswirkungen auf den Profit erfasst werden.
Die Profit-Formel wird nun zweimal erstellt: einmal auf Basis einer aktiven Anzeige, deren Performance-Daten bereits vorliegen, und einmal für eine noch nicht aktivierte Targeted-Anzeige, die auf der aktiven Anzeige basiert, jedoch eine geringere Reichweite aufweist, da die Zielgruppe kleiner ist.
Nun werden beide Formeln gleichgesetzt und nach der Break-Even-Variable aufgelöst, wodurch sich als Ergebnis die Performance-Formel ergibt. Mithilfe dieser kann schließlich vorhergesagt werden, ab welcher Reichweitenreduktion eine Targeted Ad de facto nicht mehr profitabel sein kann.

Unser Script
R bzw. RStudio (https://posit.co/download/rstudio-desktop/) ist eine Open-Source-Statistiksoftware, mit deren Hilfe eine Vielzahl komplexer Berechnungen vorgenommen werden kann.
Unser R-Script, das in RStudio 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 sowie die zu erwartende reduzierte Reichweite der Targeted Ads eingefügt werden, die auf der aktiven Anzeige basieren.

Im Anschluss kann das Script einfach ausgeführt werden. Es gibt die maximal zu empfehlende Reichweitenreduktion an, ebenso wie die Wahrscheinlichkeit, dass die Anzeige bei der gewünschten Reichweitenreduktion profitabel sein wird. Zudem können spezifische Konfigurationen zur Performance der Targeted-Anzeige vorgenommen werden. Dies ist dann sinnvoll, wenn Erfahrungswerte vorliegen, die berücksichtigt werden sollen. Andernfalls 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 <- 6015 #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)
KostenFuerTargeting <- 0 #Extrakosten für Targeting im Zeitraum X (z. B. 4 Monate)
reichweite <- 5368 #Reichweite im Zeitraum X (z. B. 4 Monate; Angaben können durch z. B. Google Keyword Planer ermittelt weden)
#Angaben zur geplanten Anzeige mit Targeting
reichweiteNeu <- 4764 #Reichweite im Zeitraum X (z. B. 4 Monate; Angaben können durch z. B. Google Keyword Planer ermittelt weden)
#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) sCTR_A <- y/(cr_ch*Umsatz_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/(cr_ch*Umsatz_ch) sCTR <- y/(cr_ch*Umsatz_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") rect(0.9, 0, 1.1, 1000, col = rgb(0, 1, 0, 0.5), border = NA) hist(sCTR_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") rect(0.9, 0, 1.1, 1000, col = rgb(0, 1, 0, 0.5), border = NA) } } #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) Umsatz_ch <- rtruncnorm(n= 10000, a= UpCA, b= UpCB, mean= UpCMean, sd= UpCSD) sCR_A <- y/(ctr_ch*Umsatz_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) sCR <- y/(ctr_ch*Umsatz_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") rect(0.9, 0, 1.1, 1000, col = rgb(0, 1, 0, 0.5), border = NA) hist(sCR_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") rect(0.9, 0, 1.1, 1000, col = rgb(0, 1, 0, 0.5), border = NA) } } #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) sUmsatz_A <- y/(cr_ch*ctr_ch) UmsatzFinal_A <- sum(sUmsatz_A > 0.9 & sUmsatz_A < 1.1 )/length(sUmsatz_A) 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*cr_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") rect(0.9, 0, 1.1, 1000, col = rgb(0, 1, 0, 0.5), border = NA) hist(sUmsatz_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") rect(0.9, 0, 1.1, 1000, col = rgb(0, 1, 0, 0.5), border = NA) } } #ende####