Plausible daran hindern, bei einem 404-Fehler in Laravel einen Pageview zu zählen

Ich nutze Plausible für Analytics sehr gerne. Google Analytics (im Folgenden nur GA) war mir „etwas“ zu viel, zumal mich PageSpeed Insights jedes Mal darauf hinweist, dass das GA-Skript „zu schwer“ ist (ironischerweise).

Was mich besonders überzeugt hat, war ihre Dokumentation – kurz, einfach, aber wirkungsvoll. Besonders gefallen haben mir die Installations-/Integrationsanleitungen (dort wird ausdrücklich Laravel erwähnt, mein bevorzugtes Werkzeug, das in solcher Dokumentation manchmal gar nicht auftaucht).

Problem mit der Route

Für diese Website habe ich mir das Composer-Paket vincentbean/laravel-plausible besorgt, und die Integration verlief ziemlich reibungslos. Leider ist mir jedoch nach einem Monat Nutzung ein Problem aufgefallen – jede Menge sinnloser Anfragen an nicht existierende Seiten und Ressourcen. Das war durchaus nachvollziehbar, denn eine der Routen war eine Wildcard-Route wie diese hier:

Route::get('/{slug}', [PageController::class, 'page'])->where('slug', '^(?!.*\.|^\/(favicon|css|js|storage|build)).*$')->name('page');

Liste der Spam-Anfragen

Als diese Liste von Endpunkten in meinem Dashboard auftauchte, dachte ich mir: kein großes Problem, ich schließe sie einfach aus, dann passt es. Das klang nach einer soliden Idee... Menschenskind, wie ich mich täuschte... Hier ist, was mich erwartete, nachdem ich alle grundlegenden Endpunkte zum Ausschluss hinzugefügt hatte:

Liste zufälliger Endpunkte russischer Banken

Als ich diese Liste von Endpunkten irgendwelcher russischer Banken sah, wurde mir klar, dass alles einzeln herauszufiltern definitiv nicht der richtige Weg für mich ist. Also habe ich mir erst mal eine Limo mit Eis geholt und dann nach der schmerzlosesten Lösung mit minimalem Codeaufwand gesucht.

Ziele

Hier ist im Grunde das Verhalten, das ich mir erwartet habe:

  1. Event auslösen, wenn das Paket konfiguriert ist;
  2. Event auslösen, wenn die Seite existiert;
  3. Event auslösen, wenn es sich nicht um die CLI handelt (quasi als Bonus, weil das die Statistik auch etwas verfälscht hat);

Die Lösung

Die Middleware im Paket kümmerte sich ziemlich gut um Punkt 1, aber die Punkte 2 und 3 blieben ungelöst. Also habe ich mir die Middleware angesehen, die – wie die meisten Middlewares – eigentlich ziemlich leer war, und ihren Code folgendermaßen verbessert:

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;
use VincentBean\Plausible\Facades\PlausibleEvent;

class TrackPlausiblePageviews
{
    public function handle(Request $request, Closure $next): mixed
    {
        $response = $next($request);

        if (config('plausible.tracking_domain') !== null 
						&& $response->status() !== Response::HTTP_NOT_FOUND 
						&& is_string($request->userAgent())
            && !in_array($request->userAgent(), config('plausible.ignore_agents'))) {
            PlausibleEvent::fire('pageview');
        }

        return $response;
    }

Also, erstens prüfe ich nach wie vor, ob tracking_domain konfiguriert ist, denn wenn nicht, gibt es ohnehin keinen Grund, mit dem Event fortzufahren. Danach nutze ich eine Out-of-the-box-Funktionalität von Laravel – das Werfen eines 404 bei Verwendung von firstOrFail(). Und schließlich wird sauber der User Agent geprüft, weil ich sonst von meinem eigenen Sitemap-Generator zugespammt werde.

In config/plausible.php habe ich einfach die lästigen Agents hinzugefügt (und ja, ich habe sie hart codiert, weil sie sich nicht so oft ändern). Fügen Sie diesen also gerne auch Ihrer Konfiguration hinzu:

	'ignore_agents' => [
        'GuzzleHttp/7'
    ],

Fazit

Ich nehme an, jeder kennt den Spruch „Never touch a running system“. Nun, in diesem speziellen Fall stimme ich dieser Aussage zu. Mein Problem wurde mit nur ein paar Zeilen Code gelöst, und meine eisgekühlte Limo ist noch nicht einmal leer.

P.S. An das Plausible-Team – wie kann ich EINIGE der alten Einträge in Analytics löschen? 😅