Google Analytics not tracking events in HTML5 mobile app properly on iPhones - ios

We are using Google Analytics to track events, but events don't appear to track 100% of the time. Sometimes they track, and sometimes they don't. We're not exceeding quota limits per session (at most we have 20 events per session). That shouldn't be the issue.
The tracking fails to work consistently on our normal website as well as our HTML5 mobile app version, though it's far less reliable with the HTML5 mobile app version.
Code:
var share_url = 'http://twitter.com/intent/tweet?text=';
// Log in GA
_gaq.push( ['_trackEvent', 'Share Twitter', ''] );
// Open URL in browser
open_external( share_url + encodeURIComponent( msg ) );
function open_external( url ) {
window.open( url + '#phonegap=external' );
}

_gaq.push( ['_trackEvent', 'Share Twitter', ''] );
This won't do anything.
For _trackEvent, the third argument (where you pass an empty string) is required. It's the 'Action' parameter. But an empty string is falsey, so it just fails silently.
Pass any value there, and it'll work.
Is this a reduced case? You shouldn't be seeing any events with that code.

Are you positive that you waited long enough for the data to be processed by Google? Especially since some tracking seems to be working.
I had the same behaviour (in a mobile app btw) but after waiting for more than a day it still came through. This still occurs on a daily basis... Hope this is the case for you too.

I'm not exactly sure what your problem can be, so I will throw some idea.
Most of them are obvious but it might help.
On your website:
Are you sure your embed the Google Analytics code snippet on every page who required tracking?
Load Google analytics from the asynchronous way.
On Google analytics check on Real time > Overview. As full report are delayed from few hours.
If you url is something like httq://localhost/ then your need to add the javascript code _gaq.push(['_setDomainName', 'none']); please read this post
It can't work with file:// url
(Probably not) Check if you can download the JavaScript from Google Analytics. Maybe your proxy block Google analytics tracking ?
In your application:
You are using embedded HTML 5 page within your app. So the way your open a page is using file://PATH_TO_MY_DIR/index.html as it's on your hard drive you can't send data to Google analytics.
As you are probably using PhoneGap, you need to "jump out" of your HTML page into native Objective-c code and send the event from your Objective-C code. Read Google Analytics and PhoneGap and this google group thread
Hope it help.

The problem is third parameter in:
_gaq.push( ['_trackEvent', 'Share Twitter', ''] );
The 2nd element of the array should be the category and the 3rd should be the action. For example:
_gaq.push( ['_trackEvent', 'Share', 'Twitter'] );
You can verify this yourself by pasting each of the above into your developer console (F12 in Chrome, Ctrl-Shift-K in Firefox) and watching the network traffic.
Reference:
https://developers.google.com/analytics/devguides/collection/gajs/methods/gaJSApiEventTracking

Related

Seaside redirect for render not working on physical iOS devices

