Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome extension adding external javascript to current page's html

I am adding some external JavaScript to the end of the page via my chrome extension. The external JavaScript then tries to post some data back to the server, however that is not taking place.

The JavaScript wants to get the url of the current page and the referrer and post it back to the server.

Can anyone please advice me what is wrong here and how can I if not possible this way can I post data from the current page back to the server.

manifest.json

{   "name": "Website Safety",   "version": "1.0",   "manifest_version": 2,   "description": "The Website Safety Extension.",   "browser_action": {     "name": "View the website information for ",     "default_icon": "icon.png",     "default_popup": "popup.html"   },   "permissions": [     "tabs", "http://*/*", "https://*/*"   ],   "background": {   //  "scripts": ["refresh.js"]     "page": "background.html"   },   "content_security_policy": "script-src 'self' https://ssl.google-analytics.com; object-src 'self'",   //"background_page": "background.html"    "content_scripts": [     {       "matches": ["<all_urls>"],       "js": ["contentScript.js"]     }   ] } 

for now contentScript.js

var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-31046309-1']); _gaq.push(['_setAllowLinker', true]); _gaq.push(['_trackPageview']); (function() { var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; //ga.src = 'https://ssl.google-analytics.com/ga.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })();  var _Hasync= _Hasync|| []; _Hasync.push(['Histats.start', '1,1342541,4,0,0,0,00000000']); _Hasync.push(['Histats.fasi', '1']); _Hasync.push(['Histats.track_hits', '']); (function() { var hs = document.createElement('script'); hs.type = 'text/javascript'; hs.async = true; hs.src = ('http://s10.histats.com/js15_as.js'); (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(hs); })(); 
like image 238
Vish Avatar asked Apr 23 '12 18:04

Vish


People also ask

How do I include an external JavaScript file in HTML?

To include an external JavaScript file, we can use the script tag with the attribute src . You've already used the src attribute when using images. The value for the src attribute should be the path to your JavaScript file. This script tag should be included between the <head> tags in your HTML document.

What will be the file extension for external JavaScript in HTML?

External JavaScript JavaScript files have the file extension .js.

How do you write externally in JavaScript?

Create external JavaScript file with the extension . js. After creating, add it to the HTML file in the script tag. The src attribute is used to include that external JavaScript file.


2 Answers

Content scripts do not run in the scope of the page (see also), they run in a context between your extension and the web page.

Since the trackers are of the type "Injected script", these fully run in the context of the web page. But the _gaq and Hasync variables don't. As a result, the track scripts cannot read the configuration variables.

There are two (three) ways to fix it.

  1. Inject your code (as posted in the question) using this method. Using this method for your purpose is discouraged, because your script overwrites a commonly used global variable. Implementing your script using this method will break the tracking on many websites - do not use it.
  2. Fully run the code within the scope of a content script:
    Two options:
    1. Include the external files in the extension
    2. Include the external files in the extension, plus implement an auto-update feature.

Method 1: Fully local copy

manifest.json (only the relevant parts are shown):

{   "name": "Website Safety",   "version": "1.0",   "manifest_version": 2,   "description": "The Website Safety Extension.",   "permissions": [     "tabs", "http://*/*", "https://*/*"   ],   "content_scripts": [     {       "matches": ["<all_urls>"],       "js": ["ga-config.js", "ga.js", "js15_as.js"]     }   ] } 

In ga-config.js, define the variables as follows:

var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-31046309-1']); _gaq.push(['_setAllowLinker', true]); _gaq.push(['_trackPageview']);  var _Hasync= _Hasync|| []; _Hasync.push(['Histats.start', '1,1342541,4,0,0,0,00000000']); _Hasync.push(['Histats.fasi', '1']); _Hasync.push(['Histats.track_hits', '']); 

Download https://ssl.google-analytics.com/ga.js, and save it as ga.js.
Download http://s10.histats.com/js15_as.js, and save it as js15_as.js.

Method 2: Injecting a Up-to-date GA

If you want to have an up-to-date version of GA, a convoluted way of injecting the code has to be used, because Content scripts cannot be included from an external URL.

An old version of this answer relied on the background page and chrome.tabs.executeScript for this purpose, but since Chrome 20, a better method has become available: Use the chrome.storage API to cache the JavaScript code. To keep the code updated, I will store a "last updated" timestamp in the storage; you can also use the chrome.alarms API instead.

Note: Do not forget to include a local copy of the external file in your extension, in case the user does not have an internet connection, etc. Without an internet connection, Google Analytics wouldn't work anyway.

Content script, activate-ga.js.

var UPDATE_INTERVAL = 2 * 60 * 60 * 1000; // Update after 2 hour  // Retrieve GA from storage chrome.storage.local.get({     lastUpdated: 0,     code: '' }, function(items) {     if (Date.now() - items.lastUpdated > UPDATE_INTERVAL) {         // Get updated file, and if found, save it.         get('https://ssl.google-analytics.com/ga.js', function(code) {             if (!code) return;             chrome.storage.local.set({lastUpdated: Date.now(), code: code});         });     }     if (items.code) // Cached GA is available, use it         execute(items.code);     else // No cached version yet. Load from extension         get(chrome.extension.getURL('ga.js'), execute); });  // Typically run within a few milliseconds function execute(code) {     try { window.eval(code); } catch (e) { console.error(e); }     // Run the rest of your code.     // If your extension depends on GA, initialize it from here.     // ... }  function get(url, callback) {     var x = new XMLHttpRequest();     x.onload = x.onerror = function() { callback(x.responseText); };     x.open('GET', url);     x.send(); } 

Minimum manifest file:

{   "name": "Website Safety",   "version": "1.0",   "manifest_version": 2,   "permissions": [     "tabs", "http://*/*", "https://*/*"   ],   "content_scripts": [     {       "matches": ["<all_urls>"],       "js": ["activate-ga.js"]     }   ],   "web_accessible_resources": ["ga.js"] } 

The same method can be used for other trackers. The minimum permission requirements:

  • https://ssl.google-analytics.com/ga.js, so that should be added at the permissions section. https://*/* or <all_urls> is also sufficient.
  • optional: unlimitedStorage - If you want to store a large piece of data with chrome.storage.
like image 114
Rob W Avatar answered Sep 28 '22 00:09

Rob W


2015 Update

The new Universal Analytics snippet can definitely handle multiple trackers, so assuming you give yours a unique name and run all Analytics code in the page's context, you should be good to go.

// add Universal Analytics to the page (could be made conditional) runFunctionInPageContext(function () {   (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){   (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o);   a.async=1;a.src=g;document.documentElement.appendChild(a)   })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); });  // all Google Analytics calls should use our tracker name   // and be run inside the page's context runFunctionInPageContext(function () {   ga('create', 'UA-12345-6', 'auto', {'name': 'myTracker'});   ga('myTracker.send', 'pageview'); // note the prefix });  // simple helper function function runFunctionInPageContext(fn) {   var script = document.createElement('script');   script.textContent = '(' + fn.toString() + '());';   document.documentElement.appendChild(script);   document.documentElement.removeChild(script); } 

Note, there's one slight modification in the analytics snippet to use document.documentElement instead of the first <script> element. It is because google assumes you add analytics in an inline script block, whereas here you add it from a content script.

like image 45
25 revs, 4 users 83% Avatar answered Sep 28 '22 01:09

25 revs, 4 users 83%