Auswertung von Benutzeraccounts in Django – Neue KPI’s für easy-tickets.app

Posted on 2023-04-15 in django

What gets measured, gets managed!
Peter Drucker (The practice of Management)

Bisher habe ich mich bei easy-tickets.app nur Anhand von Kennzahlen wie Seitenaufrufe, Besucherquellenen/3.0/getting_started.html und Konvertierungsquoten von Besuchern orientiert. Das alles ist schon nicht ganz so schlecht und es lassen sich bereits aus diesen Kennzahlen einige Erkenntnisse gewinnen. Jedoch möchte ich, nachdem die Plattform nun seit knapp 6 Monaten kostenpflichtig ist, ein paar weitere Kennzahlen etablieren mit denen ich:

  • einen besseren Einblick bekomme wie sich das Business verhält
  • Entscheidungen zur Steuerung und für das Marketing ableiten kann
  • ein paar Statistiken für Nerds habe 😉

Doch wo Anfangen? Wie können Kennzahlen zuverlässig berechnet werden? Speichern oder dynamisch berechnen und wie können sie angezeigt werden? Das ich in der Vergangenheit eine Zeit lang Daten ausgewertet habe, kommt mir hier ganz klar zu Gute 😉

Kennzahlen sind nicht gleich Kennzahlen

Machen wir aber erst einmal einen kleinen Exkurs zu den Kennzahlen an sich. Hier gibt es unterschiede auf die ich etwas näher eingehen möchte. Kennzahlen lassen sich in sog. „Leading & Lagging Indicators“ einteilen. Die Unterscheidung der beiden ist allerdings nicht ganz einfach und auch nicht zwingen auf den ersten blick ersichtlich. Vereinfacht kann man aber sagen, dass „Leading Indicators“ sich zum steuern eigenen und „Lagging Indicators“ einen Zustand abbilden, mit dessen Information man aber nicht zwingen steuern kann. Besucherzahlen oder Seitenaufrufe wären Beispiele für Lagging Indicators. Sie geben zwar Auskunft darüber wie oft die Seite aufgerufen wurde, eignen sich allerdings nicht zum Steuern. Eine Kennzahl welche besser zu Steuern geeignet ist, ist beispielsweise eine Konvertierungsrate von Besuchern welche einen Account anlegen oder einen Service buchen. Ein Steuern dieser Kennzahl hat direkte Auswirkungen auf den Umsatz und somit den Unternehmenserfolg.

Für die eigentliche Auswertung setze ich auf eine eigenständige Tabelle in der Datenbank welche jeweils eine Spalte für die Kennzahlen enthält. Dazu eine Jahres und Monatsspalte.

class Statistics(models.Model):
    stats_type = models.CharField(max_length=40)     # monthly, weekly
    year = models.IntegerField()
    month = models.IntegerField(blank=True, null=True)
    calendar_week = models. IntegerField(blank=True, null=True)
    cac = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="Customer Acquisition Cost", blank=True, null=True)
    csp_c90 = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="Customer Spend per period (letzte 90 Tage)", blank=True, null=True)
    csp_c180 = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="Customer Spend per period (letzte 180 Tage)", blank=True, null=True)
    csp_c365 = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="Customer Spend per period (letzte 365 Tage)", blank=True, null=True)
    csp_a90 = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="Users Spend per period (letzte 90 Tage)", blank=True, null=True)
    csp_a180 = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="Users Spend per period (letzte 180 Tage)", blank=True, null=True)
    csp_a365 = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="Users Spend per period (letzte 365 Tage)", blank=True, null=True)
    last_update = models.DateTimeField(auto_now=True)
    accounts_created = models.PositiveSmallIntegerField(verbose_name="Accounts created", blank=True, null=True)
    accounts_deleted = models.PositiveSmallIntegerField(verbose_name="Accounts deleted", blank=True, null=True)
    churn_rate = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="Churn rate", blank=True, null=True)
    total_acount = models.PositiveSmallIntegerField(verbose_name="Total Accounts", blank=True, null=True)
    mau = models.PositiveSmallIntegerField(verbose_name="Monthly active users", blank=True, null=True)
    mom_growth = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="Month on month account growth", blank=True, null=True)
    emails_send = models.PositiveSmallIntegerField(verbose_name="emails send", blank=True, null=True)
    fun_1_visitors = models.PositiveSmallIntegerField(verbose_name="fun_1_visitors", blank=True, null=True)
    fun_2_register = models.PositiveSmallIntegerField(verbose_name="fun_2_register", blank=True, null=True)
    fun_3_account = models.PositiveSmallIntegerField(verbose_name="fun_3_account", blank=True, null=True)
    fun_4_free = models.PositiveSmallIntegerField(verbose_name="fun_4_free", blank=True, null=True)
    fun_5_payed = models.PositiveSmallIntegerField(verbose_name="fun_5_payed", blank=True, null=True)
    fun_6_recurring = models.PositiveSmallIntegerField(verbose_name="fun_6_recurring", blank=True, null=True)

    def __str__(self):
        return str(self.year) + " | M: " + str(self.month) + " | W: " + str(self.calendar_week) + " | " + str(self.last_update)

