@sncf/ngx-piano
v2.0.0
Published
This library aims to provide an integration for the Piano Analytics product into Angular applications
Maintainers
Readme
NgxPiano

This library aims to provide an integration for the Piano Analytics product into Angular applications.
Prerequisite
This library is only compatible with the Angular 16.x.x version and above, make sure to update your project with the following Angular guide
Angular version compatibility
| Angular version | NgxPiano version |
|-----------------|------------------|
| Angular >= 16 | 1.x.x |
| Angular >= 19 | 2.x.x |
Installation
Run npm install @sncf/ngx-piano
Two approaches are available to integrate NgxPiano into your application:
- Standalone (recommended) — using provider functions (
provideNgxPiano,provideNgxPianoFromFactory,provideNgxPianoAsync) - NgModule — using
NgxPianoModule.forRoot(...)⚠️ deprecated, will be removed in the next major version
Standalone setup (recommended)
Use one of the three provider functions in your application configuration.
provideNgxPiano — Static configuration
Use this function when you have a known configuration at application startup.
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideNgxPiano } from '@sncf/ngx-piano';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideNgxPiano({
site: '123456', // replace with your site id
collectDomain: 'piano.example.com', // replace with your collect domain
excludedRoutePatterns: ['excluded*'] // optional
})
]
};provideNgxPianoFromFactory — Factory configuration
Use this function when the configuration needs to be computed or loaded dynamically at runtime. The factory function can return either a NgxPianoConfiguration object or a Promise<NgxPianoConfiguration>.
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideNgxPianoFromFactory, NgxPianoConfiguration } from '@sncf/ngx-piano';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideNgxPianoFromFactory(async () => {
const response = await fetch('/api/piano-config');
const config: NgxPianoConfiguration = await response.json();
return config;
})
]
};This is useful when your Piano configuration depends on environment variables loaded at runtime, a backend endpoint, or any asynchronous source.
provideNgxPianoAsync — Promise-based configuration
A convenience wrapper around provideNgxPianoFromFactory for when you already have a Promise<NgxPianoConfiguration>. The application will wait for the Promise to resolve before initialization completes.
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideNgxPianoAsync, NgxPianoConfiguration } from '@sncf/ngx-piano';
import { routes } from './app.routes';
const configPromise: Promise<NgxPianoConfiguration> = fetch('/api/piano-config').then(res => res.json());
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideNgxPianoAsync(configPromise)
]
};Which function should I use?
| Situation | Function to use |
|-----------|----------------|
| Configuration is known at build time (hardcoded or from environment.ts) | provideNgxPiano |
| Configuration needs to be computed or fetched (async factory logic) | provideNgxPianoFromFactory |
| You already have a Promise<NgxPianoConfiguration> | provideNgxPianoAsync |
NgModule setup (deprecated)
⚠️ Deprecated:
NgxPianoModule.forRoot(...)will be removed in the next major version. Migrate to the standalone provider functions above.
Import NgxPianoModule into your target module and call the forRoot static method with your configuration:
import { NgxPianoModule } from '@sncf/ngx-piano';
@NgModule({
imports: [
NgxPianoModule.forRoot({
site: '123456', // replace with your site id
collectDomain: 'piano.example.com' // replace with your collect domain
})
],
})
export class AppModule {}- The installation is finished !
Usage
Tracking page view
By using NgxPiano (either via a provider function or NgxPianoModule), the different routes are automatically tracked. When NgxPiano is bootstrapping, we subscribe to RouteEvent of type NavigationEnd. This event is triggered when a navigation ends successfully.
Adding info to the page view
Using route data
You can add info to the page view by using the data property of the route.
💡By defining ngxPianoRouteData as a property of the route data, it is not anymore the URL that is sent as page title but the value of the property page of the ngxPianoRouteData object.
import { NgxPianoRouteMetaData } from '@sncf/ngx-piano';
const routes: Routes = [
{
path: 'reservation',
component: 'ReservationComponent',
data: {
ngxPianoRouteData: {
page: 'Reservation',
page_chapter1: 'Home',
page_chapter2: 'Train'
} as NgxPianoRouteMetaData // IMPORTANT to have completion and to respect NgxPianoRouteData attributes
}
}
];Tracking events
Click event
A directive exists for catching click's event named ngxPianoTrackClick. You can track click events directly from the template
<button ngxPianoTrackClick ngxPianoClickName="Login" ngxPianoActionType="ACTION">
Your button text
</button>ngxPianoActionType is an input of the directive of type NgxPianoActionType which is a union type with the different possible values.
Custom events
- standard which are defined by Piano (
page.display,click.action,click.download, ...) - custom which are specific events that you have in your Data Model
You can track custom events by using the NgxPianoService and it's sendEvent(...) method.
- Inject
PianoTrackerinto your component - Call the
sendEvent(...)method ofPianoTrackerwith the event type you want to track and the event data
import {
PianoTracker,
NgxPianoEventType
} from '@sncf/ngx-piano';
@Component({
selector: 'your-component',
template: `
<input type="text" (blur)="onSearchBlur($event)" />
`,
styleUrls: ['./your-component.component.scss']
})
export class YourComponent {
constructor(private pianoTracker: PianoTracker) {
}
/**
* You can track custom events by using the PianoTracker and its trackEvent method
* @param event - The blur event
*/
onSearchBlur(event: FocusEvent) {
const input = event.target as HTMLInputElement;
const customNgxPianoEventType: NgxPianoEventType = "search.value"; // custom event type, not a standard event type => ⚠️MUST BE DEFINED IN YOUR DATA MODEL⚠️
this.pianoTracker.sendEvent(customNgxPianoEventType, {
name: input.name,
value: input.value
});
}
}Tracking some properties
You can add some properties to subsequent events, by using a specific method of PianoTracker service.
⚠️ Custom properties are defined in your Data Model. Refer to it to be able to know which properties you can provide
Imagine you have these properties in your data model:
user_logged:string
You can track these properties throw your events you send to your Piano collect domain.
Example
import { PianoTracker } from '@sncf/ngx-piano';
@Component({
selector: 'your-login-component',
template: '<button (click)="trackProperties()">Track Properties</button>',
})
export class YourLoginComponent {
constructor(private pianoTracker: PianoTracker, private yourAuthenticationService: YourAuthenticationService) {}
async trackProperties() {
await this.yourAuthenticationService.login();
const userProperties = {
user_logged: true,
};
this.pianoTracker.setProperty("user_logged", true, {
persistent: true, // Set a property to next event which will be sent and to all subsequent events
});
}
}Use-case
Set a property to next event which will be sent
pianoTracker.setProperty("property_name", "property_value");Set a property to next event which will be sent and to all subsequent events
pianoTracker.setProperty("property_name", "property_value", { persistent: true });Set a property to next event which will be sent and to all subsequent events of type
page.displaypianoTracker.setProperty("property_name", "property_value", { persistent: true, forEvents: "page.display" });Set a property to next event which will be sent and to all subsequent events of type
page.displayandclick.actionpianoTracker.setProperty("property_name", "property_value", { persistent: true, forEvents: ["page.display", "click.action"] });
FAQ
How to handle multi NgxPianoConfiguration in your app ?
Standalone
const isProduction = true;
const configNonProd: NgxPianoConfiguration = {
site: "non-prod",
collectDomain: 'collect-domain'
};
const configProd: NgxPianoConfiguration = {
site: "prod",
collectDomain: 'collect-domain'
};
const configToUse: NgxPianoConfiguration = isProduction ? configProd : configNonProd;
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideNgxPiano(configToUse)
]
};NgModule (deprecated)
const configToUse: NgxPianoConfiguration = isProduction ? configProd : configNonProd;
@NgModule({
imports: [
NgxPianoModule.forRoot(configToUse)
]
})
export class AppModule { }How to disable tracking in some environment ?
You may want to disable tracker in different environments to avoid tracking some unwanted
usage: local, test, etc.
To do so, just set the disabled property to true:
Standalone
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideNgxPiano({
site: 'your-site-id',
collectDomain: 'your-collect-domain',
disabled: true
})
]
};NgModule (deprecated)
@NgModule({
imports: [
NgxPianoModule.forRoot({
site: 'your-site-id',
collectDomain: 'your-collect-domain',
disabled: true
})
]
})
export class AppModule { }How to exclude a route from tracking ?
Use excludedRoutePatterns option to exclude routes from tracking.
Imagine you want to exclude all routes starting with excluded from tracking:
Standalone
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideNgxPiano({
site: 'your-site-id',
collectDomain: 'your-collect-domain',
excludedRoutePatterns: ['excluded*']
})
]
};NgModule (deprecated)
@NgModule({
imports: [
NgxPianoModule.forRoot({
site: 'your-site-id',
collectDomain: 'your-collect-domain',
excludedRoutePatterns: ['excluded*']
})
]})
export class AppModule {}I don't find my event in my dashboard
You sent a custom event, the request was well send, but you don't retrieve your event on your dashboard?
Check if you have these custom event on your Data Model. If not, your event appears in Events section on the tab Excluded Events on your collect explorer site.
What happened if the same property key is defined both with the setProperty(...) and the properties param in an sendEvent(...) method call
The value defined in the setProperty(...) method overrides the value defined in properties param of the sendEvent(...) method
I host my own Piano script, how to provide it to the library ?
If you host your own Piano script, you can provide it to the library by using the pianoScriptUrl option.
By default, the library will use the last version of Piano script hosted by Piano.
Standalone
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideNgxPiano({
site: 'your-site-id',
collectDomain: 'your-collect-domain',
pianoScriptUrl: 'https://your-piano-script-url' // must be valid otherwise you will get an error in the console
})
]
};NgModule (deprecated)
@NgModule({
imports: [
NgxPianoModule.forRoot({
site: 'your-site-id',
collectDomain: 'your-collect-domain',
pianoScriptUrl: 'https://your-piano-script-url' // must be valid otherwise you will get an error in the console
})
]})
export class AppModule {}