narrow-spoon-80536
02/19/2026, 9:21 AM@growthbook/growthbook-react ^1.6.1. We call setAttributes() with the logged-in user only after await gb.init() completes. When we push experiment_viewed to the GA4 dataLayer and read getAttributes().id for user_id, In GA4, we are seeing this event captured without user_id.
Question: Is there a possibility of getAttributes().id been undefined when trackingCallback is triggered? What's the recommended way to have user attributes (especially id) available when we need to send them with experiment events to GA4?
Full code that we use now
tsx
import { useEffect, useRef, useState } from 'react';
import { GrowthBook, GrowthBookProvider } from '@growthbook/growthbook-react';
import { useAuthContext } from '@/auth/hooks';
// CONFIG from app config (apiHost, clientKey, env name redacted)
const GROWTH_BOOK_API_HOST = '<api-host>';
const GROWTH_BOOK_CLIENT_KEY = '<client-key>';
const ENABLE_DEV_MODE = false;
interface Props {
children: React.ReactNode;
}
export function ABTestingProvider({ children }: Props) {
const gb = useRef<GrowthBook | null>(null);
const [isGrowthBookInitialized, setIsGrowthBookInitialized] = useState(false);
const { user: authUser } = useAuthContext();
useEffect(() => {
async function initializeAndSetAttributes() {
if (!gb.current) {
gb.current = new GrowthBook({
attributes: { role: 'student' },
apiHost: GROWTH_BOOK_API_HOST,
clientKey: GROWTH_BOOK_CLIENT_KEY,
enableDevMode: ENABLE_DEV_MODE,
backgroundSync: false,
subscribeToChanges: false,
trackingCallback: (
experiment: { key: string },
result: { key: string; variationId: number }
) => {
const gbAttributes = gb.current?.getAttributes();
if (gbAttributes && Object.keys(gbAttributes).length) {
if ('dataLayer' in window) {
window.dataLayer.push({
event: 'experiment_viewed',
user_id: gbAttributes.id as string,
experiment_id: experiment.key,
variation_id: `${result.variationId}`,
});
}
}
},
});
await gb.current.init();
if (typeof window !== 'undefined') {
window.growthbook = gb.current;
}
}
if (authUser && gb.current) {
await gb.current.setAttributes({
id: authUser.id,
email: authUser.email,
language: 'en',
});
}
setIsGrowthBookInitialized(true);
}
void initializeAndSetAttributes();
}, [authUser]);
return (
<>
{isGrowthBookInitialized && gb.current && (
<GrowthBookProvider growthbook={gb.current}>
{children}
</GrowthBookProvider>
)}
</>
);
}
Previously we have user a older version of growthbook react sdk 0.21.0 and recently we have upgraded to 1.6.1. Will there be any change need to be done and also will this third part tracking need to be used in latest version instead of trackingCallback. https://docs.growthbook.io/lib/react#third-party-tracking
Thanks.fresh-football-47124
fresh-football-47124
fresh-football-47124
narrow-spoon-80536
02/19/2026, 9:36 AMnarrow-spoon-80536
02/19/2026, 9:37 AMnarrow-spoon-80536
02/19/2026, 9:38 AMnarrow-spoon-80536
02/20/2026, 1:47 PMnarrow-spoon-80536
02/25/2026, 10:14 AM