@datalyr/web 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +122 -0
- package/dist/datalyr.cjs.js +1 -1
- package/dist/datalyr.esm.js +1 -1
- package/dist/datalyr.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -504,6 +504,128 @@ export default function RootLayout({ children }) {
|
|
|
504
504
|
}
|
|
505
505
|
```
|
|
506
506
|
|
|
507
|
+
## Authentication & Server-Side Tracking
|
|
508
|
+
|
|
509
|
+
### ⚠️ Critical: Server-Side Identification for Authentication
|
|
510
|
+
|
|
511
|
+
When implementing authentication flows (login, signup, OAuth), you **MUST** call identify on the server-side before redirecting. Client-side identification during auth flows is unreliable and will cause attribution data loss.
|
|
512
|
+
|
|
513
|
+
#### The Problem
|
|
514
|
+
|
|
515
|
+
```javascript
|
|
516
|
+
// ❌ WRONG - Client-side only (unreliable for auth flows)
|
|
517
|
+
function LoginPage() {
|
|
518
|
+
const handleLogin = async () => {
|
|
519
|
+
await login(email, password);
|
|
520
|
+
datalyr.identify(userId); // May not execute before redirect!
|
|
521
|
+
router.push('/dashboard'); // User redirects, identify never completes
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
#### The Solution
|
|
527
|
+
|
|
528
|
+
```javascript
|
|
529
|
+
// ✅ CORRECT - Server-side identification
|
|
530
|
+
// Next.js Server Action example
|
|
531
|
+
async function loginAction(email: string, password: string) {
|
|
532
|
+
const user = await authenticate(email, password);
|
|
533
|
+
|
|
534
|
+
// Critical: Identify BEFORE redirect
|
|
535
|
+
await fetch('https://datalyr.com/api/v1/events', {
|
|
536
|
+
method: 'POST',
|
|
537
|
+
headers: {
|
|
538
|
+
'Authorization': `Bearer ${process.env.DATALYR_API_KEY}`,
|
|
539
|
+
'Content-Type': 'application/json'
|
|
540
|
+
},
|
|
541
|
+
body: JSON.stringify({
|
|
542
|
+
event_name: '$identify',
|
|
543
|
+
user_id: user.id,
|
|
544
|
+
workspace_id: process.env.DATALYR_WORKSPACE_ID,
|
|
545
|
+
properties: {
|
|
546
|
+
email: user.email,
|
|
547
|
+
source: 'login'
|
|
548
|
+
}
|
|
549
|
+
})
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
redirect('/dashboard');
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// For signup
|
|
556
|
+
async function signupAction(email: string, password: string) {
|
|
557
|
+
const user = await createUser(email, password);
|
|
558
|
+
|
|
559
|
+
// Identify new user server-side
|
|
560
|
+
await identifyUserServer(user.id, {
|
|
561
|
+
email: user.email,
|
|
562
|
+
created_at: new Date().toISOString(),
|
|
563
|
+
source: 'signup'
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
redirect('/onboarding');
|
|
567
|
+
}
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
### Why Server-Side Identification Matters
|
|
571
|
+
|
|
572
|
+
1. **Attribution Tracking**: Links anonymous visitors who clicked ads (with fbclid, gclid, etc.) to authenticated users
|
|
573
|
+
2. **Cross-Device Tracking**: Connects users across different devices and browsers
|
|
574
|
+
3. **Reliability**: Guarantees execution before redirects, unlike client-side
|
|
575
|
+
4. **OAuth Compatibility**: Works with complex OAuth redirect chains
|
|
576
|
+
|
|
577
|
+
### Implementation Checklist
|
|
578
|
+
|
|
579
|
+
Ensure you call identify server-side in ALL these scenarios:
|
|
580
|
+
|
|
581
|
+
- [ ] **Email Signup**: Call identify when creating new accounts
|
|
582
|
+
- [ ] **Email Login**: Call identify for returning users
|
|
583
|
+
- [ ] **OAuth Signup**: Call identify in OAuth callback for new users
|
|
584
|
+
- [ ] **OAuth Login**: Call identify in OAuth callback for existing users
|
|
585
|
+
- [ ] **Magic Links**: Call identify when validating magic link tokens
|
|
586
|
+
- [ ] **Password Reset**: Call identify after successful password reset
|
|
587
|
+
- [ ] **Session Restore**: Call identify when validating existing sessions on app load
|
|
588
|
+
|
|
589
|
+
### Example: Complete OAuth Implementation
|
|
590
|
+
|
|
591
|
+
```javascript
|
|
592
|
+
// app/auth/callback/route.ts
|
|
593
|
+
export async function GET(request: Request) {
|
|
594
|
+
const { user } = await validateOAuthCallback(request);
|
|
595
|
+
|
|
596
|
+
const existingUser = await getUserByEmail(user.email);
|
|
597
|
+
|
|
598
|
+
if (existingUser) {
|
|
599
|
+
// Existing user logging in
|
|
600
|
+
await identifyUserServer(existingUser.id, {
|
|
601
|
+
email: existingUser.email,
|
|
602
|
+
source: 'oauth_login',
|
|
603
|
+
provider: 'google'
|
|
604
|
+
});
|
|
605
|
+
await trackEventServer('login', { method: 'oauth' });
|
|
606
|
+
} else {
|
|
607
|
+
// New user signing up
|
|
608
|
+
const newUser = await createUser(user);
|
|
609
|
+
await identifyUserServer(newUser.id, {
|
|
610
|
+
email: newUser.email,
|
|
611
|
+
source: 'oauth_signup',
|
|
612
|
+
provider: 'google'
|
|
613
|
+
});
|
|
614
|
+
await trackEventServer('signup', { method: 'oauth' });
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
return redirect('/dashboard');
|
|
618
|
+
}
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
### What Happens Without Server-Side Identify
|
|
622
|
+
|
|
623
|
+
Without proper server-side identification:
|
|
624
|
+
- **Lost Attribution**: Ad clicks (fbclid, gclid) won't be associated with conversions
|
|
625
|
+
- **Broken Cross-Device**: Users on multiple devices won't be linked
|
|
626
|
+
- **Incomplete Funnels**: User journeys will appear fragmented
|
|
627
|
+
- **Inaccurate Analytics**: Conversion rates and ROI calculations will be wrong
|
|
628
|
+
|
|
507
629
|
## Best Practices
|
|
508
630
|
|
|
509
631
|
### 1. Initialize Early
|
package/dist/datalyr.cjs.js
CHANGED
package/dist/datalyr.esm.js
CHANGED
package/dist/datalyr.js
CHANGED