Inhaltsverzeichnis
In diesem Folgebeitrag zeige ich Ihnen, wie Sie neue Attribute zu Ihrem Tracking-Datensatz hinzufügen können. Wir werden den UserAgent, Pfadnamen, Mobile, Plattform, Region und Stadt hinzufügen. Alle Daten werden in einer Neon.tech Postgres-DB über Prisma ORM gespeichert, wie im vorherigen Beitrag.
Hier ist das GitHub Repo mit dem gesamten Code und darunter der Link zur Beispielwebsite.
Beispielseite für mit integrierter Datenerfassung -> https://nextjs14-kafka-tracking.vercel.app/
Prisma-Schema für neue Attribute
Wir haben eine neue Tabelle „customtracking“ zu unserem schema.prisma hinzugefügt, damit diese Tabelle in unserem Postgres DB Service neon.tech erstellt wird. Wir müssen den folgenden Befehl ausführen, um unser Schema mit der DB zu synchronisieren
npx prisma db pushNeue schema.prisma-Datei
Wir haben neue Attribute wie Stadt, Region, Pfadname, Useragent, Plattform und Mobile hinzugefügt.
model customtracking {
id Int @id @default(autoincrement())
country String?
city String?
region String?
url String?
pathname String?
mobile Boolean?
platform String?
useragent String?
referer String?
created_at DateTime?
sessionId String?
userId String?
pageViewId String?
addedOn DateTime @default(now())
}Anpassung des existierenden Tracking Hook
Wir werden den Tracking-Hook, den wir in der letzten Geschichte erstellt haben, anpassen.
Geänderter usePageTracking Hook
Die Hauptlogik befindet sich in der usePageTracking-Hook. Der vollständige Code ist unten zu sehen.
//src/lib/hooks/usePageTracking.ts
"use client";
import { useEffect, useState } from "react";
import FingerprintJS from "@fingerprintjs/fingerprintjs";
// Define the type for the page view data
interface PageViewData {
pageViewID: string;
sessionID: string;
userID: string;
url: string;
referrer: string;
timestamp: string;
country: string;
city: string;
region: string;
pathname: string;
userAgent: string;
platform: string;
isMobileDevice: boolean;
}
// Define the type for the time spent data
interface TimeSpentData {
sessionID: string;
userID: string;
timeSpent: number;
url: string;
pathname: string;
userAgent: string;
platform: string;
isMobileDevice: boolean;
country?: string;
city?: string;
region?: string;
}
function createSessionID(): string {
return "session-" + Math.random().toString(36).substr(2, 16);
}
function createPageViewID(): string {
return "view-" + Math.random().toString(36).substr(2, 16);
}
function getSessionID(): string {
let sessionId = localStorage.getItem("session_id");
if (!sessionId) {
sessionId = createSessionID();
localStorage.setItem("session_id", sessionId);
}
return sessionId;
}
async function sendToPrisma(message: any) {
// Pushing tracking Info direct to Postgres
await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/user/customtracking`, {
method: "POST",
body: JSON.stringify(message),
});
}
async function getUserID(): Promise<string> {
const fpPromise = FingerprintJS.load();
const fp = await fpPromise;
const result = await fp.get();
return result.visitorId; // This is the anonymous user ID
}
async function getUserCountry(): Promise<string> {
try {
const response = await fetch("https://ipapi.co/json/");
const data = await response.json();
return data.country_name || "Unknown";
} catch (error) {
console.error("Error fetching country:", error);
return "Unknown";
}
}
async function getUserLocation(): Promise<{
country: string;
city: string;
region: string;
}> {
try {
const response = await fetch("https://ipapi.co/json/");
const data = await response.json();
return {
country: data.country_name || "Unknown",
city: data.city || "Unknown",
region: data.region || "Unknown",
};
} catch (error) {
console.error("Error fetching location:", error);
return {
country: "Unknown",
city: "Unknown",
region: "Unknown",
};
}
}
function getPlatform(): string {
return navigator.platform || "Unknown";
}
function isMobileDevice(): boolean {
const userAgent =
navigator.userAgent ||
navigator.vendor ||
(window as Window & { opera?: string }).opera;
// Check if the user agent matches typical mobile devices
if (/android/i.test(userAgent || "")) {
return true;
}
if (
/iPad|iPhone|iPod/.test(userAgent || "") &&
!(window as Window & { MSStream?: unknown }).MSStream
) {
return true;
}
return false;
}
async function capturePageView(userID: string): Promise<void> {
const pageViewID = createPageViewID();
const sessionID = getSessionID();
const url = window.location.href;
const referrer = document.referrer;
const timestamp = new Date().toISOString();
const country = await getUserCountry();
const { city, region } = await getUserLocation();
const pathname = window.location.pathname;
const userAgent = navigator.userAgent;
const platform = getPlatform();
const mobileDevice = isMobileDevice();
const pageViewData: PageViewData = {
pageViewID: pageViewID,
sessionID: sessionID,
userID: userID,
url: url,
referrer: referrer,
timestamp: timestamp,
country: country,
city: city,
region: region,
pathname: pathname,
userAgent: userAgent,
platform: platform,
isMobileDevice: mobileDevice,
};
sendDataToServer(pageViewData);
}
function sendDataToServer(data: PageViewData | TimeSpentData): void {
const trackdata: any = data;
const message = {
country: trackdata.country,
city: trackdata.city,
region: trackdata.region,
pathname: trackdata.pathname,
url: trackdata.url,
mobile: trackdata.isMobileDevice,
platform: trackdata.platform,
useragent: trackdata.userAgent,
referer: trackdata.referrer,
userId: trackdata.userID,
pageViewId: trackdata.pageViewID,
sessionId: trackdata.sessionID,
created_at: trackdata.timestamp,
};
sendToPrisma(message);
}
export default function usePageTracking(): void {
const [userID, setUserID] = useState<string | null>(null);
useEffect(() => {
// Initialize user ID and start tracking
const initializeTracking = async () => {
const id = await getUserID();
setUserID(id);
await capturePageView(id);
};
initializeTracking();
const pageLoadTime = Date.now();
const handleBeforeUnload = async () => {
if (userID) {
const timeSpent = Date.now() - pageLoadTime;
const url = window.location.href;
const pathname = window.location.pathname;
const userAgent = navigator.userAgent;
const platform = getPlatform();
const mobileDevice = isMobileDevice();
const { country, city, region } = await getUserLocation(); // get location before unload
const timeSpentData: TimeSpentData = {
sessionID: getSessionID(),
userID: userID,
timeSpent: timeSpent,
url: url,
pathname: pathname,
userAgent: userAgent,
platform: platform,
isMobileDevice: mobileDevice,
country: country,
city: city,
region: region,
};
sendDataToServer(timeSpentData);
}
};
window.addEventListener("beforeunload", handleBeforeUnload);
return () => {
window.removeEventListener("beforeunload", handleBeforeUnload);
};
}, [userID]);
}Um das Skript so zu erweitern, dass es den userAgent, den Pfadnamen, mobiles Gerät oder nicht, die Plattform und die Stadt verfolgt, aktualisieren wir den usePageTracking-Hook entsprechend.
Erläuterung der Zusätze und Anpassungen:
Der userAgent wird aus dem navigator.userAgent-Objekt abgerufen. Dieser String enthält Informationen über den Browser, das Betriebssystem und das Gerät.
Der Pfadname wird von window.location.pathname abgerufen, der Ihnen den Pfad der URL relativ zur Domäne angibt.
Die Plattform wird über navigator.platform abgefragt. Diese gibt das Betriebssystem oder die Umgebung an, in der sich der Benutzer befindet, z. B. Win32 für Windows, MacIntel für macOS usw.
Die Funktion isMobileDevice prüft anhand der Zeichenkette userAgent, ob das Gerät des Benutzers wahrscheinlich ein mobiles Gerät ist. Sie prüft auf gängige Identifikatoren für mobile Geräte wie Android, iPhone, iPad, usw. Sie gibt true zurück, wenn ein mobiles Gerät erkannt wird, und false, wenn nicht.
Die Funktion getUserLocation gibt nun ein Objekt zurück, das Land, Stadt und Region unter Verwendung der ipapi.co API. Diese Daten werden über die API-Antwort abgerufen und enthalten den Fallback-Wert Unknown, wenn die Daten nicht verfügbar sind.
Sie können den Hook noch weiter ausbauen, wenn Sie zusätzliche Attribute verfolgen möchten.
Neue Route zum Schreiben von Daten in die Neon.tech-Tabelle „customtracking“
Da wir eine neue Tabelle „customtracking“ erstellt haben, werden wir auch eine neue API-Route erstellen, damit wir die Logik klar trennen können.
import prisma from "@/lib/prisma";
import { NextResponse } from "next/server";
export async function POST(req: Request) {
const {
country,
city,
region,
pathname,
url,
mobile,
platform,
useragent,
referer,
created_at,
userId,
pageViewId,
sessionId,
} = await req.json();
let data = await prisma.customtracking.create({
data: {
country: country,
city: city,
region: region,
pathname: pathname,
url: url,
mobile: mobile,
platform: platform,
useragent: useragent,
referer: referer,
created_at: created_at,
userId: userId,
pageViewId: pageViewId,
sessionId: sessionId,
},
});
return NextResponse.json({
data,
});
}Das war's. Jetzt haben wir ein vollständiges Tracking unserer Nutzer auf der Seite. Bitte vergessen Sie nicht, die GDPR-Regeln zu beachten und das Tracking nur zu aktivieren, wenn Sie dazu berechtigt sind.
Cloudapp-dev und bevor Sie uns verlassen
Danke, dass Sie bis zum Ende gelesen haben. Noch eine Bitte bevor Sie gehen:

