@kundai/angular
v1.1.1
Published
Module Angular KundAi — tracking sessions, UTM, conversions et identify en 2 lignes.
Maintainers
Readme
@kundai/angular
Module Angular officiel pour intégrer le tracking KundAi dans une application Angular.
Sommaire
- Installation
- Configuration
- Démarrage automatique
- Identifier un utilisateur
- Événements
- Conversions
- Passer le sessionId au backend
- Référence API
- Ce qui est collecté automatiquement
Installation
npm install @kundai/angularVersions Angular supportées : Angular 16, 17, 18, 19+
Configuration
Les deux modes de déploiement
Le baseUrl détermine vers qui le frontend envoie les données de tracking.
Deux modes sont possibles :
Mode direct — le frontend appelle KundAi directement
Frontend Angular ──────────────────────────────► KundAi tracking :3002Simple, aucun backend intermédiaire. Utiliser quand le backend Ndewa360 n'a pas besoin d'être dans la boucle pour les événements navigateur.
...KundaiModule.forRoot({
baseUrl: environment.kundaiTrackingUrl, // 'https://api.kundai.io/v1/tracking'
apiKey: environment.kundaiApiKey, // clé API KundAi
appId: 'ndewa360-web',
})Mode proxy — le frontend passe par le backend Ndewa360
Frontend Angular ──► Backend Ndewa360 (/tracking/*) ──► KundAi tracking :3002Utile si tu veux ajouter de la logique métier avant le tracking (vérification
d'authentification, enrichissement des événements, validation). Le backend
Ndewa360 doit avoir @kundai/nestjs installé et configuré.
...KundaiModule.forRoot({
baseUrl: environment.ndewa360ApiUrl + '/tracking', // 'https://api.ndewa360.com/tracking'
apiKey: environment.ndewa360ApiKey, // ton token d'auth Ndewa360 (pas la clé KundAi)
appId: 'ndewa360-web',
})Dans ce mode, c'est le backend Ndewa360 qui détient la clé API KundAi. Le frontend ne la connaît pas.
Quel mode choisir ?
| | Mode direct | Mode proxy | |---|---|---| | Simplicité | ✅ aucun backend intermédiaire | ❌ backend requis | | Clé API KundAi exposée | dans le frontend (visible) | uniquement côté serveur | | Logique métier avant tracking | ❌ impossible | ✅ possible | | Latence | plus faible | légèrement plus élevée |
Pour Ndewa360, le mode direct est recommandé pour les événements navigateur (sessions, pages vues, clics). Le mode proxy n'est utile que si tu as des exigences de sécurité spécifiques (ne pas exposer la clé API KundAi dans le bundle JS).
App standalone (Angular 17+)
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { KundaiModule } from '@kundai/angular';
import { routes } from './app.routes';
import { environment } from '../environments/environment';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
...KundaiModule.forRoot({
baseUrl: environment.kundaiTrackingUrl,
apiKey: environment.kundaiApiKey,
appId: 'ndewa360-web',
}),
],
};AppModule (Angular classique)
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { KundaiModule } from '@kundai/angular';
import { environment } from '../environments/environment';
@NgModule({
imports: [BrowserModule],
providers: [
...KundaiModule.forRoot({
baseUrl: environment.kundaiTrackingUrl,
apiKey: environment.kundaiApiKey,
appId: 'ndewa360-web',
}),
],
})
export class AppModule {}Options de configuration
| Option | Type | Requis | Description |
|---|---|---|---|
| baseUrl | string | ✅ | URL du endpoint de tracking (KundAi direct ou backend proxy) |
| apiKey | string | ✅ | Clé API KundAi (mode direct) ou token d'auth backend (mode proxy) |
| appId | string | — | Identifiant de ton app (défaut : "web") |
| timeoutMs | number | — | Timeout des requêtes HTTP en ms (défaut : 5000) |
| autoPageView | boolean | — | Page-view auto à chaque route (défaut : true) |
Variables d'environnement
Mode direct — le frontend appelle KundAi directement :
// environments/environment.ts
export const environment = {
production: false,
kundaiTrackingUrl: 'http://localhost:3000/v1/tracking', // api-gateway KundAi en local
kundaiApiKey: 'kundai_xxxxxxxxxxxx', // clé API KundAi
};
// environments/environment.prod.ts
export const environment = {
production: true,
kundaiTrackingUrl: 'https://api.kundai.io/v1/tracking',
kundaiApiKey: 'kundai_xxxxxxxxxxxx',
};Mode proxy — le frontend passe par le backend Ndewa360 :
// environments/environment.ts
export const environment = {
production: false,
// Le backend Ndewa360 expose POST /tracking/* via @kundai/nestjs
kundaiTrackingUrl: 'http://localhost:4000/tracking',
// Vide : le backend gère lui-même l'authentification vers KundAi
// Ou un token JWT Ndewa360 si tes routes /tracking/* sont protégées
kundaiApiKey: '',
};
// environments/environment.prod.ts
export const environment = {
production: true,
kundaiTrackingUrl: 'https://api.ndewa360.com/tracking',
kundaiApiKey: '',
};En mode proxy, la clé API KundAi reste uniquement dans les variables d'environnement du backend Ndewa360 (
KUNDAI_API_KEY). Elle n'est jamais exposée dans le bundle JavaScript du frontend.
Démarrage automatique
Dès que KundaiModule.forRoot() est configuré, le module :
- Génère un
visitorIdpersistant (localStorage) - Capture les paramètres UTM et ad click IDs depuis l'URL
- Enregistre un clic si des UTM sont présents (touchpoint d'attribution)
- Démarre une session
- Enregistre la première page-view
- Écoute les changements de route Angular et enregistre une page-view à chaque
NavigationEnd - Clôture la session à la fermeture de l'onglet (
pagehide)
Aucun code supplémentaire n'est nécessaire pour ces comportements.
Identifier un utilisateur
À appeler après la connexion de l'utilisateur pour lier son identité à la session.
import { inject, Injectable } from '@angular/core';
import { KundaiService } from '@kundai/angular';
@Injectable({ providedIn: 'root' })
export class AuthService {
private readonly kundai = inject(KundaiService);
async afterLogin(user: { id: string; email: string }) {
// Lie l'utilisateur à la session navigateur courante
await this.kundai.identify(user.id, user.email);
}
afterLogout() {
// Efface l'identité locale (ne clôture pas la session)
this.kundai.clearUser();
}
}L'email n'est jamais stocké en clair — il est haché SHA-256 côté serveur avant persistance en base de données.
Événements
Événements comportementaux libres
track() accepte n'importe quel nom d'événement et des propriétés libres.
import { Component, inject } from '@angular/core';
import { KundaiService } from '@kundai/angular';
@Component({ ... })
export class MyComponent {
private readonly kundai = inject(KundaiService);
onButtonClick() {
this.kundai.track('button_click', { button: 'cta_hero', plan: 'pro' });
}
onFormSubmit() {
this.kundai.track('form_submit', { form: 'contact' });
}
onVideoPlay(videoId: string) {
this.kundai.track('video_play', { videoId });
}
}Événements recommandés par catégorie
Ces noms sont des conventions — KundAi les reconnaît et les affiche dans le dashboard.
Acquisition / Onboarding
| Événement | Propriétés suggérées | Description |
|---|---|---|
| page_view | url, title | Vue de page (automatique) |
| signup_started | plan, source | Début d'inscription |
| signup_completed | plan, method | Inscription terminée |
| account_created | plan, country | Compte créé |
| login | method | Connexion réussie |
| logout | — | Déconnexion |
Engagement
| Événement | Propriétés suggérées | Description |
|---|---|---|
| button_click | button, page | Clic sur un bouton |
| form_submit | form | Soumission de formulaire |
| search | query, results_count | Recherche effectuée |
| video_play | videoId, duration | Lecture vidéo |
| download | file, type | Téléchargement |
| share | platform, content | Partage |
| feature_used | feature | Fonctionnalité utilisée |
Funnel commercial
| Événement | Propriétés suggérées | Description |
|---|---|---|
| plan_viewed | plan | Page de tarification vue |
| plan_selected | plan, price, currency | Plan sélectionné |
| checkout_started | plan, amount, currency | Paiement initié |
| checkout_abandoned | plan, step | Paiement abandonné |
Conversions (déclenchent l'attribution dans KundAi)
| Événement | Propriétés requises | Propriétés optionnelles |
|---|---|---|
| purchase | amount, currency | planId, txRef |
| payment | amount, currency | planId, provider |
| conversion | amount, currency | planId |
| checkout | amount, currency | planId |
Les événements
purchase,payment,conversionetcheckoutsont traités spécialement par KundAi : ils déclenchent le moteur d'attribution et marquent la session comme convertie.
Conversions
Conversion côté frontend (paiement popup)
Pour les paiements confirmés directement dans le navigateur (ex. Flutterwave popup) :
onPaymentSuccess(result: { amount: number; currency: string; planId: string }) {
this.kundai.trackConversion({
amount: result.amount,
currency: result.currency,
planId: result.planId,
event: 'purchase',
});
}Conversion côté serveur (webhook)
Pour les paiements confirmés par webhook (Flutterwave, Stripe, etc.), le frontend
doit passer son sessionId au backend. Voir la section suivante.
Passer le sessionId au backend
Le sessionId est le lien entre la session navigateur et les conversions confirmées
côté serveur. Sans lui, l'attribution est aveugle.
// checkout.component.ts
import { Component, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { KundaiService } from '@kundai/angular';
@Component({ ... })
export class CheckoutComponent {
private readonly kundai = inject(KundaiService);
private readonly http = inject(HttpClient);
async pay(planId: string, amount: number) {
this.kundai.track('checkout_started', { planId, amount, currency: 'XOF' });
await this.http.post('/api/payments/checkout', {
planId,
amount,
currency: 'XOF',
sessionId: this.kundai.getSessionId(), // ← transmettre au backend
}).toPromise();
}
}Le backend stocke ce sessionId et le renvoie à KundAi lors de la confirmation
du paiement via @kundai/nestjs. Voir la documentation de @kundai/nestjs.
Référence API
// Injecter le service
private readonly kundai = inject(KundaiService);
// Identifier l'utilisateur connecté
await kundai.identify(userId: string, email?: string): Promise<void>
// Effacer l'identité locale (après logout)
kundai.clearUser(): void
// Envoyer un événement comportemental
kundai.track(event: string, properties?: Record<string, unknown>): void
// Notifier une conversion avec revenu (retry automatique x3)
kundai.trackConversion(opts: {
amount: number
currency: string // ISO 4217 : 'XOF', 'EUR', 'USD', 'GHS', 'NGN'...
planId?: string
event?: 'conversion' | 'purchase' | 'payment' | 'checkout'
metadata?: Record<string, unknown>
}): void
// Enregistrer manuellement une page-view
await kundai.recordPageView(): Promise<void>
// Récupérer le sessionId courant (à passer au backend)
kundai.getSessionId(): string | null
// Récupérer le visitorId courant
kundai.getVisitorId(): stringCe qui est collecté automatiquement
| Donnée | Stockage | Note |
|---|---|---|
| visitorId | localStorage | UUID généré à la première visite |
| UTM (utm_source, utm_medium, utm_campaign, utm_content, utm_term) | localStorage | Capturés depuis l'URL, persistés pour les conversions futures |
| Ad click IDs (fbclid, gclid, ttclid, liclid) | localStorage | Capturés depuis l'URL |
| IP address | Serveur | Anonymisée (dernier octet masqué IPv4, 80 bits IPv6) |
| User-Agent | Serveur | Utilisé pour détecter device/browser/OS |
| Email | Serveur | Haché SHA-256, jamais stocké en clair |
