Giter VIP home page Giter VIP logo

google-optimize-module's Introduction

Google Is Shutting Down Optimize

Google is shutting down Optimize Sept 30, 2023. Read the annoucement

nuxt-google-optimize

npm (scoped with tag) npm CircleCI Codecov Dependencies js-standard-style

SSR friendly Google Optimize module for Nuxt.js

๐Ÿ“– Release Notes

Features

  • Support multiple experiments (AB or MVT[Multi-Variant])
  • Auto assign experiment/variant to users
  • SSR support using cookies
  • CSS and state injection
  • Automatically revoke expired experiments from testers
  • Ability to assign experiments based on context conditions (Route, State, etc)

Setup

  • Add nuxt-google-optimize dependency using yarn or npm to your project
yarn add nuxt-google-optimize

OR

npm install nuxt-google-optimize --save
  • Add nuxt-google-optimize to modules section of nuxt.config.js
{
  modules: [
    'nuxt-google-optimize',
  ],

  // Optional options
  googleOptimize: {
    // experimentsDir: '~/experiments',
    // maxAge: 60 * 60 * 24 * 7 // 1 Week
    // pushPlugin: true,
    // excludeBots: true,
    // botExpression: /(bot|spider|crawler)/i
  }
}

Usage

Create experiments directory inside your project.

Create experiments/index.js to define all available experiments:

import backgroundColor from './background-color'

export default [
  backgroundColor
]

Creating an experiment

Each experiment should export an object to define itself.

experiments/background-color/index.js:

export default {
  // A helper exp-{name}-{var} class will be added to the root element
  name: 'background-color',

  // Google optimize experiment id
  experimentID: '....',

  // [optional] specify number of sections for MVT experiments
  // sections: 1,

  // [optional] maxAge for a user to test this experiment
  // maxAge: 60 * 60 * 24, // 24 hours,

  // [optional] Enable/Set experiment on certain conditions
  // isEligible: ({ route }) => route.path !== '/foo'

  // Implemented variants and their weights
  variants: [
    { weight: 0 }, // <-- This is the default variant
    { weight: 2 },
    { weight: 1 }
  ],
}

$exp

Global object $exp will be universally injected in the app context to determine the currently active experiment.

It has the following keys:

{
  // Index of currently active experiment
  "$experimentIndex": 0,

  // Index of currently active experiment variants
  "$variantIndexes": [
    1
  ],

  // Same as $variantIndexes but each item is the real variant object
  "$activeVariants": [
    {
      /* */
    }
  ],

  // Classes to be globally injected (see global style tests section)
  "$classes": [
    "exp-background-color-1" // exp-{experiment-name}-{variant-id}
  ],

  // All of the keys of currently active experiment are available
  "name": "background-color",
  "experimentID": "testid",
  "sections": 1,
  "maxAge": 60,
  "variants": [
    /* all variants */
  ]
}

Using inside components:

<script>
export default {
  methods: {
    foo() {
      // You can use this.$exp here
    }
  }
}
</script>

Using inside templates:

<div v-if="$exp.name === 'something'">
  <!-- You can optionally use $exp.$activeVariants and $exp.$variantIndexes here -- >
  ...
</div>
<div v-else>
  ...
</div>

Global style tests

Inject global styles to page body.

layouts/default.vue:

<template>
  <nuxt/>
</template>

<script>
export default {
      head () {
        return {
            bodyAttrs: {
                class: this.$exp.$classes.join(' ')
            }
        }
    },
}
</script>

If you have custom CSS for each test, you can import it inside your experiment's .js file.

experiments/background-color/index.js:

import './styles.scss'

With Sass:

.exp-background-color {
  // ---------------- Variant 1 ----------------
  &-1 {
    background-color: red;
  }
  // ---------------- Variant 2 ----------------
  &-2 {
    background-color: blue;
  }
}

With CSS:

/* Variant 1 */
.exp-background-color-1 {
  background-color: red;
}

/* Variant 2 */
.exp-background-color-2 {
  background-color: blue;
}

Development

  • Clone this repository
  • Install dependencies using yarn install or npm install
  • Start development server using yarn run dev or npm run dev
  • Point your browser to http://localhost:3000
  • You will see a different colour based on the variant set for you
  • In order to test your luck, try clearing your cookies and see if the background colour changes or not

License

MIT License - Alibaba Travels Co

google-optimize-module's People

Contributors

dependabot[bot] avatar farzadso avatar hecktarzuli avatar pi0 avatar renovate-bot avatar williamchong avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

