Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions examples/html-app/amplitude-integration/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,30 @@
-->
<script type="text/javascript">
!function(){"use strict";!function(e,t){var r=e.amplitude||{_q:[],_iq:[]};if(r.invoked)e.console&&console.error&&console.error("Amplitude snippet has been loaded.");else{r.invoked=!0;var n=t.createElement("script");n.type="text/javascript",n.crossOrigin="anonymous",n.async=!0,
n.src="https://unpkg.com/@amplitude/analytics-browser@1.5.4/lib/scripts/amplitude-min.js",n.onload=function(){e.amplitude.runQueuedFunctions||console.log("[Amplitude] Error: could not load SDK")};var s=t.getElementsByTagName("script")[0];function v(e,t){e.prototype[t]=function(){return this._q.push({name:t,args:Array.prototype.slice.call(arguments,0)}),this}}s.parentNode.insertBefore(n,s);for(var o=function(){return this._q=[],this},i=["add","append","clearAll","prepend","set","setOnce","unset","preInsert","postInsert","remove","getUserProperties"],a=0;a<i.length;a++)v(o,i[a]);r.Identify=o;for(var u=function(){return this._q=[],this},c=["getEventProperties","setProductId","setQuantity","setPrice","setRevenue","setRevenueType","setEventProperties"],l=0;l<c.length;l++)v(u,c[l]);r.Revenue=u;var p=["getDeviceId","setDeviceId","getSessionId","setSessionId","getUserId","setUserId","setOptOut","setTransport","reset"],d=["init","add","remove","track","logEvent","identify","groupIdentify","setGroup","revenue","flush"];function f(e){function t(t,r){e[t]=function(){var n={promise:new Promise((r=>{e._q.push({name:t,args:Array.prototype.slice.call(arguments,0),resolve:r})}))};if(r)return n}}for(var r=0;r<p.length;r++)t(p[r],!1);for(var n=0;n<d.length;n++)t(d[n],!0)}f(r),r.createInstance=function(){var e=r._iq.push({_q:[]})-1;return f(r._iq[e]),r._iq[e]},e.amplitude=r}}(window,document)}();
n.src="https://unpkg.com/@amplitude/analytics-browser@1.7.1/lib/scripts/amplitude-min.js",n.onload=function(){e.amplitude.runQueuedFunctions||console.log("[Amplitude] Error: could not load SDK")};var s=t.getElementsByTagName("script")[0];function v(e,t){e.prototype[t]=function(){return this._q.push({name:t,args:Array.prototype.slice.call(arguments,0)}),this}}s.parentNode.insertBefore(n,s);for(var o=function(){return this._q=[],this},i=["add","append","clearAll","prepend","set","setOnce","unset","preInsert","postInsert","remove","getUserProperties"],a=0;a<i.length;a++)v(o,i[a]);r.Identify=o;for(var u=function(){return this._q=[],this},c=["getEventProperties","setProductId","setQuantity","setPrice","setRevenue","setRevenueType","setEventProperties"],l=0;l<c.length;l++)v(u,c[l]);r.Revenue=u;var p=["getDeviceId","setDeviceId","getSessionId","setSessionId","getUserId","setUserId","setOptOut","setTransport","reset"],d=["init","add","remove","track","logEvent","identify","groupIdentify","setGroup","revenue","flush"];function f(e){function t(t,r){e[t]=function(){var n={promise:new Promise((r=>{e._q.push({name:t,args:Array.prototype.slice.call(arguments,0),resolve:r})}))};if(r)return n}}for(var r=0;r<p.length;r++)t(p[r],!1);for(var n=0;n<d.length;n++)t(d[n],!0)}f(r),r.createInstance=function(){var e=r._iq.push({_q:[]})-1;return f(r._iq[e]),r._iq[e]},e.amplitude=r}}(window,document)}();

// TODO Replace API_KEY with your analytics api key.
amplitude.init('a6dd847b9d2f03c816d4f3f8458cdc1d');
amplitude.init('API_KEY');

/**
* User ID, device ID, and identified user properties are used by the
* Experiment SDK in the fetch request.
*/
amplitude.setUserId('user@company.com');
amplitude.setUserId('test-resolve');
amplitude.identify(new amplitude.Identify().set('premium', true));
</script>

