From 6684dc70cb3cee303c6f7f686214b7ddb59b5a35 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 11 Feb 2026 11:52:41 -0600 Subject: [PATCH] Patch GrowthBook and set feature callback --- patches/@growthbook+growthbook+1.6.2.patch | 55 ++++++++++++++++++++++ src/analytics/index.tsx | 29 +++++++----- src/analytics/metrics/types.ts | 8 ++++ 3 files changed, 80 insertions(+), 12 deletions(-) create mode 100644 patches/@growthbook+growthbook+1.6.2.patch diff --git a/patches/@growthbook+growthbook+1.6.2.patch b/patches/@growthbook+growthbook+1.6.2.patch new file mode 100644 index 0000000000..cf69f2df84 --- /dev/null +++ b/patches/@growthbook+growthbook+1.6.2.patch @@ -0,0 +1,55 @@ +diff --git a/node_modules/@growthbook/growthbook/dist/GrowthBook.d.ts b/node_modules/@growthbook/growthbook/dist/GrowthBook.d.ts +index ec532b0..d96a5f1 100644 +--- a/node_modules/@growthbook/growthbook/dist/GrowthBook.d.ts ++++ b/node_modules/@growthbook/growthbook/dist/GrowthBook.d.ts +@@ -1,4 +1,4 @@ +-import type { ApiHost, Attributes, AutoExperiment, AutoExperimentVariation, ClientKey, Options, Experiment, FeatureApiResponse, FeatureDefinition, FeatureResult, LoadFeaturesOptions, RefreshFeaturesOptions, RenderFunction, Result, SubscriptionFunction, TrackingCallback, TrackingData, WidenPrimitives, InitOptions, InitResponse, InitSyncOptions, PrefetchOptions, StickyAssignmentsDocument, EventLogger, LogUnion, DestroyOptions } from "./types/growthbook"; ++import type { ApiHost, Attributes, AutoExperiment, AutoExperimentVariation, ClientKey, Options, Experiment, FeatureApiResponse, FeatureDefinition, FeatureResult, FeatureUsageCallback, LoadFeaturesOptions, RefreshFeaturesOptions, RenderFunction, Result, SubscriptionFunction, TrackingCallback, TrackingData, WidenPrimitives, InitOptions, InitResponse, InitSyncOptions, PrefetchOptions, StickyAssignmentsDocument, EventLogger, LogUnion, DestroyOptions } from "./types/growthbook"; + import { StickyBucketServiceSync } from "./sticky-bucket-service"; + export declare class GrowthBook = Record> { + private context; +@@ -106,6 +106,7 @@ export declare class GrowthBook = Record + setDeferredTrackingCalls(calls: TrackingData[]): void; + fireDeferredTrackingCalls(): Promise; + setTrackingCallback(callback: TrackingCallback): void; ++ setFeatureUsageCallback(callback: FeatureUsageCallback): void; + setEventLogger(logger: EventLogger): void; + logEvent(eventName: string, properties?: Record): Promise; + private _saveDeferredTrack; +diff --git a/node_modules/@growthbook/growthbook/dist/esm/GrowthBook.mjs b/node_modules/@growthbook/growthbook/dist/esm/GrowthBook.mjs +index e0847f0..4bcc20f 100644 +--- a/node_modules/@growthbook/growthbook/dist/esm/GrowthBook.mjs ++++ b/node_modules/@growthbook/growthbook/dist/esm/GrowthBook.mjs +@@ -682,6 +682,9 @@ export class GrowthBook { + this._options.trackingCallback = callback; + this.fireDeferredTrackingCalls(); + } ++ setFeatureUsageCallback(callback) { ++ this._options.onFeatureUsage = callback; ++ } + setEventLogger(logger) { + this._options.eventLogger = logger; + } +diff --git a/node_modules/@growthbook/growthbook/src/GrowthBook.ts b/node_modules/@growthbook/growthbook/src/GrowthBook.ts +index 907fc97..e59201c 100644 +--- a/node_modules/@growthbook/growthbook/src/GrowthBook.ts ++++ b/node_modules/@growthbook/growthbook/src/GrowthBook.ts +@@ -16,6 +16,7 @@ import type { + Result, + SubscriptionFunction, + TrackingCallback, ++ FeatureUsageCallback, + TrackingData, + WidenPrimitives, + EvalContext, +@@ -952,6 +953,10 @@ export class GrowthBook< + this.fireDeferredTrackingCalls(); + } + ++ public setFeatureUsageCallback(callback: FeatureUsageCallback) { ++ this._options.onFeatureUsage = callback; ++ } ++ + public setEventLogger(logger: EventLogger) { + this._options.eventLogger = logger; + } diff --git a/src/analytics/index.tsx b/src/analytics/index.tsx index 47e024ae88..cde37ab711 100644 --- a/src/analytics/index.tsx +++ b/src/analytics/index.tsx @@ -1,4 +1,4 @@ -import {createContext, useContext, useEffect, useMemo} from 'react' +import {createContext, useContext, useMemo} from 'react' import {Platform} from 'react-native' import {Logger} from '#/logger' @@ -181,20 +181,25 @@ export function AnalyticsFeaturesContext({ const parentContext = useContext(Context) /** - * Side-effect: we need to synchronously set this during the - * same render cycle. It does not trigger a re-render, it just - * sets properties on the singleton GrowthBook instance. + * Side-effects: we need to synchronously set these during the same render + * cycle. These calls do not trigger re-renders, they just set properties on + * the singleton GrowthBook instance. */ setAttributes(parentContext.metadata) - - useEffect(() => { - feats.setTrackingCallback((experiment, result) => { - parentContext.metric('experiment:viewed', { - experimentId: experiment.key, - variationId: result.key, - }) + feats.setTrackingCallback((experiment, result) => { + parentContext.metric('experiment:viewed', { + experimentId: experiment.key, + variationId: result.key, }) - }, [parentContext.metric]) + }) + feats.setFeatureUsageCallback((feature, result) => { + parentContext.metric('feature:viewed', { + featureId: feature, + featureResultValue: result.value, + experimentId: result.experiment?.key, + variationId: result.experimentResult?.key, + }) + }) const childContext = useMemo(() => { return { diff --git a/src/analytics/metrics/types.ts b/src/analytics/metrics/types.ts index 65f2a5d39f..636c0287a2 100644 --- a/src/analytics/metrics/types.ts +++ b/src/analytics/metrics/types.ts @@ -15,6 +15,14 @@ export type Events = { experimentId: string variationId: string } + 'feature:viewed': { + featureId: string + featureResultValue: unknown + /** Only available if feature has experiment rules applied */ + experimentId?: string + /** Only available if feature has experiment rules applied */ + variationId?: string + } 'account:loggedIn': { logContext: