Identify Session After Login
Bind the current authenticated userId to a previously-anonymous session id. Idempotent. Lets analytics correlate pre-login traffic with the resulting account.
PATCH /api/v1/analytics/session/:id/identify — 🔑 Bearer
Sets AnalyticsSession.userId for an existing session. Call this once, right after login or signup completes — the session was created anonymously (likely before the user authenticated), and this pulls the user identity onto it so all the prior pageviews in that session can be attributed correctly.
Idempotent and overwrite-friendly. The service does a flat update({ where: { id }, data: { userId } }) — calling it twice with the same userId is a no-op. Calling it with a different userId overwrites the previous one, so don't share session ids across users (a logout-then-login on the same anonymous session would reattribute prior views to the second user).
No 404 / 401 cross-checks. The service silently swallows update failures (update.catch(() => {})). If the session id doesn't exist or the DB rejects the write, the response is still 200 { ok: true } — you can't programmatically detect a bad id. The auth check (@CurrentUser('id') requires a valid bearer) is the only real gate.
userId comes from the JWT, not the body. The endpoint reads userId via @CurrentUser('id') — there is no way to identify a session as someone else. To unbind, you'd need a separate endpoint (none today). To re-identify after logout, the new session should be created fresh.
Request
Path parameters
| Param | Type | Required | Notes |
|---|---|---|---|
id | string (UUID) | ✓ | Session id from POST /analytics/session. Not validated server-side — bad ids no-op. |
Headers
| Header | Required | Notes |
|---|---|---|
Authorization: Bearer <accessToken> | ✓ | Global JwtAuthGuard. The user from this token is bound to the session. |
No body.
Response
200 OK — ApiResponseOf<IdentifySessionResultDto>
{ "success": true, "data": { "ok": true } }Errors
| HTTP | Reason |
|---|---|
401 | Missing / invalid bearer token. |
The endpoint has no documented 404 or 400 paths — bad session ids and DB failures collapse to a successful response.
Side effects
- Decode bearer (global
JwtAuthGuard);userId = req.user.id. analyticsDb.analyticsSession.update({ where: { id }, data: { userId } }).catch(() => {}). Single SQL UPDATE; failures swallowed.- Return
{ ok: true }.
No throttle on this endpoint. The class registers @UseGuards(ThrottleGuard) but this handler has no @Throttle() decorator and the guard returns true when no decorator is present. In practice clients should call it at most once per session (right after auth completes), so a missing throttle is fine.
Code samples
curl -X PATCH https://api.bio.re/api/v1/analytics/session/ses-uuid/identify \
-H "Authorization: Bearer $ACCESS_TOKEN"async function identifySession(
accessToken: string,
sessionId: string,
): Promise<void> {
await fetch(`https://api.bio.re/api/v1/analytics/session/${sessionId}/identify`, {
method: 'PATCH',
headers: { Authorization: `Bearer ${accessToken}` },
}).catch(() => {});
}// Run this once, immediately after a successful login/signup.
// The session was started anonymously when the page first loaded.
async function onLoginSuccess(accessToken: string) {
const sessionId = window.__ANALYTICS_SESSION_ID__; // captured from createSession()
if (!sessionId) return;
await identifySession(accessToken, sessionId);
// No need to re-fire; the binding persists for the lifetime of the session.
}Try it
Authorization
bearer In: header
Path Parameters
Response Body
application/json
application/json
curl -X PATCH "https://loading/api/v1/analytics/session/string/identify"{
"success": true,
"data": {
"ok": true
}
}{
"success": false,
"error": {
"code": "AUTH_UNAUTHORIZED",
"message": "Invalid credentials",
"i18nKey": "auth.login.invalid_credentials",
"i18nVars": {
"field": "email"
},
"details": [
{
"message": "email must be an email"
}
],
"correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}Source
| Source | Path | Lines |
|---|---|---|
| Controller | apps/api-core/src/modules/analytics/analytics.controller.ts | 179–188 (identifySession) |
| DTO (response) | apps/api-core/src/modules/analytics/dto/analytics-client-response.dto.ts | 50–53 (IdentifySessionResultDto) |
| Service | apps/api-core/src/modules/analytics/traffic-tracking.service.ts | 215–220 (identifyUser — single UPDATE, silent fail) |
| Prisma model | packages/prisma-analytics/prisma/schema.prisma | AnalyticsSession.userId line 49 (application-level FK to main DB User) |
| Throttle behavior | apps/api-core/src/common/guards/throttle.guard.ts | 43–48 (no decorator → return true) |
Record Page Leave
Public exit-time ping for the LAST pageview of a session — the one that won't get its duration back-filled by a subsequent pageview. Captures duration (capped 1h) and scroll depth (clamped 0-100). Use sendBeacon.
Register New Account
Create a new BIO.RE account — email + password + terms acceptance, with optional username, OAuth attribution, and locale.