google-optimize-service provides a lightweight abstraction layer around Google Optimize. It enables easy access to and management of experiment information.
via npm:
npm i -S google-optimize-service
via yarn:
yarn add google-optimize-service
import optimize from 'google-optimize-service';
optimize.preventFlicker();
const experiment = optmize.get();
/**
* Assuming the query parameters set by Google Optimize:
* ?utm_expid=69&utm_referrer=&variant=doggy
*
* experiment := {
* experimentId: '69', // google optimize experiment id, i.e. utm_expid
* referrer: '', // google optimize referrer, i.e. utm_referrer
* variant: 'doggy' // custom set experiment variable
* }
*/
const optimize = require('google-optimize-service');
const experiment = optimize.get();
/**
* Assuming the query parameters set by Google Optimize:
* ?utm_expid=69&utm_referrer=&variant=doggy
*
* experiment := {
* experimentId: '69', // google optimize experiment id, i.e. utm_expid
* referrer: '', // google optimize referrer, i.e. utm_referrer
* variant: 'doggy' // custom set experiment variable
* }
*/
google-optimize-service
is a highly customizable abstraction layer for Google Optimize. As such it features:
Autodiscovery of the environment.
If run in a browser, google-optimize-service
will automatically find the query parameters and check for available storage APIs to persist experiment data. If you're working in a non-browser environment, however, you can tell google-optimize-service
where to find URL query parameters and how to persist experiment data.
Custom fields carrying your experiment variables.
By default google-optimize-service
is setup to extract a variant
from the URL. If your experiment, however, requires a more complex setup, e.g. with multiple or differently named experiment variables, you can tell google-optimize-service
which query parameters belong to your experiment.
Auto-persistance of experiment data.
To ensure your users will always see the same variant of your application, google-optimize-service
by default automatically persists experiment data. Of course you can prevent persistance or employ your own storage strategies as you see fit.
Flicker prevention: anti-flicker snippet.
No need to manually add the anti-flicker snippet to your page, google-optimize-service
's got you covered.
By employing persistance and discovery strategies, google-optimize-service
facilitates work in an agile environment where change is frequent and/or multiple Optimize experiments run in parallel. This can help reduce the amount of work necessary to refactor experiment implementations.
Whether you work on a ESM powered SPA or in a CommonJS powered Node.js project google-optimize-service
has your back. It works with any modern JavaScript source base.
google-optimize-service
is implemented in a resource preserving manner and introduces minimal additional production dependencies.
google-optimize-service
can be adjusted to your needs via a multitude of settings documented in the API section.
This is what it's default configuration looks like:
{
autopersist: true, // customize via autopersist().
fields: [ // customize via fields().
'variant'
],
key: 'optimize', // customize via key().
location: { // customize via location(). location is subject to autodiscovery.
search: ''
},
storage: null, // customize via storage(). storage is subject to autodiscovery.
storagePreference: storagePreferences.localStorage // customize via storagePreference().
}
All configuration is customizable:
Configure whether or not to automatically persist experiment data to storage
. If set to true
, optimize will persist experiments found in the query with every call to get()
.
If called without parameter, autopersist()
returns the current autopersist
setting.
shouldPersist
optional - a boolean indicating whether or not to persist experiment data to storage.
const optimize = require('google-optimize-service');
optimize.autopersist(true);
const experiment = optimize.get();
// experiment will be persisted to storage
Wraps all configuration options into a convenient abstraction.
options
- a map containing configuration options. Valid, available configuration options are:
const optimize = require('google-optimize-service');
optimize.configure({
autopersist: true,
fields: [
'variant',
'subvariant'
],
key: 'my-app',
storagePreference: optimize.storagePreferences.sessionStorage
});
const experiment = optimize.get();
Returns the utm_expid
of the current, i.e. as set in the URL query parameters, experiment.
const optimize = require('google-optimize-service');
const currentExperimentId = optimize.currentExperimentId();
Autodiscovers configuration for the current environment. When calling discover()
, google-optimize-service
performs checks to see if a window
object with location
(and search
) is available to retrieve experiment information from. Furthermore, session
- and localStorage
are checked and set as storage engines if available. Discover is automatically invoked upon first importing the google-optimize-service
. Use storagePreference
to indicate whether you prefer session
- or localStorage
for your application.
const optimize = require('google-optimize-service');
optimize.discover();
const experiment = optimize.get();
Set custom fields to retrieve from the URL query when parsing experiment data.
If called without parameter, fields()
returns the current fields
setting.
fields
optional - an Array of strings representing the name of query parameters that should be added to the experiment data.
const optimize = require('google-optimize-service');
optimize.fields([
'variant',
'subvariant'
]);
const experiment = optimize.get();
/**
* experiment now contains properties variant and subvariant, if they are set in the query string.
*/
switch (experiment.variant) {
case 'A':
switch (experiment.subvariant) {
case 1:
// add code for variant A.1
break;
}
}
Returns experiment data from the URL query. Disregards persisted experiment information.
const optimize = require('google-optimize-service');
const experiment = optimize.fromQuery();
get()
is your main entrypoint to experiment data. It consolidates stored experiment data with experiment data in the URL query, whereby stored data superseeds URL data. If not not provided experimentId
defaults to the currentExperimentId
. If there is experiment data in the URL query that is not persisted, yet, it is merged into the dataset. If autopersist
is set to true
, consolidated experiment data is persisted to storage
. If no experimentId
is provided and there is no currentExperimentId
(or the parameter is deliberately set to null
or undefined
), a map of all experiments is returned. The map is keyed by experimentId
.
experimentId
optional - the id of the experiment to retrieve. Defaults to the return value of currentExperimentId()
. If not available or set to null
or undefined
, a map of all available experiments is returned.
const optimize = require('google-optimize-service');
const experiment = optimize.get();
// experiment is the current experiment
const someOtherExperiment = optimize.get(someOtherExperimentId);
// someOtherExperiment contains information about experiment with id someOtherExperimentId
Sets the key used when persisting experiment information to storage
.
If called without parameter, returns the current key.
newKey
optional - if provided newKey
is set as the key to use when persisting experiment information.
const optimize = require('google-optimize-service');
optimize.key('my-optimize-experiments')
const experiment = optimize.get();
// experiment data is fetched from and persisted to the key 'my-optimize-experiments'.
Sets the location
object to use to retrieve search
/query
data from.
If called without parameter, returns the current location
.
By default, google-optimize-service
tries to discover if it is run in a browser and defaults to window.location
if available. If you are working on the server-side, however, you may wish provide a different location object to parse experiment data from.
newLocation
optional - must be an object with a property search
, e.g. { search: '?utm_expid=69&variant=naughty' }
, from which to parse experiment information.
Use with Koa
const optimize = require('google-optimize-service');
const Router = require('koa-router');
const router = Router();
router.get('/', async (ctx) => {
optimize.location({
search: ctx.request.search
});
const experiment = optimize.get();
// experiment data is parsed from ctx.request.search.
});
Use with Express
const optimize = require('google-optimize-service');
const express = require('express');
const app = express();
app.get('/', (req, res) => {
optimize.location({
search: req.originalUrl.slice(req.originalUrl.indexOf('?'))
});
const experiment = optimize.get();
// experiment data is parsed from the original URL's query string.
});
Persists experiment data to storage
at key
. If not provided as parameter, persist()
tries to persist experiments returned by get()
. If no storage is configured, this is a noop.
experiments
optional - The experiments to persist to storage. If not provided, persist()
tries to retrieve experiment data from get()
.
const optimize = require('google-optimize-service');
const experiments = optimize.get(null);
optimize.persist(experiments);
Installs the anti-flicker snippet.
timeout
optional - Timeout to wait for Google Analytics in milliseconds. Default: 2000
.
intervalMs
optional - Interval in which to check for Google Analytics in milliseconds. Default: 10
.
const optimize = require('google-optimize-service');
optimize.preventFlicker();
Sets and returns the storage implementation to use.
If called without parameter, it returns the currently set storage engine.
By default google-optimize-service
tries to discover available storage mechanisms and configures itself accoringly. E.g. if run in a browser, google-optimize-service
can discover that both localStorage
and sessionStorage
are available on the window
object. Depending on the set storagePreference
, it configures itself to use one of those when discover()
ing.
Supplying your own storage engine to use for persist()
ing experiments, can come handy when working in non-browser environments. See the examples section for illustration.
newStorage
optional - A storage engine to use when persist()ing experiment data. newStorage
can be any custom storage solution implementing at least a minimum set of setItem()
and getItem()
from the web storage API.
Explicitly using sessionStorage
const optimize = require('google-optimize-service');
optimize.storage(window.sessionStorage);
optimize.persist(optimize.get(null));
Using a custom storage engine
const optimize = require('google-optimize-service');
const store = {};
optimize.storage({
setItem: (key, value) => {
store[key] = value;
},
getItem: (key) => store[key]
});
optimize.persist(optimize.get(null));
Sets the storage preference to use when deciding between local
- and sessionStorage
during discover()
.
If called without parameter, returns the current storage preference.
newPreference
optional - The storage preference to use. This should be one of the constants provided via storagePreferences.
const optimize = require('google-optimize-service');
optimize.storagePreference(optimize.storagePreferences.sessionStorage);
optimize.discover();
optimize.persist(optimize.get(null));
Map of available storage preferences to be used with storagePreference()
.
Currently available storage preferences:
storagePreferences.localStorage
prefers localStorage
over sessionStorage
.
storagePreferences.sessionStorage
prefers sessionStorage
over localStorage
.
storagePreferences
constitute only a hint. I.e. if the storage preference is set to sessionStorage
but only localStorage
is available, google-optimize-service
will pick localStorage
.
The MIT License (MIT)
Copyright (c) Hans-Peter Dietz @h_p_d | [email protected]
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.