Get JavaScript tracker version

Hello, how can I get the tracker version (e.g. “3.3.1”) at runtime?

My use case, in case someone has a better suggestion: make my code compatible both with v2 and v3, while we transition from v2 to v3:

if(trackerVersion === 2){

  snowplow('trackStructEvent', 'category', 'action', 'label', 'property', 0.0);

} else {

snowplow('trackStructEvent', {
  category: 'category',
  action: 'action',
  label: 'label',
  property: 'property',
  value: 0.0
});

}

Thanks,

Boris

Unfortunately, I don’t believe there is a supported way to retrieve the tracker version during runtime.

There are some hacks that you could do such as to check for some features that were introduced in v3. Here is one such option:

window.snowplow(function () {
  if (this.sp1.addPlugin) { // sp1 is the namespace of my initialized tracker
    console.log('Running v3');
  } else {
    console.log('Running v2');
  }
});

However, if you can find some other way to work around this instead of relying on a hack like this, that would be preferable.

Version is exported as part of the API - but I’m not sure if there’s a public method to actually grab it @PaulBoocock ?

In terms of migration I think it’d be quite a bit easier to migrate everything to v3 rather doing it call by call - and it’ll also avoid the overhead of including and compiling two different versions of the tracker on each page.

It’s not exposed in the “Tag Based” tracker, so I think feature detection as Matus suggests is the only option. Bit tricky because its in a callback though.

Hi guys, thanks for the help, really appreciate it.

The reason we are thinking of doing like this is that we setup the tracker in a core repository. Most of the tracking code is there, but we also have other front end code sitting in another repository and deployed as a package which sends structured and Enhanced Ecommerce events which both have their signature changed.
So the idea is to do:

  1. make the tracking code in the package compatible with both versions. Core still setups v2
  2. migrate core to v3
  3. clean up package by removing v2-compatible code

Can’t think of another way to do it. It’s going a bit off-topic but if you know a better way, I’m very curious to hear about it, because I agree that it would be better to do it in one go without a hack to determine the tracker version.

I don’t know Javascript well so this might be a terrible idea. What kind of error do you get if you call the v3 style API from v2? Could you do a try catch?

Hi Miranda, unfortunately, if I send e.g. a struct event using the v3 signature while v2 is initialized, the object is sent as the first field (category).

I have a weird and not entirely sensible dislike for doing things manually but given how similar the API is I’d look at using something like recast to automatically transform v2 to v3. You’ll probably still want to test / QA afterwards.

For an input of:

snowplow('trackStructEvent', 'category', 'action', 'label', 'property', 0.0);

snowplow('trackSelfDescribingJson', {
  schema: 'iglu:test',
  data: {
    example: '123'
  }
})

The following transform function:

export default function transformer(code, { recast, parsers }) {
  const ast = recast.parse(code, { parser: parsers.esprima });
  const b = recast.types.builders;
  const namespace = "snowplow"
  const args = ast.program.body[0].expression;
  // convert a structured event
  ast.program.body[0] = b.expressionStatement(
      b.callExpression(b.identifier(namespace), [b.literal('trackStructEvent'), b.objectExpression([
        b.property("init", b.identifier("category"), args.arguments[1]),
        b.property("init", b.identifier("action"), args.arguments[2]),
        b.property("init", b.identifier("label"), args.arguments[3]),
        b.property("init", b.identifier("property"), args.arguments[4]),
        b.property("init", b.identifier("value"), args.arguments[5]),
      ])])
    )
  
    // convert a self describing json event
  const sdjson = ast.program.body[1];
  ast.program.body[1] = b.expressionStatement(
      b.callExpression(b.identifier(namespace), [b.literal('trackSelfDescribingEvent'), b.objectExpression([
        b.property("init", b.identifier("event"), sdjson.expression.arguments[1]),
      ])])
    )

  return recast.print(ast).code;
}

will yield the output

snowplow("trackStructEvent", {
  category: 'category',
  action: 'action',
  label: 'label',
  property: 'property',
  value: 0.0
});

snowplow("trackSelfDescribingEvent", {
  event: {
    schema: 'iglu:test',
    data: {
      example: '123'
    }
  }
})

You can test this on AST explorer here.

1 Like

Hi Mike, and wow, thank you for taking the time to post this detailed solution.
I’m afraid we’re reaching the limits of my understanding (am not a JS dev). I bet your snippet will be useful to someone else but for now I’ve started to implement matus’ suggestion and will test that.

But just to clarify, your transform function always transforms to the v3 signature, right? Even if the tracker that’s loaded is v2?

Yes - you may need to customise it according to your codebase but the idea would be that you could run it across your source files to identify any v2 instances and transform them to v3 rather than having to do so by hand.

Oooh, okay, I hadn’t understood what your code was doing. Actually it modifies the source code, right? Neat.
But we don’t have that so many calls per repo so doing it by hand is not too much an issue.

Our main concern was how to ensure that when we update the repo which initializes the tracker to v3, events sent by other repositories are not being sent with the wrong signature. Even if we try to deploy them at the same time, we still might loose some events.

Ah fair enough.

Any chance you’ve got any functional tests in place? Having Snowplow Micro as part of your CI/CD pipeline can help a lot as you can assert that the events are getting sent through correctly.