I want to track on google analytics the 404 errors. Each time there is a 404 a specific part of my page has "404" string as content. So, I create a Universal analytics tag.
Then I create a custom javascript macro
function() {
var viewcontainer = document.getElementsByClassName("view-container");
var content = viewcontainer[0].childNodes[3].innerHTML;
var error404 = parseInt(content);
//if there is an error page it returns 404, else it returns NaN
return error404;
}
The macro reads the contents of the part of my page on which the 404 should appear and returns it. If it is an error it will return 404 otherwise it will return some other content.
Then I create a rule to fire the tag each time the macro is equals to 404
I create the version of google tags and publish it. Then by adding some random string on my url I can trigger a 404 error page. But on the google analytics nothing is tracked. Any idea what I am doing wrong? Is this the right way of using custom macros? Is there any problem on my macro or is something that I forget to do?
Add an additional condition to your rule, like {{event}} equals gtm.dom.
Related
Background
To pass a client_id from one domain to another, Google supports adding a "linker" parameter to outgoing Links that are part of the cross-domain tracking setup. This linker parameter contains the client_id, session_id (I believe, information about Google Ads, e.g. gclid) and a basic fingerprint + timestamp. On the receiving domain, if the browser fingerprint matches and the timestamp is not too far in the past, the passed client_id and session_id are stored in a first party cookie on the 2nd domain and consequently used.
analytics.js / GA-UA
With analytics.js (GA-UA) you could easily do the following, to decorate URLs manually:
function decorateUrl(urlString) {
var ga = window[window['GoogleAnalyticsObject']];
var tracker;
if (ga && typeof ga.getAll === 'function') {
tracker = ga.getAll()[0]; // Uses the first tracker created on the page
urlString = (new window.gaplugins.Linker(tracker)).decorate(urlString);
}
return urlString;
}
Yet, when only gtag is loaded, window.ga and window.gaplugins are not defined. As far as I see, there is currently no documented way to manually generate links with the linker parameter with gtag.
In Google's documentation, they suggest setting up the linker manually. (https://support.google.com/analytics/answer/10071811?hl=en#zippy=%2Cmanual-setup)
But this has several disadvantages, e.g. I have to create a custom "fingerprint" logic (so that decorated URLs are not shared) and e.g. Google Ads information is not included.
Either way, I would like to use the internal gtag logic to decorate URLs.
"Hacky" Workaround Solution
gtag automatically decorates a tags (as soon as they're clicked) that lead to a cross-domain-tracking domain specified in the GA4 data stream settings (e.g. "test.com"), but I specifically need to decorate URLs manually (i.e. without immediately redirecting to them).
I thought about doing the following:
Create a dummy, hidden a tag with the URL to decorate
Prevent redirection with onclick='event.preventDefault();'
Simulate click on hidden element so that gtag automatically adds the linker url parameter to the href attribute
Extract new href attribute
Remove hidden element
function decorateUrlGtag(urlString) {
var tempAnchorEl = document.createElement("a");
tempAnchorEl.setAttribute("type", "hidden");
tempAnchorEl.setAttribute("href", urlString);
tempAnchorEl.setAttribute("onclick", "event.preventDefault(); return false");
document.body.appendChild(tempAnchorEl);
tempAnchorEl.click();
var urlWithLinker = tempAnchorEl.href;
tempAnchorEl.remove();
return urlWithLinker;
}
This also does not work, because gtag does not seem to register the tempAnchorEl.click(); call. If I click the link manually, the URL is decorated - as expected.
Suggested Solutions
The solutions outlined here (Google Analytics gtag.js Manually adding the linker cross-domain parameter to URLs) also do not work for me:
Answer: Even after gtag is initiated, I do not see a global ga element
Answer: Same problem (no ga defined)
Do you (1) know if there is a way to generate the linker parameter manually with gtag that I have overlooked, (2) know how to make my "hacky" solution work or (3) have another possible solution?
I haven't grokked this solution, and I am not sure it answers your question directly, but Simo does give an outline of how to configure GA4 cross domain tracking here:
https://www.simoahava.com/gtm-tips/cross-domain-tracking-google-analytics-4/#how-to-configure-cross-domain-tracking-manually
He breaks the problem down into steps but does not go into great detail. He provides one code snippet:
"...you could also load the URL parameter values directly into the GA4 configuration with something like:
gtag('config', 'G-12345', {
// Namespace roll-up trackers
cookie_prefix: 'roll-up',
// Pull in the Client ID from the URL
client_id: (new URLSearchParams(document.location.search)).get('client_id'),
// Pull in the Session ID from the URL
session_id: (new URLSearchParams(document.location.search)).get('session_id')
});
"
Hope that helps!
I'm crawling website secured with Cloudflare and sometimes getting an error due to redirection to page with ReCapcha, the page cannot be even loaded due to some javascript error. The code is failing on #getPage method and i have no idea why.
Here is the code works fine for normal pages, but fails on confirmation page:
final WebClient webClient = new WebClient(BrowserVersion.CHROME);
webClient.getOptions().setJavaScriptEnabled(true);
final HtmlPage page = webClient.getPage("https://mydummy.site");
webClient.waitForBackgroundJavaScript(10000);
int waitForBackgroundJavaScript = webClient.waitForBackgroundJavaScript(200);
int loopCount = 0;
while (waitForBackgroundJavaScript > 0 && loopCount < 2) {
++loopCount;
waitForBackgroundJavaScript = webClient.waitForBackgroundJavaScript(200);
if (waitForBackgroundJavaScript == 0) {
break;
}
}
Logs:
java.lang.RuntimeException: com.gargoylesoftware.htmlunit.ScriptException: Wrapped com.gargoylesoftware.htmlunit.ScriptException: Wrapped com.gargoylesoftware.htmlunit.ScriptException: TypeError: Cannot find function start in object [object MessagePort]. (https://www.gstatic.com/recaptcha/api2/v1536705955372/recaptcha__en.js#249) (https://www.gstatic.com/recaptcha/api2/v1536705955372/recaptcha__en.js#253)
at com.gargoylesoftware.htmlunit.html.HtmlPage.initialize(HtmlPage.java:305)
at com.gargoylesoftware.htmlunit.WebClient.loadWebResponseInto(WebClient.java:539)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:399)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:316)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:467)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:449)
at Main.htmlUnit(Main.java:156)
at Main.main(Main.java:43)
Caused by: com.gargoylesoftware.htmlunit.ScriptException: Wrapped com.gargoylesoftware.htmlunit.ScriptException: Wrapped com.gargoylesoftware.htmlunit.ScriptException: TypeError: Cannot find function start in object [object MessagePort]. (https://www.gstatic.com/recaptcha/api2/v1536705955372/recaptcha__en.js#249) (https://www.gstatic.com/recaptcha/api2/v1536705955372/recaptcha__en.js#253)
at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine$HtmlUnitContextAction.run(JavaScriptEngine.java:892)
at net.sourceforge.htmlunit.corejs.javascript.Context.call(Context.java:616)
at net.sourceforge.htmlunit.corejs.javascript.ContextFactory.call(ContextFactory.java:532)
at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.execute(JavaScriptEngine.java:772)
at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.execute(JavaScriptEngine.java:748)
at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.execute(JavaScriptEngine.java:104)
at com.gargoylesoftware.htmlunit.html.HtmlPage.loadExternalJavaScriptFile(HtmlPage.java:992)
at com.gargoylesoftware.htmlunit.html.HtmlScript.executeScriptIfNeeded(HtmlScript.java:371)
at com.gargoylesoftware.htmlunit.html.HtmlScript$2.execute(HtmlScript.java:246)
at com.gargoylesoftware.htmlunit.html.HtmlPage.initialize(HtmlPage.java:298)
We have been struggling with this issue as well. Our test suite ran perfectly until late 2018 when this issue broke all of our logins. I believe Google has put this in deliberately to break automated attempts to break captchas, because solving one part of this seems to only lead to another problem. Both loading the page and submitting the page causes issues, even if you tell HtmlUnitDriver to ignore all JavaScript errors.
I have tried several options at this point. If you use the Google specified test site key, then the errors go away. So if you have full server-side control of how that site key is generated, you are OK. Remember to ensure that the test site key shows up again on validation errors and all similar use cases, otherwise you will get that error.
(Unfortunately for us, our login page is plain JSP and so implementing this is a headache unless we want to change the URL everywhere. Still debating what to do, for right now we do have a workable if ugly solution that involves some conditional logic on the page and catching JavaScript exceptions at other points in the test code.)
I am trying to combine Github Pages with Google Apps Script so I can have Server Side Scripting with Github Pages. I try to connect to the Google Script web app using:
<script src="https://script.google.com/macros/s/NO_LINK_FOR_YOU/dev">
</script>
(I need that /dev there, google script says nothing was returned when I don't use it.)
That is supposed to (and does) return:
return ContentService.createTextOutput("window.onload = function(){document.getElementById(\"request\").innerHTML = \"Generated: " + generateRandomNumber(10, 42) + "\";}");
Which outputs this:
window.onload = function(){document.getElementById("request").innerHTML = "Generated: 28";}
(Of course, it would not always be 28.)
When I load this into the browser, it does nothing. I looked in inspect element and it says that it's returning the code 302 (Temporarily Moved). This is usually used for redirects, and content service always makes the browser redirect "for security reasons", so this is expected.
But how can I get the browser to follow that redirect and get the script from there? Can I even do that?
In this case, a mimetype error occurs, since mimetype is not set. So please add setMimeType() as follows.
return ContentService
.createTextOutput("window.onload = function(){document.getElementById(\"request\").innerHTML = \"Generated: " + generateRandomNumber(10, 42) + "\";}")
.setMimeType(ContentService.MimeType.JAVASCRIPT);
Follow the following steps.
Steps 1:
Go to google.
Open the javascript console.
Enter the command: document.all.q.value = "hello"
As expected the element with a name of "q" (the search field) is set to "hello").
Steps 2:
Go to google.
In the address bar type javascript: document.all.q.value = "hello!"
Press Enter
If your browser is either Internet Explorer, or Google Chrome, the javascript will have replaced the google website with an entirely blank page, with the exception of the word "Hello".
Finally
Now that you've bugged out your browser, go back to Google.com and repeat Steps 1. You should receive an error message "Uncaught ReferenceError: document is not defined (...) VM83:1
Question:
Am I doing something wrong? And is there another method which works, while still using the address bar for JS input?
The purpose of a javascript: scheme URL is to generate a new page using JavaScript. Modifying the existing page with it is something of a hack.
document.all.q.value = "hello!"; evalues as "hello!", so when you visit that URL, a new HTML document consisting solely of the text hello! is generated and loaded in place of the existing page.
To avoid this: Make sure the JS does not return a string. You can do this by using void.
javascript:void(document.all.q.value = "hello!");
When messing around with javascript: in the adressbar some (if not the most) browsers handle it as a new page, so you have to add a window.history.back(); at the end
javascript: document.all.q.value = "hello!"; window.history.back();
It seems it's fairly common practice to grab the contents of a Google-calendar embed code, and add a stylesheet into it (either manually or through something like a PHP script) and display a custom-styled public calendar.
The odd thing is, I noticed if you click the print button at the top, or the "Google Calendar" in the lower right, it goes to localhost or whatever domain the page is - not the Google calendar.
If you try to trace the "gcal$func$[3]();" onclick through the Chrome devtools, or through Firefox with gcal$func$[3].toSource(); it will not find it or say
"function () {
[native code]
}"
So where is this function coming from, and how can you tweak this to make it open in a new window with the Google url, not the current domain (404)?
According to the Google Calendar embed JS code, the function points to the following code
window.open(Pf(this.c.i.Nb + "/render", "cid", b))
this.c.i.Nb represents the base URL, which is by default the domain where the script runs (in your case that's your domain). However, it's intended to be google.com domain and fortunately, it's very easy to change that. baseURL is one of the parameters in the initialization script (declared in the page you're grabbing) and you just need to configure that to https://www.google.com.
If you use PHP, your code might look like this.
$page = new DOMDocument("1.0", "utf-8");
// grab the Google Calendar code
$page->loadHTMLfile("https://www.google.com/calendar/embed?src=yourcalendar%40gmail.com");
// set up the baseUrl and print the grabbed page
echo str_replace('"baseUrl":"/"', '"baseUrl":"https://www.google.com/"', $page->saveHTML());
Now all the links should work correctly.