Add Rybbit analytics alongside Umami

- Load Rybbit script via app.html (recommended SvelteKit approach)
- Mirror all Umami custom events (First guess, Guessed correctly, Share, Copy to Clipboard, social link clicks) with rybbit.event()
- Identify logged-in users with name/email traits; anonymous users by stable UUID

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
George Powell
2026-02-21 17:13:41 -05:00
parent 6554ef8f41
commit 3036264d44
5 changed files with 32 additions and 7 deletions

View File

@@ -17,11 +17,18 @@ function getOrCreateAnonymousId(): string {
// Reactive store that keeps in-memory game state in sync with localStorage.
// Accepts getter functions (rather than plain values) so Svelte's reactivity
// system can track dependencies and re-run effects when they change.
type AuthUser = {
id: string;
firstName?: string | null;
lastName?: string | null;
email?: string | null;
};
export function createGamePersistence(
getDate: () => string,
getReference: () => string,
getCorrectBookId: () => string,
getUserId: () => string | undefined,
getUser: () => AuthUser | null | undefined,
) {
let guesses = $state<Guess[]>([]);
let anonymousId = $state("");
@@ -34,18 +41,27 @@ export function createGamePersistence(
$effect(() => {
if (!browser) return;
const userId = getUserId();
const user = getUser();
// CRITICAL: If user is logged in, ALWAYS use their user ID
if (userId) {
anonymousId = userId;
if (user) {
anonymousId = user.id;
} else {
anonymousId = getOrCreateAnonymousId();
}
// Tell Umami analytics which player this is so events are grouped correctly.
// Tell analytics which player this is so events are grouped correctly.
if ((window as any).umami) {
(window as any).umami.identify(anonymousId);
}
if (user) {
const nameParts = [user.firstName, user.lastName].filter(Boolean);
(window as any).rybbit?.identify(user.id, {
...(nameParts.length ? { name: nameParts.join(' ') } : {}),
...(user.email ? { email: user.email } : {}),
});
} else {
(window as any).rybbit?.identify(anonymousId);
}
const date = getDate();
const reference = getReference();