We're having a problem with physical iOS devices (works fine on Chrome virtual device) where a final Seaside redirect is not happening after an Azure SSO redirect.
I'd like to understand what triggers the Seaside redirect: I can see it in normal rendering, but I've never had to dig into it like this before.
When I log from a non-iOS device I see...
1 - WAApplication>>handleFiltered: application URL
self requestContext redirectTo: 'https://login.microsoftonline.com/...'
redirects back to our app URL with an access token
2 -WAApplication>>handleFiltered: application URL with MS access token & no _s & _k values
validate token with Azure
save user info in new WASession
finish render
3 - WAApplication>>handleFiltered: application URL with _s & _k plus callback values like: &2=2160&1=3840&3=false
WAResponse>>location: application URL with _s & new _k and no callback values
4 - WAApplication>>handleFiltered: application URL with _s & _K
finish render
With iOS step 3 does not happen; I'd like to know what triggers it normally.
Just to add to the fun, we have a two WAApplication registered. The default application fails on iOS, the other works fine. I can see no obvious difference between the two.
Thanks for any help (I'll cross post on the the Seaside mailing list and Discord)
Problem is caused by a seven year old method that used a window.location.href= to gather device characteristics, like screen size and touch support. Removing that href fixes the problem with iOS. Lots of other & cleaner ways to get the data.
Quick fix is to wrap the href with a setTimeout for 200 ms.

The embedded player shows "Please click here to watch this video on YouTube" to some users under unclearly circumstances

We use the YouTube embedded player on a hybrid app based on Cordova. The app has a lot of traffic worldwide.
The player displays the message "Please click here to watch this video on YouTube" to some users when they try to play any video under unclearly circumstances.
We do not see a clear pattern, it doesn't seem to depend on the user's country nor the restrictions of the video.
We have seen in the player code (https://www.youtube.com/yts/jsbin/player_ias-vflrnurMS/en_US/base.js) that the message is assigned to a constant called "TOO_MANY_REQUESTS_WITH_LINK" but there is no high volume of requests per user and the quota cannot be configured as in other Google APIs.
We follow the iFrame API reference:
https://developers.google.com/youtube/iframe_api_reference?hl=en
<iframe id="player" src="https://www.youtube.com/embed/M7lc1UVf-VE?autoplay=1&cc_load_policy=0&controls=0&disablekb=1&enablejsapi=1&fs=0&iv_load_policy=3&loop=0&modestbranding=1&playsinline=1&rel=0&showinfo=0&wmode=transparent&origin=XXX" frameborder="0"></iframe>
<script type="text/javascript">
var player,
scriptTag = document.createElement('script'),
firstScriptTag = document.getElementsByTagName('script')[0];
scriptTag.src = "https://www.youtube.com/iframe_api";
firstScriptTag.parentNode.insertBefore(scriptTag, firstScriptTag);
function onYouTubeIframeAPIReady() {
var options = JSON.parse('{"autoplay":1,"cc_load_policy":0,"controls":0,"disablekb":1,"enablejsapi":1,"fs":0,"iv_load_policy":3,"loop":0,"modestbranding":1,"playsinline":1,"rel":0,"showinfo":0,"wmode":"transparent","origin":"XXX"}');
if (!options.origin) {
options.origin = location.origin ||
location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '');
}
player = new YTRemoteVPlayer('player', '<%-videoId%>', options);
}
</script>
Does anyone know what may be happening and how to fix it?
Me and my teammates managed to reproduce that behaviour locally.
To reproduce that behaviour, all you need to do is, under the same IP Address, to load the youtube JS multiple times and for different videos. Although I cannot clarify the exact amount of times it must be done (we left some devices aside doing it), the behavior certainly happened.
As an attempt of a workaround for that problem, we accessed the https://web.archive.org/web website and fetched an old YouTube JS script (https://www.youtube.com/iframe_api). We tried to use that old script, but with no success. The message continued to appear =/.
I really do not know if there is much we, developers, can do about it, but wait for an YouTube statement and/or revision of recent changes on their end.
Update
There is an issue opened on Google's issue tracker website:
https://issuetracker.google.com/issues/143091693
Update
It looks like that YouTube have resolved that problem on their end. We'll keep monitoring :)
Update (November 5th 2019)
The problem is happening again.
Update (November 7th 2019)
I have opened a new issue on issuetracker:
- https://issuetracker.google.com/issues/144057800
I don't have a fix for it, but I can add more information about the problem, this way maybe someone can help us with this issue.
I am getting the same error with some users, and like you said there is no a clear pattern. My devices are working properly, but I did some tests with the help of a user of my app that is getting this error. Following the results:
Demo used in my tests: https://developers.google.com/youtube/youtube_player_demo
Test 1 - Open the iframe player api demo on device's browser - WORKED
Test 2 - Open the iframe player api demo into a webview on my app - FAIL
Test 3 - Open the iframe player api demo into a webview on my app using a VPN connection - WORKED
So, it appears to be a combination of APP + IP is blocked. I don't know the reason, and it will be very helpful if someone repeat these tests. I am trying to confirm it with another user, but it's a little hard to find someone willing to help.
UPDATE: a second user tried to use a VPN and it worked to him too.
UPDATE 2: a user with this problem told me that the videos are working properly again now. It appears to be a temporary block by Youtube on server side.

Is there a way to recognize, that the app was installed thru firebase dynamic link in didFinishLaunchingWithOptions?

I am implementing firebase dynamic links in my iOS app and I can already parse the link, redirect to AppStore etc. Now I want to distinguish the first run of the app, when user installs it from the dynamic link - I want to skip the intro and show him the content that is expected to be shown.
Is there some parameter, that I could catch in application(_:didFinishLaunchingWithOptions:) so I could say that it was launched thru the dynamic link?
The method application(_:continueUserActivity:userActivity:restorationHandler:) is called later, so the intro is already launched.
This case is difficult to test, because you have to have your app published on the AppStore.
You actually don't need to have the app published in the App Store for this to work — clicking a link, closing the App Store, and then installing an app build through Xcode (or any other beta distribution platform like TestFlight or Fabric) has exactly the same effect.
According to the Firebase docs, the method that is called for the first install is openURL (no, this makes no sense to me either). The continueUserActivity method is for Universal Links, and is only used if the app is already installed when a link is opened.
I am not aware of any way to detect when the app is opening for the first time after install from a 'deferred' link, but you could simply route directly to the shared content (skipping the intro) whenever a deep link is present. If a deep link is NOT present, show the regular intro.
Alternative Option
You could check out Branch.io (full disclosure: I'm on the Branch team). Amongst other things, Branch is a great, free drop-in replacement for Firebase Dynamic Links with a ton of additional functionality. Here is an example of all the parameters Branch returns immediately in didFinishLaunchingWithOptions:
{
"branch_view_enabled" = 0;
"browser_fingerprint_id" = "<null>";
data = "{
\"+is_first_session\":false,
\"+clicked_branch_link\":true,
\"+match_guaranteed\":true,
\"$canonical_identifier\":\"room/OrangeOak\",
\"$exp_date\":0,
\"$identity_id\":\"308073965526600507\",
\"$og_title\":\"Orange Oak\",
\"$one_time_use\":false,
\"$publicly_indexable\":1,
\"room_name\":\"Orange Oak\", // this is a custom param, of which you may have an unlimited number
\"~channel\":\"pasteboard\",
\"~creation_source\":3,
\"~feature\":\"sharing\",
\"~id\":\"319180030632948530\",
\"+click_timestamp\":1477336707,
\"~referring_link\":\"https://branchmaps.app.link/qTLPNAJ0Jx\"
}";
"device_fingerprint_id" = 308073965409112574;
"identity_id" = 308073965526600507;
link = "https://branchmaps.app.link/?%24identity_id=308073965526600507";
"session_id" = 319180164046538734;
}
You can read more about these parameters on the Branch documentation here.
Hmm... as far as I'm aware, there's not really anything you can catch in the application:(_:didFinishLaunchingWithOptions) phase that would let you know the app was being opened by a dynamic link. You're going to have to wait until the continueUserActivity call, as you mentioned.
That said, FIRDynamicLinks.dynamicLinks()?.handleUniversalLink returns a boolean value nearly instantly, so you should be able to take advantage of that to short-circuit your into animation without it being a bad user experience. The callback itself might not happen until several milliseconds later, depending on if it's a shortened dynamic link (which requires a network call) or an expanded one (which doesn't).

