American Express billing statements intermittently won't download, with "ReferenceError: $iTagTracker is not defined pdfweb2.16.js:1225"

RESOLVED INCOMPLETE

Status

Tech Evangelism
Desktop
RESOLVED INCOMPLETE
2 years ago
a year ago

People

(Reporter: dholbert, Unassigned)

Tracking

Firefox Tracking Flags

(Not tracked)

Details

(Whiteboard: [see comment 6 for summary, comment 9 for suggested change] [sitewait], URL)

Attachments

(1 attachment)

(Reporter)

Description

2 years ago
STR:
 0. Have an American Express account.
 1. Visit https://online.americanexpress.com/myca/statementimage/us/welcome.do?request_type=authreg_StatementCycles
   (Login, if prompted.)

 2. Click a month with a PDF icon next to it -- e.g. for the most recent month available.

EXPECTED RESULTS: A file-download dialog should appear.

ACTUAL RESULTS: The PDF icon changes to a throbber image, but no dialog ever appears.  The following appears in my error console:
> ReferenceError: $iTagTracker is not defined  pdfweb2.16.js:1225

That's referring to the "$.isFunction($iTagTracker)" check in this code:
> if(arraiTagValues!="PARSING_ERROR"){if(asset.length==2){($.isFunction($iTagTracker))? [ ...SNIP ...]
https://online.americanexpress.com/myca/shared/summary/estatement/pdf/js/pdfweb2.16.js

This bug reproduces intermittently -- i.e. sometimes $iTagTracker is defined (and I get EXPECTED RESULTS), sometimes it is not defined (and I get ACTUAL RESULTS).  I've only seen it fail in Firefox, though -- not Chrome. (not sure why; there may be a race condition of some sort, which could be a website bug or a browser bug.)

A few observations:
(1) When $iTagTracker *is* defined (i.e. in cases where the bug doesn't reproduce), it's defined as a function.  So I think this "$.isFunction" check is really just intending to check "Did the code to initialize $iTagTracker run yet."

(2) When $iTagTracker *is* defined, it's an alias for window.iTagTracker. (I think this is how "$" works in jquery? not sure.)

(3) From local testing, it seems that if this code were to instead pass window.iTagTracker (instead of $iTagTracker) into the "$.isFunction()" check, it would work more reliably -- i.e. it would return false instead of throwing, for undefined values.  In other words: $.isFunction($helloIAmUndefined) will throw, whereas $.isFunction(window.helloIAmUndefined) will returns false.  Chrome & Firefox are consistent on this.

So I think this might work better if they changed their check to use "window." instead of "$" here. (Or maybe there's another better way to pass in undefined $VARIABLES to $.isFunction() in a way that doesn't throw? not sure.)

Mike, any chance you have an AmEx account and can reproduce this bug (and/or have any insight about the JQuery stuff here?)
(Reporter)

Updated

2 years ago
Flags: needinfo?(miket)
(Reporter)

Comment 1

2 years ago
(In reply to Daniel Holbert [:dholbert] from comment #0)
>  1. Visit
> https://online.americanexpress.com/myca/statementimage/us/welcome.do?request_type=authreg_StatementCycles

(Alternate way to get to this page: click "Statements & Activity" at upper-left of AmEx account main page, and then "Billing Statements" towards upper-right of that page.)
(Reporter)

Updated

2 years ago
Summary: American Express billing statements intermittently won't download, with "ReferenceError: $iTagTracker is not definedpdfweb2.16.js:1225" → American Express billing statements intermittently won't download, with "ReferenceError: $iTagTracker is not defined pdfweb2.16.js:1225"
(In reply to Daniel Holbert [:dholbert] from comment #0)
> > ReferenceError: $iTagTracker is not defined  pdfweb2.16.js:1225

Do you have tracking protection on? This looks like some analytics code to report what buttons you're clicking on.

> That's referring to the "$.isFunction($iTagTracker)" check in this code:
> > if(arraiTagValues!="PARSING_ERROR"){if(asset.length==2){($.isFunction($iTagTracker))? [ ...SNIP ...]
> https://online.americanexpress.com/myca/shared/summary/estatement/pdf/js/
> pdfweb2.16.js
> 
> This bug reproduces intermittently -- i.e. sometimes $iTagTracker is defined
> (and I get EXPECTED RESULTS), sometimes it is not defined (and I get ACTUAL
> RESULTS).  I've only seen it fail in Firefox, though -- not Chrome. (not
> sure why; there may be a race condition of some sort, which could be a
> website bug or a browser bug.)

Oh hrm. Tracking protection shouldn't be intermittent. But lookind around, $iTagTracker is an Omniture tracking thing.

> A few observations:
> (1) When $iTagTracker *is* defined (i.e. in cases where the bug doesn't
> reproduce), it's defined as a function.  So I think this "$.isFunction"
> check is really just intending to check "Did the code to initialize
> $iTagTracker run yet."
> 
> (2) When $iTagTracker *is* defined, it's an alias for window.iTagTracker. (I
> think this is how "$" works in jquery? not sure.)

Nah, $ in jQuery is more like a function that returns jQuery instances, and sometimes people hang expandos off of it -- by default it won't create globals. 

(But sometimes people also just use the "$" to indicate that it's a jQuery object instance (i.e., can use jQuery API methods). Or sometimes, people come from PHP and they use that to denote a variable.)

I found this one random window.$iTagTracker definition here:

<https://github.com/jmuhammed/CustomAnnotation/blob/e892a72a0b39db025a1411eda099a6cce92968d6/binduilayer.js#L5>
 
> (3) From local testing, it seems that if this code were to instead pass
> window.iTagTracker (instead of $iTagTracker) into the "$.isFunction()"
> check, it would work more reliably -- i.e. it would return false instead of
> throwing, for undefined values.  In other words:
> $.isFunction($helloIAmUndefined) will throw, whereas
> $.isFunction(window.helloIAmUndefined) will returns false.  Chrome & Firefox
> are consistent on this.
> 
> So I think this might work better if they changed their check to use
> "window." instead of "$" here. (Or maybe there's another better way to pass
> in undefined $VARIABLES to $.isFunction() in a way that doesn't throw? not
> sure.)
> 
> Mike, any chance you have an AmEx account and can reproduce this bug (and/or
> have any insight about the JQuery stuff here?)

Sadly, I don't have an account to repro. :(

Adam, any chance you have an Amex account?
Flags: needinfo?(miket) → needinfo?(astevenson)
I don't unfortunately.
Flags: needinfo?(astevenson)
(Reporter)

Comment 4

2 years ago
(In reply to Mike Taylor [:miketaylr] from comment #2)
> (In reply to Daniel Holbert [:dholbert] from comment #0)
> > > ReferenceError: $iTagTracker is not defined  pdfweb2.16.js:1225
> 
> Do you have tracking protection on? This looks like some analytics code to
> report what buttons you're clicking on.

I didn't have tracking protection on -- I reproduced in a fresh profile (and not in private browsing mode).

> Oh hrm. Tracking protection shouldn't be intermittent. But lookind around,
> $iTagTracker is an Omniture tracking thing.

For AmEx, it seems to be defined here:
window.$iTagTracker=function(){this.map={"layertrack":function(){if(args.length>1){omn_pagename=args[1];omn.pagename=args[1];var layerVals="layer"+$itag.PageId+"vals";var o;var c;if(typeof clearevents=="function")clearevents();for(o in $iTagData[layerVals])if(typeof $iTagData[layerVals][o]=="function"){window[o]=$iTagData[layerVals][o]();
https://nexus.ensighten.com/amex/prod/code/b1d9d5b886aece3aee06e6ff31160071.js

(The "omn" stuff suggests you're on-target about Omniture.)

When I compared a "File|Save As Complete" dump of a buggy scenario vs. a working scenario yesterday, that JS file was *missing* in the buggy scenario.  I also don't see any mentions of that script's name (b1d9d5b886aece3aee06e6ff31160071.js) in the page's initial HTML (in "view source"), so I think it's loaded dynamically (i.e. a new <script> tag gets appended to the DOM at some point after pageload).

So, it seems that this dynamic script load must be what's failing to happen, in the buggy scenario, though I don't know why/when.
(Reporter)

Comment 5

2 years ago
I do think this is a tracking/no-tracking thing, though. Some googling reveals that ensighten (where that omniture script is hosted) exists to help companies enforce DNT: http://blogs.wsj.com/digits/2011/07/21/start-up-ensighten-aims-to-let-websites-enforce-do-not-track/

So: i'm guessing it's a host for tracking scripts, and it makes some yes/no decision while the page is loading. (And this bug reproduces when it decides "no".)

Sadly, turning on DNT doesn't seem to be sufficient to trigger this bug. (And I hit the bug without DNT, too.) So it's not as simple as that.

One useful data-point, though -- when this reproduces (i.e. when the script from comment 4 is missing), I see only two scripts loaded from nexus.ensighten.com (as shown in our JS debugger devtools):
 https://nexus.ensighten.com/amex/amexhead/Bootstrap.js
 https://nexus.ensighten.com/amex/amexhead/serverComponent.php

When things are working correctly, I see *lots* of scripts get loaded from nexus.ensighten.com, including one extra instance of serverComponent.php, which has the following:
> var psj6 = 'https://nexus.ensighten.com/amex/prod/code/b1d9d5b886aece3aee06e6ff31160071.js?conditionId0=418409';
> Bootstrapper.loadScriptCallback(psj6, Bootstrapper.callOnPageSpecificCompletion);

So: that seems to be where the iTagTracker-defining script gets loaded, when things are working.
(Reporter)

Comment 6

2 years ago
So stepping back from my dig here -- the basic summary of the problem here is that:
 (1) their pdf-downloading scripts seem to be implicitly (and accidentally) depending on a tracking script having been loaded.
 (2) They're using ensighten to host their tracking scripts, and it sometimes (for not-yet-known reasons) doesn't actually add the tracking scripts to this AmEx page.

I say they're "accidentally" depending on it because they try to handle the case where it's not defined, using "$.isFunction", as shown in comment 0 -- but that throws when passed an undefined variable.

They might really want to be checking if (typeof $iTagTracker === "undefined") instead of using $.isFunction, I think...
(Reporter)

Comment 7

2 years ago
er, I suppose they really want
 if (typeof $iTagTracker === "function") 
...as an undefined-friendly drop-in replacement for their $.isFunction(($iTagTracker) call.
Yeah, that matches what this other site is doing here:

(typeof($iTagTracker)=='function' )? $iTagTracker('rmaction','Click_FacebookShare') : null;

<https://github.com/solcratius/SBS/blob/ae0cb62983eea927a1b2979d31b9c8e9afdfd066/ambassador/headerfooterscript.js#L81>
(Reporter)

Comment 9

2 years ago
@AmericanExpress seems relatively active, so I reached out over Twitter:
  https://twitter.com/CodingExon/status/723567341305352192

Any American Express developers who end up here: hi / thanks! See comment 6 for a description of the bug (and comment 0 for what it breaks).

Our suggested change is to edit this script...
 https://online.americanexpress.com/myca/shared/summary/estatement/pdf/js/pdfweb2.16.js
...to replace all instances of this check:
> $.isFunction($iTagTracker)               <--- Throws exception if $iTagTracker is undefined!
...with:
> typeof($iTagTracker)==='function'        <--- Doesn't throw.
(Reporter)

Updated

2 years ago
Whiteboard: [see comment 6 for summary, comment 9 for suggested change]
(Reporter)

Comment 10

2 years ago
Created attachment 8744419 [details]
screencast of bug
Just a quick note since Adam asked me to try this the other day:
The Canadian AMEX site seems to be different from the US one (entirely different UI) and it works fine when clicking on the PDF statements.
Adding [sitewait] because of the contact effort by daniel.

Does it still reproduce? In this case, we might want to switch back to needscontact
Flags: needinfo?(dholbert)
Whiteboard: [see comment 6 for summary, comment 9 for suggested change] → [see comment 6 for summary, comment 9 for suggested change] [sitewait]
Also @jakeadams on https://github.com/americanexpress

Updated

a year ago
(Reporter)

Comment 14

a year ago
(In reply to Karl Dubost :karlcow from comment #12)
> Does it still reproduce? In this case, we might want to switch back to
> needscontact

So far, I've only ever been able to reproduce on my mom's laptop.

I'll be seeing her sometime in the next month, and I'll give this a try when I do.
(Reporter)

Comment 15

a year ago
My mom actually doesn't have an American Express account anymore, so I'm unable to test this now.

I guess I'll resolve as INCOMPLETE, though if anyone else can test & reproduce using STR in comment 0, please feel free to reopen.
Status: NEW → RESOLVED
Last Resolved: a year ago
Flags: needinfo?(dholbert)
Resolution: --- → INCOMPLETE
You need to log in before you can comment on or make changes to this bug.