google-optimize-module's Issues

Experiment is not set on Google Analytics

Description

I noticed that there was a discrepancy between the total number of sessions and the experiment sessions that were reported on Google Analytics.

After enabling the debug option for Google Analytics I noticed that the ga("set", "exp", exp) wasn't being called consistently.

Below is a workaround using @nuxtjs/google-analytics that seems to work for now.

// experiments.client.js
export default ({ $ga, $exp: { experimentID, $variantIndexes } }) => {
  if (!experimentID) return;
  const exp = experimentID + "." + $variantIndexes.join("-");
  $ga.set("exp", exp);
};
// nuxt.config.js
extendPlugins(plugins) {
  plugins.push("~/plugins/experiments.client.js");
  return plugins;
}

Reproduction

https://codesandbox.io/s/nuxt-google-optimize-issue-vkmho

What is Expected?

Console should output:

Executing Google Analytics commands.
Running command: ga("set", "exp", "test.0")

What is actually happening?

The command ga("set", "exp", "test.0") was never called

variant weight means ...

Just to confirm on what the variant weight values mean and how I can achieve a 50 / 50 split.

Would use weight of 1 on both of the variants in a two variant test be correct? Or should it be 0?

Sorry just the example and doc doesn't describe what / and how the weight should be used. It was also confusing that the default variant had a weight of 0.

Run multiple experiments simultaneously

Is it possible to run multiple experiments simultaneously?
As I see in the source code, if I create multiple experiments it randomly chooses only one based on the experiments weight.
Is there a way to run 2 experiments at the same time? i.e $exp will contain array of experiments where each experiment contains its active variant

Thanks in advanced,
Yael, Full-Stack Developer

Unsure of how to use

Good day!

I am unsure as to how to actually use the module with Google Optimize.

We have a SSR-ed Nuxt application, with Google Tag Manager installed and properly set up. We recieve statistics and added the Google Optimize bingings to the GTM on the GTM's side and it is working properly - segmentation occurs, cookie is set and all that.

Then, we've brought in your module, to actually react to the experiments on the server side. And this is where I get confused: your module sets the cookie with name exp and format { experimentID }.{ variant index }. GTM sets the cookie with name _gaexp and format GAX1.2.2{ experimentID }.?????.{ variant index }. Variant index actually differs between two cookies from time to time, and I don't really know which one actually applies.

This is separate (I think) from #16, as the $exp object is available.

Thank you for your assistance!

The usage of the module is not clear

I'm trying to understand how the module works.
You have completed setting up the project correctly and confirmed that the experiment is activated in the development environment.
However, it seems to work independently from the Google Optimized settings.
When I actually deployed and started the Google Optimizer experiment, I didn't see the results I wanted in the preview.
Thank you for letting me know what I'm missing.

Hydration error while using v-if

We got a hydration error when showing other variants than the first one on the first visit on site. This is due to that the server-side code that contains active variation to be the first index and then immediately after the variant changes.

I used v-if to conditionally render the visible component. Using v-show fixes this error but then the first variant will flash at the first load. Is it possible to trigger variant selection before Nuxt creates HTML code in the server? Right now we have fixed this by wrapping these components inside <client-only> tags, but this shows a blank area (or placeholder) for the area where the component should appear.

Forcing the "test" experience

Is there any way, for testing purposes, to force viewing the "test" experience, aside from simply setting the weight to 100? I ask because it can be helpful for QA purposes to verify expected functionality between test and control. It seems like manually modifying the cookie is another option, but I would prefer something like ?testName=enabled as a query param. If this is outside of the scope of the module, simply let me know.

Support for several experiments

Hello! I have been testing the module and looks like it works fine, but I dont know how would I be able to use two experiments at the same time. So I'm looking for something like this:

<div v-if="$experiments[$exp.name] === 'background'" class="absolute w-12 h-12 z-50 m-auto top-0 pt-16 right-0 bg-red-300 left-0" > experimento background activo </div> <div v-if="$exp.name === 'text'" class="absolute w-12 h-12 z-50 m-auto top-0 pt-16 right-0 bg-red-300 left-0" > experimento texto activo </div>

Use with google-tag-manager

Hi, congrats for the job with the module. I'm trying to use it with the google-tag-manager module also made by the nuxt-community. My google tag manager already has a tag for google optimize. In my nuxt.config.js the modules look like:
['@nuxtjs/google-tag-manager', { id: 'GTM-XXXXXX', layer: 'dataLayer' }], 'nuxt-google-optimize',
And the google tag assinstant look like the image:
google_optimize

