Where is the Google Analytics pixel in my DOM? - javascript

How can I identify, using JavaScript that a Google Analytics pixel (or any pixel for that matter) has been sent, and contains URL parameters i'm looking for?
I thought, since it's a tracking pixel, i could look for it in the DOM, but it doesn't look like it's ever inserted.
Can someone think of a way to analyze the network request made by google using javascript (not a chrome extension)?
something like
document.whenGooglePixelIsSentDoReallyCoolStuff(function(requestUrl){
});

A few things:
1) The tracking beacons aren't always pixels. Sometimes they're XHR and sometimes they use navigator.sendBeacon depending on the situation and/or your tracker's transport setting, so if you're just looking for pixels you could be looking in the wrong place.
2) You don't need to add an image to the DOM to get it to send the request. Simply doing document.createElement('img').src = "path/to/image.gif" is sufficient.
3) You don't need to use a Chrome extension to debug Google Analytics, you can simply load the debug version of the script instead of the regular version.
4) If you really don't want to use the debug version of Google Analytics and want to track what is sent programmatically, you can override the sendHitTask and intercept hits before they're sent.
Update (7/21/2015)
You've changed how your question is worded, so I'll answer the new wording by saying you should follow the suggestion I give in #4 above. Here's some code that would work with your hypothetical whenGooglePixelIsSentDoReallyCoolStuff function:
document.whenGooglePixelIsSentDoReallyCoolStuff = function(callback) {
// Pass the `qa` queue method a function to get acess to the default
// tracker object created via `ga('create', 'UA-XXXX-Y', ...)`.
ga(function(tracker) {
// Grab a reference to the default `sendHitTask` function.
var originalSendHitTask = tracker.get('sendHitTask');
// Override the `sendHitTask` to call the passed callback.
tracker.set('sendHitTask', function(model) {
// When the `sendHitTask` runs, get the hit payload,
// which is formatted as a URL query string.
var requestUrl = model.get('hitPayload')
// Invoke the callback passed to `whenGooglePixelIsSentDoReallyCoolStuff`
// If the callback returns `false`, don't send the hit. This allows you
// to programmatically do something else based on the contents of the
// request URL.
if (callback(requestUrl)) {
originalSendHitTask(model);
}
});
});
};
Note that you'd have to run this function after creating your tracker, but prior to sending your first hit. In other words, you'd have to run it between the following two lines of code:
ga('create', 'UA-XXXX-Y', 'auto');
ga('send', 'pageview');

Related

How do I log the body of js network request with a chrome extension? [duplicate]

I'm aware that chrome.webRequest.onBeforeRequest allows a request to be intercepted, analyzed and blocked, but it only allows access to the request headers, and not the request body (as far as i know).
Sample use case: think intercepting form values.
It seems there is a API change proposal here suggesting exactly this.
Is there another way this could be accomplished?
Thanks.
This functionality has been added to the API now, see the documentation.
In order to access the body you need to do the following:
chrome.webRequest.onBeforeRequest.addListener(
function(details)
{
console.log(details.requestBody);
},
{urls: ["https://myurlhere.com/*"]},
['requestBody']
);
Here is what I did
I used the requestBody to get the post requests body
I used a decoder the parse the body into a string
Here is an example
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
if(details.method == "POST")
// Use this to decode the body of your post
var postedString = decodeURIComponent(String.fromCharCode.apply(null,
new Uint8Array(details.requestBody.raw[0].bytes)));
console.log(postedString)
},
{urls: ["<all_urls>"]},
["blocking", "requestBody"]
);
While you may not be able to intercept, you can use standard AJAX approach to duct-tape it. Instead of making the href request see if you can make an asynchronous call and save it to an HTML object that isn't presented. Then scrape/read/parse/whatever your body criteria is, and if it passes, push that body object back up to the current window/page.
Storing the content in a suppressed element and then using that same element for content would allow you to avoid making duplicate calls. The downside is that you will get the full content for stuff you won't end up using. That may or may not be a bandwidth/speed performance issue.

Consuming chunked data asyncrhonously in javascript

