Aller au contenu principal

Signals API

Tracking des signaux d'engagement pour les recommandations personnalisees. Les signaux capturent les comportements de visionnage, les interactions et les preferences pour alimenter le moteur de recommandation.

Base URL : /api/v2/signals

Endpoints

MethodeEndpointDescriptionAuth
POST/signalsEnregistrer un signalOui
POST/signals/batchEnregistrer un batch de signaux (max 100)Oui
GET/signalsObtenir les signaux (pagine)Oui
GET/signals/countsCompteurs agreges par typeOui
GET/signals/most-viewedContenu le plus vuOui
GET/signals/recentActivite recenteOui
GET/signals/has-viewed/:contentIdVerifier si vuOui
GET/signals/progress/:contentIdProgression de visionnageOui
DELETE/signalsEffacer l'historique des signauxOui

POST /signals

Enregistrer un signal d'engagement unique.

POST /api/v2/signals
Authorization: Bearer <access_token>
Content-Type: application/json

{
"type": "CONTENT_VIEW_START",
"contentId": "movie-uuid",
"contentType": "MOVIE",
"metadata": {
"source": "home_carousel",
"position": 3
}
}

Reponse 201 Created

{
"id": "signal-uuid",
"type": "CONTENT_VIEW_START",
"contentId": "movie-uuid",
"contentType": "MOVIE",
"profileId": "profile-uuid",
"createdAt": "2025-01-15T10:30:00Z"
}

POST /signals/batch

Enregistrer plusieurs signaux en une seule requete (maximum 100).

POST /api/v2/signals/batch
Authorization: Bearer <access_token>
Content-Type: application/json

{
"signals": [
{
"type": "CONTENT_IMPRESSION",
"contentId": "movie-uuid-1",
"contentType": "MOVIE",
"timestamp": "2025-01-15T10:00:00Z"
},
{
"type": "CONTENT_VIEW_START",
"contentId": "movie-uuid-1",
"contentType": "MOVIE",
"timestamp": "2025-01-15T10:05:00Z"
}
]
}

Reponse 201 Created

{
"recorded": 2,
"failed": 0,
"errors": []
}

GET /signals/counts

Compteurs agreges par type de signal.

GET /api/v2/signals/counts?from=2025-01-01&to=2025-01-31
Authorization: Bearer <access_token>

Reponse 200 OK

{
"counts": {
"CONTENT_IMPRESSION": 1250,
"CONTENT_VIEW_START": 85,
"CONTENT_PROGRESS": 340,
"CONTENT_COMPLETE": 42,
"CONTENT_ABANDON": 18,
"SEARCH_QUERY": 23,
"CATEGORY_BROWSE": 56,
"FAVORITE_ADD": 12,
"FAVORITE_REMOVE": 3
},
"period": {
"from": "2025-01-01T00:00:00Z",
"to": "2025-01-31T23:59:59Z"
}
}

GET /signals/most-viewed

Contenu le plus visionne par le profil.

GET /api/v2/signals/most-viewed?contentType=MOVIE&limit=10
Authorization: Bearer <access_token>

Reponse 200 OK

{
"data": [
{
"contentId": "series-uuid-1",
"contentType": "SERIES",
"title": "Breaking Bad",
"viewCount": 25,
"totalWatchTime": 54000,
"lastViewedAt": "2025-01-15T10:00:00Z"
}
]
}

GET /signals/has-viewed/:contentId

Verifier si un contenu a ete visionne.

GET /api/v2/signals/has-viewed/movie-uuid
Authorization: Bearer <access_token>

Reponse 200 OK

{
"contentId": "movie-uuid",
"hasViewed": true,
"viewCount": 2,
"firstViewedAt": "2025-01-10T20:00:00Z",
"lastViewedAt": "2025-01-14T21:00:00Z",
"completed": true
}

GET /signals/progress/:contentId

Obtenir la progression de visionnage d'un contenu.

GET /api/v2/signals/progress/movie-uuid
Authorization: Bearer <access_token>

Reponse 200 OK

{
"contentId": "movie-uuid",
"contentType": "MOVIE",
"progress": 0.65,
"position": 4680,
"duration": 7200,
"lastUpdatedAt": "2025-01-15T10:30:00Z",
"completed": false
}

DELETE /signals

Effacer l'historique des signaux du profil.

DELETE /api/v2/signals?type=CONTENT_IMPRESSION&before=2025-01-01
Authorization: Bearer <access_token>

Query Parameters

ParametreTypeDescription
typestringSupprimer uniquement un type specifique
beforeISO dateSupprimer uniquement avant cette date

Reponse 200 OK

{
"message": "Signal history cleared",
"deletedCount": 1250
}

Types de signaux

TypeDescriptionMetadata
CONTENT_IMPRESSIONContenu affiche a l'utilisateursource, position
CONTENT_VIEW_STARTL'utilisateur a commence a regardersource
CONTENT_PROGRESSMise a jour de progressionposition, duration
CONTENT_COMPLETEL'utilisateur a termine le contenucompletionRate
CONTENT_ABANDONL'utilisateur a arrete de regarderposition, reason
SEARCH_QUERYL'utilisateur a effectue une recherchequery, resultCount
SEARCH_CLICKClic sur un resultat de recherchequery, position
CATEGORY_BROWSENavigation dans une categoriecategoryId
FAVORITE_ADDAjout aux favoris--
FAVORITE_REMOVERetrait des favoris--
SHAREPartage de contenuplatform
RATINGEvaluation du contenurating

Poids des signaux dans les recommandations

SignalPoids
Impression0.1
Debut de visionnage0.3
Completion1.0
Ajout aux favoris0.8

Rate Limits specifiques

EndpointLimite
Signal unitaire60 / minute
Batch de signaux10 / minute
Endpoints de lecture100 / minute

Bonnes pratiques

Batching des signaux

Pour la performance, regrouper les signaux :

const signalBuffer: Signal[] = [];

function trackSignal(signal: Signal) {
signalBuffer.push({
...signal,
timestamp: new Date().toISOString(),
});

if (signalBuffer.length >= 10) {
flushSignals();
}
}

async function flushSignals() {
if (signalBuffer.length === 0) return;
const signals = [...signalBuffer];
signalBuffer.length = 0;
await api.post('/signals/batch', { signals });
}

// Envoyer aussi lors du dechargement de page
window.addEventListener('beforeunload', flushSignals);

Tracking de progression

Envoyer la progression a intervalles reguliers (toutes les 30 secondes) :

let lastPosition = 0;

player.on(
'timeupdate',
throttle(() => {
const position = Math.floor(player.currentTime);
if (Math.abs(position - lastPosition) >= 30) {
trackSignal({
type: 'CONTENT_PROGRESS',
contentId: currentContentId,
contentType: 'MOVIE',
metadata: { position, duration: Math.floor(player.duration) },
});
lastPosition = position;
}
}, 5000),
);

Codes d'erreur

CodeHTTPDescription
SIGNAL_001400Type de signal invalide
SIGNAL_002400ID de contenu invalide
SIGNAL_003400Batch trop volumineux (max 100)
SIGNAL_004429Rate limit depasse