With that configuration, I put a console.log in a component to see if I have access to the $exp object: if (this.$exp) { console.log(this.$exp) return this.$exp.$classes.join(" ") }

I have configured the experiment files too and created the experiment and so on... but it does not log the $exp object. Thank you again and sorry about the English thing (not my native language).

Just for SSR?

I'm just confirming, this module is only for target: server, mode: universal (SSR) correct?

Any other way doesn't seem to make sense.

@pi0 @farzadso

isEligible should fire on route change

Maybe I'm not understanding the intent of isEligible but I feel this should be continuously checked as route is being changed. Resulting in a experiment being able to be inactive until a user reaches a certain route.

publish as @nuxtjs

  • Rename references to @nuxtjs/google-optimize
  • Apply module template updates
  • Publish package
  • Deprecate nuxt-google-optimize

You need to run more than one experiment at a time

I am interested in the following possibility: it is required to run more than one experiment at a time. I can't find the parameters for this in the config.. Is it possible?

<body class="exp-123_example-1, exp-1234_example-1, exp-12345_example-1">
  ...
</body>

Missing Features

a) Robots - It's critical that spiders/bots get assigned the original version of the experiment so no unintended side effects occur. I propose a regex to match against user agent with a default that includes 'spider', 'bot' etc.. It can be disabled.

b) Emit Assignment Function - Since there are so many edge cases that would negate the initial window.ga push, a helper function should be exposed that would run the window.ga push again whenever you want.

c) Get Optimize Value Function - To help make this lib more useful outside of Vue Analytics, a helper function or $exp.prop should be exposed that gets the value of the Optimize token (uePZO471S-6qGUwbeUyw_Q.1 for example). This would make this lib much more helpful in GTM as well.

d) Ability to Disable Auto-Assign Reporting - There are cases when you don't want the assignment on first page hit. Specifically when you are looking at people hitting a certain page type you don't want to tell Optimize/GA about it as your results would be diluted with people that may have never seen the experiment. This should be optional.

If these are acceptable, I wouldn't mind making a pull req, but before I spent time on it I wanted to make sure the Nuxt gang was on board since this lib doesn't seem to be getting any updates besides dep bumps.

@pi0 @farzadso

cc: @Atinux

named variants

Originally mentioned by @hecktarzuli (#34 (comment))

I'm also toying with the idea of revamping the MVT support. Currently it's just 'sections:#' and weights but in practice I would find it very hard to code an experiment against a variant index and an intVal vs a named obj with values. For example.
As a user, I'd prefer something like this
if($exp.$activeVariants.buttonColor == 'red') ..
if($exp.$activeVariants.headerText == 'excited') ..
vs
An array of variant objects ($exp.$activeVariants)
[ {weight: 25 }, { weight: 25}, {weight: 25 }, { weight: 25}]..
This idea is pretty new and not totally flushed out, but if we do decide to go in this direction, then we'd want a new major version for sure.

As a non breaking change, we may support new flattened $exp.variants[name || index] computed property which is an object from itentifier to variant object.

Seems to require Google Tag Manager

I struggled to get this working but eventually figured it out. I couldn't see this anywhere in the docs, but I had to add the container ID using Google Tag Manager. It's simple enough with the Nuxt module:

modules: [
   ['@nuxtjs/google-tag-manager', { id: 'your-container-id' }],
]

Without this, experiment data was not being sent back to Optimize.

I have not looked into this deeply, so maybe my case is a one-off, or maybe this belongs in the docs, I dunno.

Can't Handle MVT

It doesn't look like the plugin can handle MVT with sections > 1. In the variant index selection code, it resets the weight of the current variant index to 0. In the case of a 2x2 experiment, that would mean that only 0-0, 1-0, or 0-1 experiments can be chosen. 1-1 would never be chosen because the weight for it would be reduced to zero before the second round of picks.

Additionally, it doesn't look like it can handle different numbers of variants per section. Would it be possible to get an update that can handle MVT more universally? If I'm wrong and just not seeing how to do that right, please let me know.

can anyone confirm if this is working?

I've attempted to use this module recently and all looked fine. However, after following the google dev guide for setting up the experiments. I could not get any session record tracked in the GO interface.

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

circleci
.circleci/config.yml
npm
package.json
  • cookie ^0.5.0
  • weighted-random ^0.1.0

  • Check this box to trigger a request for Renovate to run again on this repository

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.