I have a (GET) endpoint that sends data in chunks (Transfer-Encoding: chunked). The data is JSON encoded and sent line by line.
Is there a way to consume the data sent by this endpoint in an asynchronous manner in JavaScript (or using some JavaScript library)?
To be clear, I know how to perform an asynchronous GET, but I would like to have the GET request not waiting for the whole data to be transfered, but instead read the data line by line as it arrives. For instance, when doing:
curl http://localhost:8081/numbers
The lines below are shown one by one as they become available (the example server I made is waiting a second between sending a line and the second).
{"age":1,"name":"John"}
{"age":2,"name":"John"}
{"age":3,"name":"John"}
{"age":4,"name":"John"}
I would like to reproduce the same behavior curl exhibits, but in the browser. I don't want is leave the user wait till all the data becomes available in order to show anything.
Thanks to Dan and Redu I was able to put together an example that consumes data incrementally, using the Fetch API . The caveat is that this will not work on Internet Explorer, and it has to be enabled by the user in Firefox:
/** This works on Edge, Chrome, and Firefox (from version 57). To use this example
navigate to about:config and change
- dom.streams.enabled preference to true
- javascript.options.streams to true
See https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream
*/
fetch('http://localhost:8081/numbers').then(function(response) {
console.log(response);
const reader = response.body.getReader();
function go() {
reader.read().then(function(result) {
if (!result.done) {
var num = JSON.parse(
new TextDecoder("utf-8").decode(result.value)
);
console.log(
"Got number " + num.intVal
);
go ();
}
})
}
go ();
})
The full example (with the server) is available at my sandbox. I find it illustrative of the limitations of XMLHttpRequest to compare this version with the this one, which does not use the fetch API.

connecting javascript to a Web API

I am new to the web development world and I would like to be able to connect an HTML page to a web api through . and I was really not successful in this.
I followed this tutorial to be able to make this connection : http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api
All I need is to send some inputs from an HTML page to a web api that takes these parameters and returns an object
I am using this code
$.getJSON("api/GeneratorController/setparameters/"+firstparameter+"/"+secondparameter+"/"+thirdparameter+"/"+fourthparameter+"/"+fifthparameter+"/"+sixthparameter,
function (data) {
alert(data); //never comes here
}).fail(function (jqXHR, textStatus, err) {
alert("All checks are correct, image was not generated. jqXHR = " + jqXHR.valueOf() + " textStatus=" + textStatus + " Error" + err);
});
it always goes into the fail portion , I attached the alert message that comes out of it
Any Reason why it is doing this ?
#smartmeta (I changed the typo , thanks) I followed your advice and here is the output of the alert (as expected , values that I have inserted are displayed):
Your url needs to start with your domain, not 'api/generatorcontroller/...'. If you are developing locally, something like http://localhost:[port]/api/generatorController/....
Also, webApi maps to url verbs, (get, post, put, delete..), not functions like setparameters, unless you have a [name=setparameters] above your get() function.
Also, I am pretty sure you don't have a route setup to handle the url with all those parameters. What you want to look at, as it seems your using jQuery, is jQuery.get documentation. The second example near the bottom shows where to place parameters. WebAPI will check for them in the body if they are not in the query string. so it would end up looking like:
$.getJSON("http://"+window.location.host+"/api/GeneratorController/setparameters", {parameter1: parameter1, parameter2:parameter2 ...});
Well, the first thing to check is to make sure that your server-side function is returning the values you expect. You can do this with Chrome's developer tools or with the Firebug Firefox extension, and I think IE10 has something equivalent, too. Go to the "net" tab, find the request corresponding to your API call, and take a look at what the server responded with.
Please add the line
alert("api/GeneratorController/setparameters/"+firstparemeter+"/"+secondparameter+"/"+thirdparameter+"/"+fourthparameter+"/"+fifthparameter+"/"+sixthparameter)
Then call your script and take the output of the alert into a browser. Then check if your application Handels that route.
By the way I think you have a typo. I guess it should be firstparameter.
I assume you would like to do
"api/GeneratorController?foo=Bar
But when you are new to this, I would suggest that you first try the example like it is. And After that you can start changing setails.
So I found what was the problem with my code
Two things :
1- I shouldn't use the word "Controller" when I call my API ,it should be api/Generator/...
2- the function name needs to start with "get" and not "set" since it "gets" the return value from the api
Thanks everyone!

How to Call Google Apps Script from Web Page

