I am attempting to set up two analytics trackers in my Angular App. One of my requirements is to set up a tracker for every user that logs in to the app that forwards page tracking and event data to a static tracker known at config time. However, the second tracker needs to be set during runtime once a user is logged in. It needs to send analytics data to a tracker that is associated with their account.
I am new to using google analytics and thought it would be as easy as pushing to the ga command queue to trackers but after reading the analytics developer literature it seems that I would have to explicitly send page track commands to both trackers.
So instead of re-inventing the wheel I looked at revolunet/angular-google-analytics hoping that it would solve my problem. However, it complains about not setting the tracker at run-time. I tried using
AnalyticsProvider.delayScriptTag(true);
then mutating the array
Analytics.configuration.accounts;
at runtime but it seems to produce no effect.
If anyone has had experience with this in the past please let me know, i'm looking for a clean Angular-ish solution besides putting a wrapper around the ga command queue unless that's my best bet.
Thanks!
A little late in the response but to those it may help I ended up creating an analyticsService that is responsible for setting up the dynamic tracker. In order for it to work I added the following to my app's config
AnalyticsProvider.delayScriptTag(true);
AnalyticsProvider.ignoreFirstPageLoad(true);
AnalyticsProvider.setPageEvent('$stateChangeSuccess');
This delayed the initialization of the auto tracking. Then I forked angular-google-analytics and added the following code
this._kickOffAutoTracking = function() {
// activates page tracking
if (trackRoutes) {
$rootScope.$on(pageEvent, function () {
that._trackPage();
});
}
};
Finally in my analyticsService I made my API request, got the user's tracker and added it as follows:
Analytics.setAccount([
{ tracker: DEFAULT_TRACKER, name: "defaultTracker", trackEvent: true },
{ tracker: user.analyticCode, name: "userTracker" }
])
Analytics.createAnalyticsScriptTag();
Analytics.kickOffAutoTracking();
It was a quick an dirty solution.
Related
We're not sure if this is the right place for us to obtain the answers of such. We've contacted the Firebase Support Team but did not get the answers that we want except a few links to the online documentation that we've mostly been through before. After further clarifying our requests, we've not been receiving any response from them for 5 days; therefore we might as well try our luck here.
1. How to create a Custom Dimension in GA4?
As we understand, GA4 are all events now, including the Hit in Universal Analytics (UA), but how can we map from our UA custom dimensions to the GA4 model as shown below?
When we tried to create the AccCode custom dimension in GA4, we have no idea what to enter under the Event parameter dropdown list as it also cannot be dropped down whatsoever:
May I know how can we proceed from here and what should we enter for the Event parameter value?
2. How to get Unique PageView (UPV) in Firebase GA4 API?
In UA or GA v3, this is how we get our Page View and Unique PageView:
return jwt.authorize()
.then((response) => {
return google.analytics('v3').data.ga.get({
'auth': jwt,
'ids': 'ga:' + gaConfig.ViewerID,
'start-date': validatedDateRange.strStartDate,
'end-date': validatedDateRange.strEndDate,
'metrics': 'ga:pageviews,ga:uniquepageviews',
"dimensions": gaConfig.AccCodeDimension,
'filters': ${gaConfig.PageUrlDimension}!#googleusercontent.com;${gaConfig.PageUrlDimension}!#blogspot.com${!accCode ? "" : ";" + gaConfig.AccCodeDimension + "==" + accCode}`,
'sort': `${gaConfig.AccCodeDimension},-ga:pageviews,-ga:uniquepageviews`
}).then((gaQuery) => {
// Do something here
});
Below is the sample code that we found from the Firebase GA4 documentation:
import firebase from "firebase/app";
import "firebase/analytics";
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
// Initialize Analytics and get a reference to the service
const analytics = firebase.analytics();
analytics.logEvent('select_content', {
content_type: 'image',
content_id: 'P12453',
items: [{ name: 'Kittens' }]
});
But the above sample code seems to be far from giving us an idea on how to achieve the same result as did in GA v3. It's more like logging of event data, potentially for our custom dimensions as what we did in the UA's tracking code. Examples for data pulling don't seem to be available in the documentation here. We need an equivalent example on how we can achieve the same result with Firebase GA4 API so that we can quickly migrate over to GA4 before July 2023.
We hope that someone here can help us to resolve the above two issues as quickly as possible because they involve changing the core engine of our app, which requires vast amount of development time and testing while the clock is ticking. Thank you so much in advance!
After so much of the studies and R&D, we realized that for what we're trying to achieve has nothing to do Firebase at all -- we can purely focus on GA and its latest API, which is still on Beta while some are on Alpha. But for the custom dimension creation, below is the answer:
Creating Custom Dimensions in GA4
As per the question described, the custom dimension creation process can be very confusing, especially to the UA users due to the change of data model and concepts. But what you need to know is that, you need to finalize your event parameters before mapping them over to the custom dimensions on GA console because the event parameter cannot be edited once the custom dimension is created on GA console:
So what you need to do is to extend your existing UA tracking code as shown below before creating your custom dimensions on GA console:
gtag('event','page_view', { // the page_view event is for web
"acc_code": "{{{AccCode}}}", // acc_code is your event parameter
"acc_name": "{{{AccName}}}", // This is another event parameter
"viewer_id": "{{{ViewerID}}}",
"viewer_title": "{{{ViewerTitle}}}",
"viewer_url": "{{{gaUrl}}}"
});
gtag('config', 'G-XXXXXXXX'); // This is your GA4 MEASUREMENT_ID
Data Query in GA4
For data query in GA4 that is equivalent to the given example in the question, please refer to the GA4 Data API here.
What about the Unique Pageview metric?
According to the GA documentation here, looks like Unique Pageview is no longer available in GA4:
I'm not sure if this is still subject to change, but you may need to write your own code, perhaps using sessionStorage or session cookies to track your own unique pageviews per user session for every page viewed.
We're using both GFC as our consent platform and client side PreBid along with Google DFP.
The implementation looks correct and most of the time we see the bids appearing correctly along with the consent tokens, however, on some occasions we get the following error message from prebid:
ERROR: CMP not found. Canceling auction as per consentManagement config. undefined.
We load both scripts asynchronously, but we do load Google's script first and then Prebid.js right after that.
We suspect that Google's implementation doesn't create the __tcfapi or __cmp objects immediately on the global scope, and that if those are not present, PreBid cancels the auction and doesn't fire the bids.
Did anyone else stumble upon this issue and can verify? Is there a way to prevent this from happening without delaying the page load or the ads? If not, is there a way to register an error handler on prebid?
We had the same problem. We use fundingchoices which is now integrated into Google AdManager.
Try
window.googlefc = window.googlefc || {};
window.googlefc.ccpa = window.googlefc.ccpa || {}
window.googlefc.callbackQueue = window.googlefc.callbackQueue || [];
// wait for consent
googlefc.callbackQueue.push({
'CONSENT_DATA_READY': () => {
// do prebidding
}
});
But it seems to be very slow as the Google Publisher Tag (gpt.js) must be loaded which then decides that a FundingChoice/CMP is needed which gets loaded and then after a while the consent is available.
We don't have it production because it is too slow. Does somebody knwo how to speed things up with fundingchoice aka AdManger-GDPR-Messages
I'm trying to implement enableSingleRequest() for Google Publisher Tags in a React application.
I have it set up the way google suggests:
this.googletag.cmd.push(() => {
if (this.props.enableSingleRequest) {
// Infinite scroll requires SRA
this.googletag.pubads().enableSingleRequest();
}
// add support for async loading
this.googletag.pubads().enableAsyncRendering();
// collapse div without ad
this.googletag.pubads().collapseEmptyDivs();
// load ad with slot refresh
this.googletag.pubads().disableInitialLoad();
// enable google publisher tag
this.googletag.enableServices();
});
I have 6 ads on one of the pages, and I'm still seeing 6 requests.
I'm also seeing multiple slots have the exact same ad, which is the problem that SRA is used to resolve.
I have a react adComponent that gets loaded in each slot.
Do I need to re-architect how individual adSlots are loaded?
Maybe using redux because it seems like the call to enableSingleRequest() should be made once per page and you should only call display() once so you'd include all the ads for display in that call.
Any help is appreciated.
How do you configure Single Request Architecture for Google Publisher Tags in a react application?
Thanks :)
Update:
I've found the clue but the implementation details are not clear.
This is from the google documentation regarding enableSingleRequest():
Create one SRA request with all ad slots to best serve guaranteed
roadblocks or competitive exclusions, instead of sending
SRA requests with one ad slot at a time.
So, now I"m wondering how do you achieve this in react - when the adSlot component only knows about the id of the google publisher tag where it is currently being rendered? I need to figure out some way to pass all the ids with one request on page load...
I provide SEO services to a customer of mine.
The customer website uses AngularJS as a single-page-application using ui-router to swipe between pages (views).
I having troubles with sending pageView event for each different page, I've asked him to follow the instructions in this link.
He tried both:
ga('set', {
page: '/new-page',
title: 'New Page'
});
and:
ga('set', 'page', '/new-page');
for each route (page) on the site.
When I check Google Analytics 'real time' dashboard I can see the pageView(s)
but it count as the home page in the reports data.
I've tried implement it as GTM as well and still nothing.
p.s the routes look a bit different then regular ui-router routes, it looks like that:
http://www.example.com/s#!/page_name
Any idea why and what should I do to fix it?
appreciate any help, thanks :)
First - reconfigure tracker
This code seems to be OK, if you use default tracker and namespace names. After sending first pageview, you reconfigure tracker values. Your solution is right, because it keeps values for e.g. events fired later on virtual page.
ga('set', {
page: '/new-page',
title: 'New Page'
});
Second - send pageview again
After reconfiguring tracker, you have to send pageview again.
You do not show a lot of your code, but I am missing sending pageview. I expect you need to use some Angular router's method.
ga('send', 'pageview');
GTM alternations
The same is for GTM. Here you need firing event on virtual pageview and some data passed into dataLayer to update trackers values by page and title parameters. You have to recofigure Custom fields in PageView Tag settings.
Better debugging
If you have this kind of probles, please, add HTTP log (or console log from analytics_debug.js or whatever where is full signal).
Live HTTP headers, Omnibug, Charles Web debugging proxy or any other similar analyzer will help you.
I coach a sports team and set up a website for it. I would like to add a button to an admin page which I can click to quickly send an email to everyone on the team. This email will say something like: "Today's schedule has changed, please visit the website for more info."
I am sure this could be achieved easier though a distribution list in outlook or something, but I want to use, and get a better understanding of, Google Apps Script.
I have a Google Spreadsheet with the email addresses and a simple script function which sends the email.
This works great when I click to run it inside the script editor, but is there a way to call this from an external website with a button and some JavaScript?
You need to create a Google UI object that you can embed in your site - you'll do this by creating a Script that you will deploy as a web app. (Refer to Google Apps Script - Web Apps.) That object will contain a button that will invoke your existing script function to send the email.
Publish your web app to execute as you. For your specific situation, you will also want to have access to the app limited to you. That will mean that the UI Blob you create will not function for the general public. This is very incomplete, but produces a blob with a single button that will trigger your script:
function doGet() {
var app = UiApp.createApplication();
var button = app.createButton('Send Schedule Change Email');
app.add(button);
var handler = app.createServerHandler('myClickHandler');
button.addClickHandler(handler);
return app;
}
function myClickHandler(e) {
var app = UiApp.getActiveApplication();
// Call your library function, e.g.
TeamSpreadsheet.sendScheduleChanged();
var label = app.createLabel('Message Sent')
.setId('statusLabel')
.setVisible(false);
label.setVisible(true);
app.close();
return app;
}
Your web app will need to have access to your existing script, which I assume is embedded in your spreadsheet. This is accomplished by first saving a version of your existing script (File - Manage Versions), then adding it as a library to your new web app script (Resources - Manage Libraries). Read more about libraries here. Since your web app will run as you, you can keep your spreadsheet private.
Caveats
The utility script in your library will need to open your spreadsheet in a way that will work from outside of the sheet; use SpreadsheetApp.openById(), rather than SpreadsheetApp.getActiveSpreadsheet(). Unfortunately, openById pukes when you use it to open the host spreadsheet, so you'll want something like this:
var ss = null;
try {
// This works for scripts running in the host spreadsheet
ss = SpreadsheetApp.getActiveSpreadsheet();
} catch(err) {
try {
// This works for web apps
ss = SpreadsheetApp.openById("SPREADSHEET ID");
} catch(err) {
Logger.log("Could not open source spreadsheet.");
// Well, then, not much sense carrying on, is there?
return;
}
}
SpreadsheetApp.setActiveSpreadsheet(ss);
...
In fact, watch for any reliance on calls to get info from "active" objects. You may need to do some gymnastics to get around them.
I've found debugging this type of arrangement to be painful, since the app-script debugger often reports "Server Errors" when you try to trace into a library routine.
I hope that helps gets you started!
As a complement to Mogsdad's answer (that was quite complete and interesting) I'd say that your case could be a bit simpler since you have already a working script.
Take your script and add a doGet() function like in Mogsdad example, define a handler on the button that will call your existing function you wrote to send mails, in this function replace the getActiveSpreadsheet() by SpreadsheetApp.OpenById("the ID of the SS") and the getActiveSheet() by OpenByName() and you're done with the modifications.
After that follow Mogsdad instructions : deploy the script as a webapp running as you and use the provided url to access it from a link on your site.
If you want not to take any risk, do all these changes on a copy of your original spreadsheet so you always keep a working model at hand.
If you want more accurate advice (or if you meet some difficulties) feel free to show your existing script to get some help with the modifications.
PS : please consider this as a simple comment, written in an answer for the comfort of formating
Just publish your script as web application and upon a button click, excecute:
window.open("https://script.google.com/macros/s/<id>/exec");
Don't know if this was possible a year ago.