This library is a developer preview.
It provides an easy and powerful way to implement A/B testing with React
. It is made to work with Digital Optimization Groups' Headless CMS and requires an account on our platform.
Signing up for a developer preview requires an invite. If you would like to join the waiting list for access please email us at [email protected].
The SDK includes the following features:
- Simple implementation with a render prop
- A/B/n testing of arbitrary data structures
- A/B/n testing of
React
components - Viewport exposure tracking of all variations
- Wide range of client metrics automatically collected and associated with variations
The DigitalOpt Group React SDK can be installed and added to the project specific dependencies by running the following command:
npm install --save @digitaloptgroup/cms-react
The SDK provides the following set of Providers
and Render Props
:
- AbTesting
- Feature
- Feature.Track
- withOutcome
- withPathChange
- withCaughtError
https://docs.digitaloptgroup.com
Digital Optimization Groups' React SDK makes uses of a provider to inject all the required code into your application.
The provider is required for the correct usage of the SDK. Its main purposes are:
- Make a connection to the public API
- Provide RealTime development feature
- Initialize analytics tracking
The provider should be placed at the root
of your application and expect a set of configuration properties (explained below):
The React SDK requires a set of keys and configurations required to connect the Client Application with the Public API.
projectId (required)
The Application Id or Project Id given to you by Digital Optimization Group when creating your account.
vid (optional)
Internally the API sets a cookie with a unique ID for each user. This cookie is used to assure consistent assignment of variations. You may optionally pass in your own unique visitor identifier that will be used to provide assignments.
rid (optional)
Unique request Id. If you are deploying your application into the DigitalOptADN you should not set this as it will be done for you automatically.
startTimestamp (optional)
Server timestamp of request Id creation time. If you are deploying your application into the DigitalOptADN you should not set this as it will be done for you automatically.
import { AbTesting } from "@digitaloptgroup/cms-react";
ReactDOM.render(
<AbTesting projectId="your-app-or-project-id">
<App />
</AbTesting>,
document.getElementById("root")
);
All components provided by SDK, are written as Render Props or Higher Order Components, to provide a full set of features, with minimal impact on your app.
There are currently 2 render props, and they are:
- Feature
- Feature.Track
And 3 higher order components:
- withCaughtError
- withOutcome
- withPathChange
This component fetches the data related to a Schema from the CMS (Feature Schema Documentation).
Props that can be passed to the Feature
component.
queryName (required)
The root entrypoint to query your API. This is defined in the CMS when creating a new Schema.
args (as required by Schema type)
When defining a Schema it may be created with one or more parameters, such as path
for blog posts, lang
for localization, or sku
for products. Providing these to the Feature
component will allow you to query for a specific Feature that implements a given Schema.
Props passed from Feature
to the user's render prop function.
error
Provided in the event of an error.
type Error = null | { code: number; message: string };
Note on serving 404 pages
If the given combination ofqueryName
andargs
does not result in a feature this will return a 404 error with the following object:
{code: 404, message: "404 - Feature not found"}
This is useful if you are serving pages, such as blog posts, and would like to dynamically show your visitors 404 pages when a page does not exist.
isLoading
A boolean prop indicating feature loading.
type IsLoading = boolean;
variation
The variation assigned to a given user for the requested feature. This can be either an object containing the properties defined by the feature's schema or it can be a list of variations.
type Variation =
| FeatureSchema
| Array<{ tracking: Tracking; variation: FeatureSchema }>;
type FeatureSchema = { [key]: any };
tracking
The tracking object associated with a given variation.
type Tracking = {
releaseId: string;
featureId: string;
variationId: string;
exposureId: string;
};
import { Feature } from "@digitaloptgroup/cms-react";
function App() {
return (
<Feature queryName="helloWorld">
{({ error, isLoading, variation, tracking }) => {
if (variation) {
const { image, headline, subhead } = variation;
return (
<div>
<img src={image.url} />
<h1>{headline}</h1>
<h4>{subhead}</h4>
</div>
);
} else if (isLoading) {
return <div>Loading...</div>;
} else if (error) {
return (
<div>
{error.code} : {error.message}
</div>
);
}
}}
</Feature>
);
}
This component provides viewport tracking for assigned variations including proportion of exposure and time in viewport.
Props that MUST be passed to the Feature.Track
component.
releaseId (required)
This Id represents a hash of the entire release and provides integrity when analyzing data by assuring it is always possible to know what other elements may have been under test at any given time.
featureId (required)
Represents a hash of all the variations for a given feature in a given release. It provides integrity to know what other variations where under test for a given feature.
variationId (required)
A hash of the variation, assuring integrity of knowing the exact content for a given variation.
exposureId (required)
Not currently used, but still required. This may be used in the future for more granular exposure tracking than provided at the variation level (like by fields).
Props passed from Feature.Track
to the user's render prop function.
trackingRef
A React ref that MUST be attached to a root DOM element surrounding the implementation of a given variation.
import { Feature } from "@digitaloptgroup/cms-react";
function App() {
return (
<Feature queryName="helloWorld">
{({ error, isLoading, variation, tracking }) => {
if (variation) {
return (
<Feature.Track {...tracking}>
{({ trackingRef }) => {
return <div ref={trackingRef}>{/*...*/}</div>;
}}
</Feature.Track>
);
}
/* ... */
}}
</Feature>
);
}
Refer to A/B Testing Analytics for a full overview of metrics automatically and manually tracked by this SDK.
This section will cover the manual tracking details from the SDK.
The SDK provides a set of higher order component that offers the possiblity of wrapping your components to track additional analytics information not tracked automatically.
The use of these HOCs requires the main application to wrapped within the AbTesting provider, but it can be applied to any of the components provided within the SDK. It will also work with normal React components.
Examples
Record add to cart events, page views, searches, checkouts, and more.
This higher order component passes the pathChange
prop to it's wrapped child, allowing for page view metrics to be associated with A/B test variations.
None
Props passed to the wrapped component.
pathChange
A function that can be used to track pageviews.
type PathChange = (pathname: string) => void;
import { withPathChange } from "@digitaloptgroup/cms-react";
class BlogPost extends React.Component {
componentDidMount() {
this.props.pathChange(this.props.location.pathname);
}
componentDidUpdate(prevProps) {
if (this.props.location.pathname !== prevProps.location.pathname) {
this.props.pathChange(this.props.location.pathname);
}
}
render() {
/*...*/
}
}
const BlogPostWithPageTracking = withPathChange(BlogPost);
This higher order component passes the outcome
prop to it's wrapped child, allowing for custom outcomes to be associated with A/B test variations.
None
Props passed to the wrapped component.
outcome
A function that can be used to track custom outcomes. Any outcome can be used to evaluate a given A/B test.
type Metadata = Array<{ key: string; value: string }>;
type Outcome = (name: string, metadata: Metadata) => void;
Naming Outcomes
We recommend picking and sticking with a consistent naming convention for outcomes. One that we like is the Object / Action naming convention. For example:
- cartAddItem
- cartRemoveItem
- searchAddFilter
- searchEnterPhrase
- productView
import { withOutcome } from "@digitaloptgroup/cms-react";
class ProductItem extends React.Component {
cartAddItem = (sku, price) => {
const name = "cartAddItem";
const metadata = [
{ key: "sku", value: sku },
{ key: "price", value: price }
];
this.props.outcome(name, metadata);
};
render() {
/*...*/
}
}
const ProductItemWithOutcome = withOutcome(ProductItem);
This higher order component passes the caughtError
prop to it's wrapped child, allowing for caught errors to be associated with A/B test variations. This can be useful for monitoring A/B tests and becoming notified of potential bugs or problems with a particular test variation.
None
Props passed to the wrapped component.
caughtError
A function that can be used to track errors your application catches.
type CaughtErrorMetadata = Array<{ key: string; value: string }>;
type CaughtError = (metadata: CaughtErrorMetadata) => void;
import { withCaughtError } from "@digitaloptgroup/cms-react";
class CartCheckout extends React.Component {
completeOrder = () => {
stripe.createSource(this.card).then(result => {
if (result.error) {
const metadata = [
{ key: "location", value: "stripe.createSource" },
{ key: "error", value: error.message }
];
this.props.caughtError(metadata);
/* ... */
} else {
/*...*/
}
});
};
render() {
/*...*/
}
}
const CartCheckoutWithErrorReporting = withCaughtError(CartCheckout);
If you'd like to do server side rendering just reach out to us.