Facebook/Mobile deep-linking + app links

I'm confused. I think I've fundamentally misunderstood how to use Open Graph stories + deep-linking across my iOS/Web app. I'm hoping someone can help me clarify things. Here's what I have:
A web app set up that takes http://mywebapp.com/?video_id=XXXXXXXX
Properly configured meta tags for app-links
An iOS app with similar functionality that communicates with an API
Facebook sharing on the iOS app.
Here's what I expect:
See a link (ON MOBILE) in either the Facebook app or Safari, when I tap the link get the 'Install App' or 'Open in App' UX
I experimented with simply linking to 'http://mywebapp.com/?video_id=XXXXXXXX'. It doesn't work UNLESS I go to the object debugger (https://developers.facebook.com/tools/debug/og/object/) and 'Fetch New Scrape Information' for that video_id (i.e. it doesn't work dynamically, the page has to be scraped.) I also tried using Open Graph sharing with a contentURL and a combination of custom objects/actions/content/stories and at no stage did the Facebook app offer to open up the iOS app (again, unless I scraped the page in advance).
Have I misunderstood what is possible? I take it that if I scrape + link to http://www.mywebapp.com it'll work fine, but I want to have custom stories like:
'User X played video 'Y' using MyWebApp', but that kind of dynamic sharing WITH a concept of deep linking/app link/whatever seems impossible. Does anyone have any experience with this?