<!--
Install the Amplitude Experiment SDK via script tag.
-->
<script src="https://unpkg.com/@amplitude/experiment-js-client@1.5.6/dist/experiment.umd.js"></script>
<script src="https://unpkg.com/@amplitude/experiment-js-client@1.7.0/dist/experiment.umd.js"></script>
<script>
/**
* Initialize the experiment client with the Amplitude Analytics integration
* and set a variable on the window.
*/
// TODO Replace DEPLOYMENT_KEY with your own deployment
window.experiment = Experiment.Experiment.initializeWithAmplitudeAnalytics('client-QQEu7NCkqMmhdGdWl3Y4post5mZaVkCL', { debug: true });
window.experiment = Experiment.Experiment.initializeWithAmplitudeAnalytics('DEPLOYMENT_KEY', { debug: true });
</script>
</script>
<body>
Expand Down
11 changes: 9 additions & 2 deletions examples/html-app/basic/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Experiment Example - Basic</title>
</head>
<script src="https://unpkg.com/@amplitude/experiment-js-client@1.5.6/dist/experiment.umd.js"></script>
<script src="https://unpkg.com/@amplitude/experiment-js-client@1.7.0/dist/experiment.umd.js"></script>
<script>
/**
* Initialize the experiment client and set a variable on the window.
Expand All @@ -27,7 +27,14 @@ <h2>Amplitude Experiment Browser Example - Basic</h2>

<!-- TODO Replace FLAG_KEY with your flag key -->
<button onclick="
const variants = window.experiment.variant('FLAG_KEY');
const variant = window.experiment.variant('space-permissions');
if (variant?.value === 'admin') {
// redirect to admin.amplitude.com
} else if (variant?.value === 'on') {
// redirect to ...
} else {
// off
}
document.getElementById('output').innerText = JSON.stringify(variants);
">Variant</button>

Expand Down
4 changes: 2 additions & 2 deletions examples/react-app/amplitude-integration/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Experiment } from '@amplitude/experiment-js-client';
/**
* Initialize the Amplitude Analytics SDK.
*/
amplitude.init('a6dd847b9d2f03c816d4f3f8458cdc1d', 'user@company.com');
amplitude.init('API_KEY', 'user@company.com');
amplitude.identify(new amplitude.Identify().set('premium', true))

/**
Expand All @@ -19,7 +19,7 @@ amplitude.identify(new amplitude.Identify().set('premium', true))
* automatically be used by the Experiment SDK on fetch().
*/
export const experiment = Experiment.initializeWithAmplitudeAnalytics(
'client-QQEu7NCkqMmhdGdWl3Y4post5mZaVkCL',
'DEPLOYMENT_KEY',
{ debug: true }
);

Expand Down
2 changes: 1 addition & 1 deletion examples/react-app/basic/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Experiment } from '@amplitude/experiment-js-client';
* Initialize the Amplitude Experiment SDK and export the initialized client.
*/
export const experiment = Experiment.initialize(
'client-QQEu7NCkqMmhdGdWl3Y4post5mZaVkCL',
'DEPLOYMENT_KEY',
{ debug: true }
);