Hier der Auszug aus dem Django models.py meines Backends. Ich hatte vorsichtshalber die Spalte „calendar_week“ aufgenommen, falls ich mich doch irgendwann dazu entscheide die Kennzahlen auf Wochenebene zu Reporten.

Die eigentliche Auswertung wird dann in meinem Backend in einer Service-Klasse berechnet. Die jeweilige Methode kann über eine API ausgeführt werden. Das gibt mir die Flexibilität den Zeitpunkt der Ausführung von Außen über einen Cron-Job zu steuern.

@api_view(['GET']) @permission_classes([IsAuthenticated]) def run_calculation(request, format=None): if request.user.groups.filter(name="xxxx").exists():

    StatisticService.calculate_csp_c()
    StatisticService.calculate_csp_a()
    StatisticService.calculate_account_created_deleted()
    StatisticService.calculate_month_on_month_growth()

    content = {
        'status': 'OK',
        'message': 'Calculation done',
    }

    return Response(content)

Da die Auswertungen nur wenige Sekunden benötigen, habe ich für den Anfang alle Berechnungen, bis auf die Historischen-Daten, auf einen API Endpunkt gelegt. Falls sich der Rechenaufwand irgendwann erhöhen sollte, habe ich die Flexibilität dies auf mehrere Endpunkte und somit Aufrufe aufzuteilen.

Messen der Benutzer-Account Entwicklung

Bisher hatte ich lediglich eine Gesamtanzahl der Accounts in meinem Backend gesehen. Mit der Zahl lässt sich allerdings wenig anfangen. Das war auch ein Grund warum ich da nie so genau darauf geachtet habe.

Anstelle der Gesamtzahl der User-Accounts habe ich nun gleich 5 unterschiedliche Kennzahlen eingeführt.

  • Customer Acquisition / Month
  • Customer Churn / Month
  • Month on month growth
  • Anzahl User Accounts
  • Monthly active Users (MAU)

Nicht jede der Kannzahlen hat eine eigene Grafik. Manche habe ich in einer Grafik zusammengefasst weil sie entweder einfach gemeinsam mehr Sinn ergeben oder um Platz zu sparen.

Customer Acquisition, Churn & Month on month growth

Gleich drei Kennzahlen habe ich in einer einzigen Grafik untergebracht. Die Kennzahlen gehören für mich zusammen und lassen sich prima gemeinsam Visualisieren. Balkengrafik mit Anzahl der neu erstellten und gelöschten Accounts sowie des monatlichen Wachstums

Anhand der Balken in dieser Grafik lassen sich, die in dem jeweiligen Monat hinzugekommenen Benutzer-Accounts sowie die gelöschten Benutzer-Accounts auf einen Blick ablesen.

Eine weitere Kennzahl welche aus den anderen Beiden resultiert ist der prozentuale Zuwachs an User-Accounts gegenüber dem Vormonat. Hier „Month on month growth %“.

Daran lässt sich direkt der Zuwachs an neuen Benutzern ablesen und man kann erkennen wie schnell (oder langsam) das Unternehmen, zumindest basierend auf der Nutzerzahl, wächst.

Anzahl User Accounts & Monthly active Users (MAU)

Hier sieht man ganz schön die Gesamtanzahl an User Accounts (blau) und kann über die Monate hinweg verfolgen ob sie steigen oder fallen. Grafik mit Verlauf für Anzahl User Accounts und monatlich aktiver User

Darunter die Anzahl der in dem jeweiligen Montag aktiven User Accounts (grün). Natürlich sind nicht alle Veranstalter gleichzeitig aktiv. Manche haben nur ein oder zwei Veranstaltungen im Jahr oder den Account ersteinmal nur zum Testen angelegt. Aus diesem Grund ist die Anzahl der tatsächlich aktiven Accounts im Montag wesentlich geringer. Bei Gelegenheit werde ich hier aber nochmal die Anzahl der aktiven Accounts als prozentuale Darstellung mit implementieren.