mirror of
https://github.com/hatchet-dev/hatchet.git
synced 2026-02-19 22:59:08 -06:00
Feat: Initial cross-domain identify setup (#2533)
* feat: initial setup * fix: factor out * chore: lint * fix: xss vuln * feat: set up properly * fix: lint * fix: key * fix: keys, cleanup
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
import { User } from '@/lib/api';
|
||||
import { useTenant } from '@/lib/atoms';
|
||||
import useApiMeta from '@/pages/auth/hooks/use-api-meta';
|
||||
import { useAnalytics } from '@/hooks/use-analytics';
|
||||
import {
|
||||
POSTHOG_DISTINCT_ID_LOCAL_STORAGE_KEY,
|
||||
POSTHOG_SESSION_ID_LOCAL_STORAGE_KEY,
|
||||
useAnalytics,
|
||||
} from '@/hooks/use-analytics';
|
||||
import React, { PropsWithChildren, useEffect, useMemo } from 'react';
|
||||
|
||||
interface AnalyticsProviderProps {
|
||||
@@ -19,6 +23,13 @@ const AnalyticsProvider: React.FC<
|
||||
const { identify } = useAnalytics();
|
||||
|
||||
const config = useMemo(() => {
|
||||
if (import.meta.env.DEV) {
|
||||
return {
|
||||
apiKey: import.meta.env.VITE_PUBLIC_POSTHOG_KEY,
|
||||
apiHost: import.meta.env.VITE_PUBLIC_POSTHOG_HOST,
|
||||
};
|
||||
}
|
||||
|
||||
return meta.data?.posthog;
|
||||
}, [meta]);
|
||||
|
||||
@@ -38,12 +49,32 @@ const AnalyticsProvider: React.FC<
|
||||
return;
|
||||
}
|
||||
|
||||
let bootstrapConfig = '';
|
||||
|
||||
if (localStorage) {
|
||||
const distinctId = localStorage.getItem(
|
||||
POSTHOG_DISTINCT_ID_LOCAL_STORAGE_KEY,
|
||||
);
|
||||
const sessionId = localStorage.getItem(
|
||||
POSTHOG_SESSION_ID_LOCAL_STORAGE_KEY,
|
||||
);
|
||||
|
||||
if (distinctId && sessionId) {
|
||||
bootstrapConfig = `bootstrap: ${JSON.stringify({
|
||||
sessionID: sessionId,
|
||||
distinctID: distinctId,
|
||||
})},`;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Initializing Analytics, opt out in settings.');
|
||||
setLoaded(true);
|
||||
|
||||
const posthogScript = `
|
||||
!function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.async=!0,p.src=s.api_host.replace(".i.posthog.com","-assets.i.posthog.com")+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys onSessionId".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
|
||||
posthog.init('${config.apiKey}',{
|
||||
api_host:'${config.apiHost}',
|
||||
${bootstrapConfig}
|
||||
session_recording: {
|
||||
maskAllInputs: true,
|
||||
maskTextSelector: "*"
|
||||
|
||||
@@ -15,6 +15,9 @@ interface UseAnalyticsReturn {
|
||||
isAvailable: boolean;
|
||||
}
|
||||
|
||||
export const POSTHOG_DISTINCT_ID_LOCAL_STORAGE_KEY = 'ph__distinct_id';
|
||||
export const POSTHOG_SESSION_ID_LOCAL_STORAGE_KEY = 'ph__session_id';
|
||||
|
||||
/**
|
||||
* Hook for PostHog analytics integration
|
||||
* Provides a clean interface for tracking events and identifying users
|
||||
@@ -61,6 +64,11 @@ export function useAnalytics(): UseAnalyticsReturn {
|
||||
} catch (error) {
|
||||
console.warn('Analytics identify failed:', error);
|
||||
}
|
||||
|
||||
// important: clear out the distinct_id and session_id from local storage
|
||||
// after identifying the user so we don't re-bootstrap over and over
|
||||
localStorage.removeItem(POSTHOG_DISTINCT_ID_LOCAL_STORAGE_KEY);
|
||||
localStorage.removeItem(POSTHOG_SESSION_ID_LOCAL_STORAGE_KEY);
|
||||
},
|
||||
[isAvailable],
|
||||
);
|
||||
|
||||
@@ -2,18 +2,41 @@ import { Link, useNavigate } from 'react-router-dom';
|
||||
import { UserRegisterForm } from './components/user-register-form';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import api, { UserRegisterRequest } from '@/lib/api';
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useApiError } from '@/lib/hooks';
|
||||
import useApiMeta from '../hooks/use-api-meta';
|
||||
import { Loading } from '@/components/ui/loading';
|
||||
import { GithubLogin, GoogleLogin, OrContinueWith } from '../login';
|
||||
import useErrorParam from '../hooks/use-error-param';
|
||||
import React from 'react';
|
||||
import {
|
||||
POSTHOG_DISTINCT_ID_LOCAL_STORAGE_KEY,
|
||||
POSTHOG_SESSION_ID_LOCAL_STORAGE_KEY,
|
||||
} from '@/hooks/use-analytics';
|
||||
|
||||
export default function Register() {
|
||||
useErrorParam();
|
||||
const meta = useApiMeta();
|
||||
|
||||
// allows for cross-domain tracking with PostHog
|
||||
// see: https://posthog.com/tutorials/cross-domain-tracking
|
||||
// for setup instructions and more details
|
||||
// important: we need to set these in local storage from here,
|
||||
// because once we redirect after the user signs up, we lose the hash params
|
||||
const hashParams = new URLSearchParams(window.location.hash.substring(1));
|
||||
const distinctId = hashParams.get('distinct_id');
|
||||
const sessionId = hashParams.get('session_id');
|
||||
|
||||
useEffect(() => {
|
||||
if (distinctId) {
|
||||
localStorage.setItem(POSTHOG_DISTINCT_ID_LOCAL_STORAGE_KEY, distinctId);
|
||||
}
|
||||
|
||||
if (sessionId) {
|
||||
localStorage.setItem(POSTHOG_SESSION_ID_LOCAL_STORAGE_KEY, sessionId);
|
||||
}
|
||||
}, [distinctId, sessionId]);
|
||||
|
||||
if (meta.isLoading) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user