Have searched high and low for this. I have a web page of basic HTML/CSS/JS. I want users to be able to visit the page and upon opening page, a call is made to a google script I made which takes information from a spreadsheet and displays some of it on the page. I am hoping I don't have to do any fancy set up like in Google's tutorials because none of them were helpful to me.
My Webpage ----> Google Script ----> Google Spreadsheet
My Webpage <---- Google Script <---- Google Spreadsheet
Users should be able to select an item shown on the webpage (item populated from spreadsheet) and click a button which will allow users to enter a new page with a URL derived from the selected item.
This is essentially a chat room program where the chat rooms are stored on a spreadsheet. I want users to be able to create a new chat room as well which should update the google spreadsheet.
Look into using the GET parameters. https://stackoverflow.com/a/14736926/2048063.
Here's a previous question on the topic.
You can access the parameters passed by GET in your doGet(e) function using e.parameter. If you call http://script.google......./exec?method=doSomething, then
function doGet(e) {
Logger.log(e.parameter.method);
}
doSomething will be written to the log, in this case.
Returning data from the script can be done using the ContentService, which allows you to serve JSON (I recommend). JSON is easiest (in my opinion) to make on the GAS end, as well as use on the client end.
The initial "populate list" call would look something like this. I will write it in jQuery because I feel that is very clean.
var SCRIPT_URL = "http://script.google.com/[....PUT YOUR SCRIPT URL HERE....]/exec";
$(document).ready(function() {
$.getJSON(SCRIPT_URL+"?callback=?",
{method:"populate_list"},
function (data) {
alert(JSON.stringify(data));
});
});
And the corresponding GAS that produces this.
function doGet(e) {
if (e.parameter.method=="populate_list") {
var v = {cat:true,dog:false,meow:[1,2,3,4,5,6,4]}; //could be any value that you want to return
return ContentService.createTextOutput(e.parameter.callback + "(" + JSON.stringify(v) + ")")
.setMimeType(ContentService.MimeType.JAVASCRIPT);
}
}
This method is called JSONP, and it is supported by jQuery. jQuery recognizes it when you put the ?callback=? after your URL. It wraps your output in a callback function, which allows that function to be run on your site with the data as an argument. In this case, the callback function is the one defined in the line that reads function (data) {.

Using PUT/POST/DELETE with JSONP and jQuery

I am working on creating a RESTful API that supports cross-domain requests, JSON/JSONP support, and the main HTTP method (PUT/GET/POST/DELETE). Now while will be easy to accessing this API through server side code , it would nice to exposed it to javascript. From what I can tell, when doing a JSONP requests with jQuery, it only supports the GET method. Is there a way to do a JSONP request using POST/PUT/DELETE?
Ideally I would like a way to do this from within jQuery (through a plugin if the core does not support this), but I will take a plain javascript solution too. Any links to working code or how to code it would be helpful, thanks.
Actually - there is a way to support POST requests.
And there is no need in a PROXI server - just a small utility HTML page that is described bellow.
Here's how you get Effectively a POST cross-domain call, including attached files and multi-part and all :)
Here first are the steps in understanding the idea, after that - find an implementation sample.
How JSONP of jQuery is implemented, and why doesn't it support POST requests?
While the traditional JSONP is implemented by creating a script element and appending it into the DOM - what results inforcing the browser to fire an HTTP request to retrieve the source for the tag, and then execute it as JavaScript, the HTTP request that the browser fires is simple GET.
What is not limited to GET requests?
A FORM. Submit the FORM while specifing action the cross-domain server.
A FORM tag can be created completely using a script, populated with all fields using script, set all necessary attributes, injected into the DOM, and then submitted - all using script.
But how can we submit a FORM without refreshing the page?
We specify the target the form to an IFRAME in the same page.
An IFRAME can also be created, set, named and injected to the DOM using script.
But How can we hide this work from the user?
We'll contain both FORM and IFRAME in a hidden DIV using style="display:none"
(and here's the most complicated part of the technique, be patient)
But IFRAME from another domain cannot call a callback on it's top-level document. How to overcome that?
Indeed , if a response from FORM submit is a page from another domain, any script communication between the top-level page and the page in the IFRAME results in "access denied". So the server cannot callback using a script. What can the server can do? redirect. The server may redirect to any page - including pages in the same domain as the top-level document - pages that can invoke the callback for us.
How can a server redirect?
two ways:
Using client side script like <Script>location.href = 'some-url'</script>
Using HTTP-Header. See: http://www.webconfs.com/how-to-redirect-a-webpage.php
So I end up with another page? How does it help me?
This is a simple utility page that will be used from all cross-domain calls. Actually, this page is in-fact a kind of a proxi, but it is not a server, but a simple and static HTML page, that anybody with notepad and a browser can use.
All this page has to do is invoke the callback on the top-level document, with the response-data from the server. Client-Side scripting has access to all URL parts, and the server can put it's response there encoded as part of it, as well as the name of the callback that has to be invoked. Means - this page can be a static and HTML page, and does not have to be a dynamic server-side page :)
This utility page will take the information from the URL it runs in - specifically in my implementation bellow - the Query-String parameters (or you can write your own implementation using anchor-ID - i.e the part of a url right to the "#" sign). And since this page is static - it can be even allowed to be cached :)
Won't adding for every POST request a DIV, a SCRIPT and an IFRAME eventually leak memory?
If you leave it in the page - it will. If you clean after you - it will not. All we have to do is give an ID to the DIV that we can use to celan-up the DIV and the FORM and IFRAME inside it whenever the response arrives from the server, or times out.
What do we get?
Effectively a POST cross-domain call, including attached files and multi-part and all :)
What are the limits?
The server response is limited to whatever fits into a redirection.
The server must ALWAYS return a REDIRECT to a POST requests. That include 404 and 500 errors.
Alternatively - create a timeout on the client just before firing the request, so you'll have a chance to detect requests that have not returned.
not everybody can understand all this and all the stages involved. it's a kind of an infrastructure level work, but once you get it running - it rocks :)
Can I use it for PUT and DELETE calls?
FORM tag does not PUT and DELETE.
But that's better then nothing :)
Ok, got the concept. How is it done technically?
What I do is:
I create the DIV, style it as invisible, and append it to the DOM. I also give it an ID that I can clean it up from the DOM after the server response has arrived (the same way JQuery cleans it's JSONP SCRIPT tasgs - but the DIV).
Then I compose a string that contains both IFRAME and FORM - with all attributes, properties and input fields, and inject it into the invisible DIV. it is important to inject this string into the DIV only AFTER the div is in the DOM. If not - it will not work on all browsers.
After that - I obtain a reference to the FORM and submit it.
Just remember one line before that - to set a Timeout callback in case the server does not respond, or responds in a wrong way.
The callback function contains the clean-up code. It is also called by timer in case of a response-timeout (and cleans it's timeout-timer when a server response arrives).
Show me the code!
The code snippet bellow is totally "neutral" on "pure" javascript, and declares whatever utility it needs. Just for simplification of explaining the idea - it all runs on the global scope, however it should be a little more sophisticated...
Organize it in functions as you may and parameterize what you need - but make sure that all parts that need to see each other run on the same scope :)
For this example - assume the client runs on http://samedomain.com and the server runs on http://crossdomain.com.
The script code on the top-level document
//declare the Async-call callback function on the global scope
function myAsyncJSONPCallback(data){
//clean up
var e = document.getElementById(id);
if (e) e.parentNode.removeChild(e);
clearTimeout(timeout);
if (data && data.error){
//handle errors & TIMEOUTS
//...
return;
}
//use data
//...
}
var serverUrl = "http://crossdomain.com/server/page"
, params = { param1 : "value of param 1" //I assume this value to be passed
, param2 : "value of param 2" //here I just declare it...
, callback: "myAsyncJSONPCallback"
}
, clientUtilityUrl = "http://samedomain.com/utils/postResponse.html"
, id = "some-unique-id"// unique Request ID. You can generate it your own way
, div = document.createElement("DIV") //this is where the actual work start!
, HTML = [ "<IFRAME name='ifr_",id,"'></IFRAME>"
, "<form target='ifr_",id,"' method='POST' action='",serverUrl
, "' id='frm_",id,"' enctype='multipart/form-data'>"
]
, each, pval, timeout;
//augment utility func to make the array a "StringBuffer" - see usage bellow
HTML.add = function(){
for (var i =0; i < arguments.length; i++)
this[this.length] = arguments[i];
}
//add rurl to the params object - part of infrastructure work
params.rurl = clientUtilityUrl //ABSOLUTE URL to the utility page must be on
//the SAME DOMAIN as page that makes the request
//add all params to composed string of FORM and IFRAME inside the FORM tag
for(each in params){
pval = params[each].toString().replace(/\"/g,""");//assure: that " mark will not break
HTML.add("<input name='",each,"' value='",pval,"'/>"); // the composed string
}
//close FORM tag in composed string and put all parts together
HTML.add("</form>");
HTML = HTML.join(""); //Now the composed HTML string ready :)
//prepare the DIV
div.id = id; // this ID is used to clean-up once the response has come, or timeout is detected
div.style.display = "none"; //assure the DIV will not influence UI
//TRICKY: append the DIV to the DOM and *ONLY THEN* inject the HTML in it
// for some reason it works in all browsers only this way. Injecting the DIV as part
// of a composed string did not always work for me
document.body.appendChild(div);
div.innerHTML = HTML;
//TRICKY: note that myAsyncJSONPCallback must see the 'timeout' variable
timeout = setTimeout("myAsyncJSONPCallback({error:'TIMEOUT'})",4000);
document.getElementById("frm_"+id+).submit();
The server on the cross-domain
The response from the server is expected to be a REDIRECTION, either by HTTP-Header or by writing a SCRIPT tag. (redirection is better, SCRIPT tag is easier to debug with JS breakpoints).
Here's the example of the header, assuming the rurl value from above
Location: http://samedomain.com/HTML/page?callback=myAsyncJSONPCallback&data=whatever_the_server_has_to_return
Note that
the value of the data argument can be a JavaScript Object-Literal or JSON expression, however it better be url-encoded.
the length of the server response is limited to the length of a URL a browser can process.
Also - in my system the server has a default value for the rurl so that this parameter is optional. But you can do that only if your client-application and server-application are coupled.
APIs to emit redirection header:
http://www.webconfs.com/how-to-redirect-a-webpage.php
Alternatively, you can have the server write as a response the following:
<script>
location.href="http://samedomain.com/HTML/page?callback=myAsyncJSONPCallback&data=whatever_the_server_has_to_return"
</script>
But HTTP-Headers would be considered more clean ;)
The utility page on the same domain as the top-level document
I use the same utility page as rurl for all my post requests: all it does is take the name of the callback and the parameters from the Query-String using client side code, and call it on the parent document. It can do it ONLY when this page runs in the EXACT same domain as the page that fired the request! Important: Unlike cookies - subdomains do not count!! It has to he the exact same domain.
It's also make it more efficient if this utility page contains no references to other resources -including JS libraries. So this page is plain JavaScript. But you can implement it however you like.
Here's the responder page that I use, who's URL is found in the rurl of the POST request (in the example: http://samedomain.com/utils/postResponse.html )
<html><head>
<script type="text/javascript">
//parse and organize all QS parameters in a more comfortable way
var params = {};
if (location.search.length > 1) {
var i, arr = location.search.substr(1).split("&");
for (i = 0; i < arr.length; i++) {
arr[i] = arr[i].split("=");
params[arr[i][0]] = unescape(arr[i][1]);
}
}
//support server answer as JavaScript Object-Literals or JSON:
// evaluate the data expression
try {
eval("params.data = " + params.data);
} catch (e) {
params.data = {error: "server response failed with evaluation error: " + e.message
,data : params.data
}
}
//invoke the callback on the parent
try{
window.parent[ params.callback ](params.data || "no-data-returned");
}catch(e){
//if something went wrong - at least let's learn about it in the
// console (in addition to the timeout)
throw "Problem in passing POST response to host page: \n\n" + e.message;
}
</script>
</head><body></body></html>
It's not much automation and 'ready-made' library like jQuery and involes some 'manual' work - but it has the charm :)
If you're a keen fan of ready-made libraries - you can also check on Dojo Toolkit that when last I checked (about a year ago) - had their own implementation for the same mechanism.
http://dojotoolkit.org/
Good luck buddy, I hope it helps...
Is there a way to do a JSONP request using POST/PUT/DELETE?
No there isn't.
No. Consider what JSONP is: an injection of a new <script> tag in the document. The browser performs a GET request to pull the script pointed to by the src attribute. There's no way to specify any other HTTP verb when doing this.
Rather than banging our heads with JSONP method, that actually won't
support POST method by default, we can go for CORS .That will provide no big changes in the conventional way of programming. By simple Jquery Ajax call we can go with cross domains.
In CORS method, you have to add headers in server side scripting file, or in the server itself(in remote domain), for enabling this access. This is much reliable, since we can prevent/restrict the domains making unwanted calls.
It can be found in detail in wikipedia page.

Categories