SoundCloud Widget External Control iOS issue

I have found a bug using the external controls for the html5 widget on iOS, i have tested with iphone and ipad. The controls inside the widget work ok. However on my clients site http://www.bushytunes.net and the widget api playground http://w.soundcloud.com/player/api_playground.html the external controls run an error.
Here is what the console from the widget playground prints:
SC.Widget.Events.PLAY {"loadedProgress":null,"currentPosition":0,"relativePosition":0}
SC.Widget.Events.PAUSE {"loadedProgress":null,"currentPosition":0,"relativePosition":0}
SC.Widget.Events.PLAY {"loadedProgress":null,"currentPosition":0,"relativePosition":0}
SC.Widget.Events.PLAY {"loadedProgress":null,"currentPosition":0,"relativePosition":0}
SC.Widget.Events.PLAY {"loadedProgress":null,"currentPosition":0,"relativePosition":0}
SC.Widget.Events.READY {}
Loading...
Thanks, James
TL;DR: iOS 6 should work with a limitation of a call to play to be init by user action, iOS5 and below probably won't get a fix.
We'll try to resolve this with some kind of a hack, but most probably this won't get a proper solution any time soon.
SoundCloud Widget is using HTML5 Audio to play sounds on iOS. There are two limitations on starting playback in iOS:
Playback must be started by user action (so within event handler)
The call to audio.play method has to be within synchronous call stack of that event handler.
This means, that this works:
document.querySelector('.play-button').addEventListener('click', function () {
audioController.play();
}, false);
But this doesn't:
document.querySelector('.play-button').addEventListener('click', function () {
setTimeout(function () {
audioController.play();
}, 500);
}, false);
Cross-domain communication between iframes is only possible in asynchronous manner. Our implementation is using postMessage DOM API, but even older techniques such as Fragment Identifier Messaging (FIM) that is using location.hash are asynchronous. This means we don't currently see a way of enabling playback through API for iOS5 and below (as there is also no Flash fallback).
However, there are also good news: iOS6 has dropped the limitation No2. This means that as long as the API call to play is called by user action, you'll be able to play sounds. Even though the communication between your parent window and widgets' iframe is still async. Unfortunately iOS hasn't dropped this limitation.
I hope this helps and I'll update this answer in case we find a proper workaround.
My suggestion would be to build your own custom player with a library like Audio5JS or SoundManager2 in case controlling playback on iOS is crucial for your app.
You can see vague description of what I am talking about on developer.apple.com resource.
I can't completely tell if #gryzzly is trying to say this, but the Widget API's external controls are completely broken on mobile. The answer does explain why -- you can't synchronously tell the iFrame to play the sound, but it is my understanding that proper iframe.contentWindow calls would be synchronous? I may be wrong.
Try directing your mobile phone to the widget API playground: https://w.soundcloud.com/player/api_playground.html
Even there it doesn't actually play unless you press the orange button.
Pretty irritating since there's no application to get around the streaming API limit either. There seems to be literally no way to get a site that may experience more than 15,000 requests/plays per day to work with SoundCloud on mobile. I just want continuous music playback.

Resources