Expand Down
6 changes: 5 additions & 1 deletion packages/experiment-browser/src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const initialize = (
config = {
userProvider: new DefaultUserProvider(
connector.applicationContextProvider,
config?.userProvider,
),
...config,
};
Expand Down Expand Up @@ -60,7 +61,10 @@ const initializeWithAmplitudeAnalytics = (
const connector = AnalyticsConnector.getInstance(instanceName);
if (!instances[instanceKey]) {
config = {
userProvider: new ConnectorUserProvider(connector.identityStore),
userProvider: new DefaultUserProvider(
connector.applicationContextProvider,
new ConnectorUserProvider(connector.identityStore),
),
exposureTrackingProvider: new ConnectorExposureTrackingProvider(
connector.eventBridge,
),
Expand Down
9 changes: 8 additions & 1 deletion packages/experiment-browser/src/integration/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,25 @@ import { ExperimentUser } from '../types/user';

export class DefaultUserProvider implements ExperimentUserProvider {
private readonly contextProvider: ApplicationContextProvider;
constructor(applicationContextProvider: ApplicationContextProvider) {
private readonly userProvider: ExperimentUserProvider | undefined;
constructor(
applicationContextProvider: ApplicationContextProvider,
userProvider?: ExperimentUserProvider,
) {
this.contextProvider = applicationContextProvider;
this.userProvider = userProvider;
}

getUser(): ExperimentUser {
const user = this.userProvider?.getUser() || {};
const context = this.contextProvider.getApplicationContext();
return {
version: context.versionName,
language: context.language,
platform: context.platform,
os: context.os,
device_model: context.deviceModel,
...user,
};
}
}
183 changes: 183 additions & 0 deletions packages/experiment-browser/test/defaultUserProvider.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import { ApplicationContext } from '@amplitude/analytics-connector';
import { DefaultUserProvider } from 'src/integration/default';
import { ExperimentUser } from 'src/types/user';

const applicationContext: ApplicationContext = {
versionName: 'versionName',
language: 'language',
platform: 'platform',
os: 'os',
deviceModel: 'deviceModel',
};

describe('DefaultUserProvider', () => {
test('basic wrapped provider', async () => {
const user: ExperimentUser = {
user_id: 'user_id',
device_id: 'device_id',
user_properties: {
k1: 'v1',
},
};
const applicationContext: ApplicationContext = {
language: 'language',
platform: 'platform',
os: 'os',
deviceModel: 'deviceModel',
versionName: 'versionName',
};
const defaultUserProvider = new DefaultUserProvider(
{
versionName: 'versionName',
getApplicationContext(): ApplicationContext {
return applicationContext;
},
},
{
getUser(): ExperimentUser {
return user;
},
},
);
const actualUser = defaultUserProvider.getUser();
const expectedUser = {
user_id: 'user_id',
device_id: 'device_id',
user_properties: {
k1: 'v1',
},
language: 'language',
platform: 'platform',
os: 'os',
device_model: 'deviceModel',
version: 'versionName',
};
expect(actualUser).toEqual(expectedUser);
});

test('wrapped provider not set', async () => {
const applicationContext: ApplicationContext = {
language: 'language',
platform: 'platform',
os: 'os',
deviceModel: 'deviceModel',
versionName: 'versionName',
};
const defaultUserProvider = new DefaultUserProvider({
versionName: 'versionName',
getApplicationContext(): ApplicationContext {
return applicationContext;
},
});
const actualUser = defaultUserProvider.getUser();
const expectedUser = {
language: 'language',
platform: 'platform',
os: 'os',
device_model: 'deviceModel',
version: 'versionName',
};
expect(actualUser).toEqual(expectedUser);
});

test('wrapped provider undefined', async () => {
const applicationContext: ApplicationContext = {
language: 'language',
platform: 'platform',
os: 'os',
deviceModel: 'deviceModel',
versionName: 'versionName',
};
const defaultUserProvider = new DefaultUserProvider(
{
versionName: 'versionName',
getApplicationContext(): ApplicationContext {
return applicationContext;
},
},
undefined,
);
const actualUser = defaultUserProvider.getUser();
const expectedUser = {
language: 'language',
platform: 'platform',
os: 'os',
device_model: 'deviceModel',
version: 'versionName',
};
expect(actualUser).toEqual(expectedUser);
});

test('wrapped provider null', async () => {
const applicationContext: ApplicationContext = {
language: 'language',
platform: 'platform',
os: 'os',
deviceModel: 'deviceModel',
versionName: 'versionName',
};
const defaultUserProvider = new DefaultUserProvider(
{
versionName: 'versionName',
getApplicationContext(): ApplicationContext {
return applicationContext;
},
},
null,
);
const actualUser = defaultUserProvider.getUser();
const expectedUser = {
language: 'language',
platform: 'platform',
os: 'os',
device_model: 'deviceModel',
version: 'versionName',
};
expect(actualUser).toEqual(expectedUser);
});

test('default value overwritten by wrapped provider', async () => {
const user: ExperimentUser = {
user_id: 'user_id',
device_id: 'device_id',
user_properties: {
k1: 'v1',
},
device_model: 'deviceModel2',
};
const applicationContext: ApplicationContext = {
language: 'language',
platform: 'platform',
os: 'os',
deviceModel: 'deviceModel',
versionName: 'versionName',
};
const defaultUserProvider = new DefaultUserProvider(
{
versionName: 'versionName',
getApplicationContext(): ApplicationContext {
return applicationContext;
},
},
{
getUser(): ExperimentUser {
return user;
},
},
);
const actualUser = defaultUserProvider.getUser();
const expectedUser = {
user_id: 'user_id',
device_id: 'device_id',
user_properties: {
k1: 'v1',
},
language: 'language',
platform: 'platform',
os: 'os',
device_model: 'deviceModel2',
version: 'versionName',
};
expect(actualUser).toEqual(expectedUser);
});
});