Quando si sviluppa un prodotto digitale, prima o poi nasce una domanda concreta: le funzionalità che abbiamo costruito vengono davvero usate?
Le page view da sole spesso non bastano. In una web application può essere più utile sapere se un utente ha iniziato un workflow, se lo ha completato, se ha usato una funzione opzionale o se ha espresso un feedback positivo o negativo.
Il problema è che molte applicazioni trattano dati che non vogliamo necessariamente inviare a un servizio analytics esterno: valori economici, dati di processo, informazioni aziendali, testi inseriti dall’utente o semplicemente dettagli che non servono per rispondere alle domande di prodotto.
Da un'esigenza reale emersa durante lo sviluppo di una web application è nato il progetto open-source Privacy-Friendly Analytics for ASP.NET Core.
Il problema: product analytics senza tracking indiscriminato
Immaginiamo un’applicazione in cui il calcolo principale avviene nel browser. Dal punto di vista del prodotto vogliamo sapere quante persone iniziano il flusso, quante lo completano, quali funzioni opzionali vengono utilizzate e se il feedback è positivo o negativo.
Per rispondere a queste domande non serve conoscere i valori inseriti nei campi. Possiamo modellare l’analytics come una sequenza di eventi:
demo_opened
workflow_started
workflow_completed
feature_used
feedback_submittedIl server riceve quindi il fatto che un evento sia avvenuto, non il contenuto funzionale che ha prodotto quell’evento.
Architettura generale
[Browser / TypeScript]
|
| POST /api/analytics/events
v
[ASP.NET Core endpoint]
|
v
[IAnalyticsService]
|
v
[EF Core]
|
v
[SQL Server]
|
v
[Dashboard]La soluzione separa Application, Infrastructure e Web. Il progetto Web dipende da IAnalyticsService, mentre il dettaglio di persistenza resta nell’Infrastructure layer.
Eventi e proprietà esplicitamente consentiti
Un client non dovrebbe poter inviare arbitrariamente qualsiasi evento o proprietà. Nel progetto gli eventi ammessi sono definiti esplicitamente e il server rifiuta quelli sconosciuti.
public static class AnalyticsEventNames
{
public const string DemoOpened = "demo_opened";
public const string WorkflowStarted = "workflow_started";
public const string WorkflowCompleted = "workflow_completed";
public const string FeatureUsed = "feature_used";
public const string FeedbackSubmitted = "feedback_submitted";
}Lo stesso principio vale per le proprietà: vengono applicate allow-list, limiti sulla lunghezza e filtri sui tipi JSON accettati.
Cosa viene salvato e cosa no
Viene salvato: nome evento, timestamp UTC, identificatore casuale della sessione di pagina, path e un piccolo insieme di proprietà consentite.
Non viene salvato: valore dei campi del form, dati economici o business, email, testi liberi, IP esplicitamente persistiti dall’applicazione o identificatori permanenti del browser.
Questa distinzione è fondamentale: la telemetria deve essere progettata a partire dalle domande che vogliamo risolvere, non dalla quantità massima di dati che possiamo raccogliere.
Nessun identificatore persistente del browser
Per correlare gli eventi della stessa apertura pagina viene generato un UUID casuale in memoria:
const sessionId = crypto.randomUUID();Non viene scritto in cookie o localStorage. Questo limita alcune metriche, come la distinzione tra visitatori nuovi e di ritorno, ma evita di introdurre persistenza quando non è necessaria.
Best-effort telemetry
Una decisione architetturale importante è che la telemetria non deve diventare una dipendenza del flusso principale. Se l’endpoint analytics o SQL Server sono temporaneamente indisponibili, il workflow dell’utente deve continuare.
Il client invia quindi gli eventi in modo asincrono, con timeout breve e gestione degli errori.
Rate limiting dell’endpoint
Un endpoint che riceve eventi dal browser è pubblico per definizione. Nel progetto viene applicato il rate limiting integrato in ASP.NET Core con una finestra fissa. In produzione i limiti andrebbero dimensionati sul traffico reale e sul modello di deployment.
Dashboard e metriche
La demo include una dashboard minimale con numero totale di eventi, sessioni, workflow iniziati e completati, completion rate, percentuale di feedback positivo, conteggio per tipo e ultimi eventi ricevuti.
Per un prodotto piccolo queste informazioni sono spesso sufficienti per rispondere alle prime domande di utilizzo senza introdurre una piattaforma analytics più complessa.
Testare anche ciò che non deve essere salvato
I test verificano anche le regole di minimizzazione: proprietà sconosciute eliminate, stringhe troppo lunghe limitate e oggetti JSON annidati rifiutati. In questo modo alcune decisioni di privacy diventano vincoli tecnici verificabili.
Build e test automatici con GitHub Actions
Il repository esegue automaticamente restore, build e test ad ogni push o pull request verso main. È una pipeline semplice, ma verifica che il progetto continui a funzionare anche su un ambiente pulito.
Quando questo approccio ha senso
Una soluzione self-hosted minimale è adatta quando servono poche metriche ben definite, si vuole evitare di inviare dati business a terze parti, l’applicazione ha già un backend e un database e il volume degli eventi è moderato.
Se servono attribution avanzata, funnel complessi, session replay, sperimentazione o grandi volumi, una piattaforma analytics dedicata può invece essere la scelta migliore.
Prima della produzione
- proteggere la dashboard con autenticazione e autorizzazione;
- definire retention e cleanup automatico;
- spostare le connection string in un secret store;
- controllare che i log non acquisiscano request body sensibili;
- rivedere rate limiting e strategia di ingestion;
- valutare queue o batching per volumi elevati;
- rivedere periodicamente allow-list di eventi e proprietà.
FAQ
È un’alternativa a Google Analytics o ad altre piattaforme analytics?
Non necessariamente. È una reference implementation per casi in cui bastano poche metriche di prodotto e si preferisce mantenere la telemetria self-hosted.
Perché non salvare un identificatore persistente anonimo?
Perché nel caso d’uso iniziale non era necessario riconoscere lo stesso browser nelle visite successive. Se quella metrica diventa importante, la scelta può essere rivalutata esplicitamente.
Perché usare un dizionario di proprietà se poi viene limitato?
Per mantenere il modello generico senza rinunciare al controllo. La flessibilità resta, ma il server decide quali proprietà possono essere persistite.
Repository open-source
Il codice completo è disponibile nel repository Drik81/privacy-friendly-analytics, con .NET 10, ASP.NET Core, EF Core, SQL Server, TypeScript, Docker, test e GitHub Actions.
La domanda corretta non è “quanti dati possiamo raccogliere?”, ma “quali dati ci servono davvero per migliorare il prodotto?”.
In sintesi
Raccogliere meno dati può essere sufficiente per prendere decisioni migliori sul prodotto.
Una telemetria utile non deve necessariamente registrare tutto ciò che l'utente fa o inserisce. Eventi espliciti, proprietà limitate e persistenza self-hosted possono essere sufficienti per misurare l'adozione delle funzionalità mantenendo sotto controllo i dati raccolti.
Guide correlate
Vuoi introdurre telemetria o analytics in un'applicazione .NET senza raccogliere più dati del necessario?
Posso supportare software house e team di sviluppo nella progettazione di telemetria applicativa, API, logging e osservabilità, definendo quali eventi raccogliere e come integrarli senza rendere l'analytics una dipendenza critica del prodotto.