Skip to content

Commit 881ab55

Browse files
authored
feat: add user properties to analytics events like exposure (#11)
1 parent 737b4c8 commit 881ab55

File tree

3 files changed

+40
-3
lines changed

3 files changed

+40
-3
lines changed

packages/browser/src/integration/amplitude.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ type AmplitudeInstance = {
99
options?: AmplitudeOptions;
1010
_ua?: AmplitudeUAParser;
1111
logEvent(eventName: string, properties: Record<string, string>): void;
12+
setUserProperties(userProperties: Record<string, unknown>): void;
1213
};
1314

1415
type AmplitudeOptions = {
@@ -77,6 +78,9 @@ export class AmplitudeAnalyticsProvider implements ExperimentAnalyticsProvider {
7778
}
7879

7980
track(event: ExperimentAnalyticsEvent): void {
81+
if (event.userProperties) {
82+
this.amplitudeInstance.setUserProperties(event.userProperties);
83+
}
8084
this.amplitudeInstance.logEvent(event.name, event.properties);
8185
}
8286
}

packages/browser/src/types/analytics.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,18 @@ export interface ExperimentAnalyticsEvent {
1616
name: string;
1717

1818
/**
19-
* Properties for the analytics event. Should be passed as the event
19+
* Event properties for the analytics event. Should be passed as the event
2020
* properties to the analytics implementation provided by the
2121
* {@link ExperimentAnalyticsProvider}.
2222
*/
2323
properties: Record<string, string>;
24+
25+
/**
26+
* Custom user properties from the {@link ExperimentUser} stored by the
27+
* {@link ExperimentClient}. Also includes merged properties provided by the
28+
* {@link ExperimentUserProvider}.
29+
*/
30+
userProperties?: Record<string, unknown>;
2431
}
2532

2633
/**
@@ -30,6 +37,7 @@ export interface ExperimentAnalyticsEvent {
3037
export class ExposureEvent implements ExperimentAnalyticsEvent {
3138
name = '[Experiment] Exposure';
3239
properties: Record<string, string>;
40+
userProperties?: Record<string, unknown>;
3341

3442
/**
3543
* The user exposed to the flag/experiment variant.
@@ -53,5 +61,8 @@ export class ExposureEvent implements ExperimentAnalyticsEvent {
5361
key: key,
5462
variant: variant.value,
5563
};
64+
this.userProperties = {
65+
[`[Experiment] ${key}`]: variant.value,
66+
};
5667
}
5768
}

packages/browser/test/client.test.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,8 @@ test('ExperimentClient.fetch, with config user provider, success', async () => {
220220
*/
221221
class TestAnalyticsProvider implements ExperimentAnalyticsProvider {
222222
public didTrack = false;
223-
public block: (ExposureEvent) => void;
224-
public constructor(block: (ExposureEvent) => void) {
223+
public block: (event: ExperimentAnalyticsEvent) => void;
224+
public constructor(block: (event: ExperimentAnalyticsEvent) => void) {
225225
this.block = block;
226226
}
227227
track(event: ExperimentAnalyticsEvent): void {
@@ -273,3 +273,25 @@ test('ExperimentClient.variant, with analytics provider, exposure not tracked on
273273
client.variant(initialKey);
274274
client.variant(unknownKey);
275275
});
276+
277+
/**
278+
* Configure a client with an analytics provider which checks that
279+
* user_properties from the ExperimentUser object are passed through the event
280+
* to the analytics provider.
281+
*/
282+
test('ExperimentClient.variant, with analytics provider, user properties tracked', async () => {
283+
const analyticsProvider = new TestAnalyticsProvider(
284+
(event: ExperimentAnalyticsEvent) => {
285+
expect(event.userProperties).toEqual({
286+
[`[Experiment] ${serverKey}`]: serverVariant.value,
287+
});
288+
},
289+
);
290+
const client = new ExperimentClient(API_KEY, {
291+
debug: true,
292+
analyticsProvider: analyticsProvider,
293+
});
294+
await client.fetch(testUser);
295+
client.variant(serverKey);
296+
expect(analyticsProvider.didTrack).toEqual(true);
297+
});

0 commit comments

Comments
 (0)