Google custom search, the simple side of google

Outdated – Google switched the custom search off

“Everyone” uses Google, so do I (among other search engines) but the Google page got a bit heavy over the years and I felt watched. If you look into the page source you see all kind of stuff that monitors your behavior while you are on the page, where you hover, where you click and if you click, it redirects you over one of their servers. That way they collect a complete browsing history (admit it: Apart from some pages you have bookmarked, all of your web visits somehow start with Google ;)) which is not what I want. 

Some day I found out that Google offers a special search, called Google Custom.

The result page already looks quite clean, (see the source code of this “test” search: ) but it could be improved a bit. During an ICQ session BS-Harou and I had the idea to clean it up a little bit more and to “pimp” it a bit by adding some extras like a search for related YT videos and images.

This is the result:


and this is the code of the userJS and CSS we created:

// ==UserScript== // @name           Nicer Google/custom search // @author         BS-Harou, QuHno // @description    prettifies  searches, adds links to the top 8 query related images and top 3 related YouTube Videos // @include* // @version        1.0.12 // ==/UserScript==  document.addEventListener('DOMContentLoaded', function() { 	var block = document.createElement('div'); = 'userjs-block'; 	 	// QuHno: No link replacement for me. 	var theA = document.querySelectorAll('A'); 	for (var i = theA.length - 1; i >= 0; i--) { 		theA[i].onmousedown = null; 	} 	window['curwt'] = null; 	  	function getQueryVariable(variable) { 		var query =; 		var vars = query.split('&'); 		for (var i = 0; i < vars.length; i++) { 			var pair = vars[i].split('='); 			if (decodeURIComponent(pair[0]) == variable) { 				return pair[1]; 			} 		} 	}  	function insertAfter(newNode, referenceNode) { 		referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); 	}  	function addImage(url, realUrl, title) { 		var link = document.createElement('a'); 		link.href = realUrl; 		link.className = 'userjs-image-link'; 		link.title = title.replace(/<\/?b>/g,''); // QuHno: remove ugly <B> tags  		var tmp = new Image(url); 		tmp.src = url; 		tmp.className = 'userjs-image'; 		tmp.width = 100; 		tmp.height = 100;  		link.appendChild(tmp); 		block.appendChild(link); 	}  	function addVideo(url, realUrl, title, desc) { 		var link = document.createElement('a'); 		link.href = realUrl; 		link.className = 'userjs-video-link'; 		link.title = title;  		var tmp = new Image(url); 		tmp.src = url; 		tmp.className = 'userjs-video'; 		tmp.width = 120; 		tmp.height = 90;  		var text = document.createElement('span'); 		text.className = 'userjs-video-text'; 		text.innerHTML = title;  		var descEle = document.createElement('span'); 		descEle.className = 'userjs-video-desc'; 		descEle.innerHTML = desc;  		link.appendChild(tmp); 		link.appendChild(text); 		link.appendChild(descEle);  		block.appendChild(link); 	} 	 	// QuHno: add search for more videos or images. Should this be inlined? 	function searchMore(what) {         var theHref, theInnerHTML, theQuery = getQueryVariable('q');                  switch(what) {             case 'images':                 theHref = '' + theQuery + '&ie=UTF-8&tbm=isch&sa=N';                 theInnerHTML = 'Google Images: <span class="link">' + decodeURIComponent(theQuery).replace(/[+]/g,' ') + '</span>';                 break;             case 'videos':                 theHref = '' + theQuery;                 theInnerHTML = 'YouTube: <span class="link">' + decodeURIComponent(theQuery).replace(/[+]/g,' ') + '</span>';                 break;             default: return;         }                  var link = document.createElement('a');         link.href = theHref;         link.innerHTML = theInnerHTML;         link.className = 'userjs-more-link';                  block.appendChild(link);     }      window.imageHandler = function(data) {         var tmp;         if (data && data.hasOwnProperty('responseData') && data.responseData && typeof data.responseData == 'object' && data.responseData.hasOwnProperty('results')) {             for (var i=0; i < 8 && i < data.responseData.results.length; i++) {                 tmp = data.responseData.results[i];                 addImage(decodeURIComponent(tmp.tbUrl), tmp.unescapedUrl, tmp.title);             }             searchMore('images'); // QuHno: add direct link to Google image search                          //document.querySelector('#res').appendChild(block);             //document.querySelector('#res').insertBefore(block, document.querySelector('#navbar'));             insertAfter(block, document.querySelector('#res div')); // QuHno: changed because of "Did you mean"         }          var videoLoader = document.createElement('script');         videoLoader.src = '' + getQueryVariable('q') + '&v=2&alt=jsonc&callback=videoHandler&max-results=3';          document.body.appendChild(videoLoader);     };      window.videoHandler = function(data) {         var tmp;         if (data && data.hasOwnProperty('data') &&'items')) {             for (var i=0; i < 3 && i <; i++) {                 tmp =[i];                 addVideo(tmp.thumbnail.sqDefault, tmp.player.default, tmp.title, tmp.description);             }             searchMore('videos'); // QuHno: add direct link to YouTube video search                          //document.querySelector('#res').appendChild(block);             //document.querySelector('#res').insertBefore(block, document.querySelector('#res div'));         }     };      var imageLoader = document.createElement('script');     imageLoader.src = '' + getQueryVariable('q') + '&v=1.0&callback=imageHandler&rsz=8';     document.body.appendChild(imageLoader);          // QuHno: embedded the CSS in the script. No need to set up a site specific userCSS.     var css = '\r\n\ html { \r\n\     color: #000;\r\n\     background: #f2f2f2;\r\n\ }\r\n\ #navbar, #res > p { \r\n\     clear: both;\r\n\ } \r\n\ .tc img { \r\n\     height: 60px;\r\n\     width: 130px;\r\n\ }\r\n\ #res li:first-of-type .g { \r\n\     margin: 0;\r\n\ }\r\n\ body { \r\n\     padding: 0 40px;\r\n\     max-width: 80rem;\r\n\     margin: 0 auto;\r\n\     box-sizing: border-box;\r\n\ }\r\n\ table.ra, body > table + table { \r\n\     display: none;\r\n\ }\r\n\ #res > p:first-child + div, #res > div:first-child { \r\n\     padding: 20px 0;\r\n\     float: left;\r\n\ }\r\n\ /*#res li*/.g { \r\n\     break-inside: avoid;\r\n\     margin: 20px 0;\r\n\ }\r\n\ input[name=q] { \r\n\     padding: 4px 8px;\r\n\     font-size: 1rem;\r\n\     vertical-align: middle;\r\n\     border: 1px solid #bbb;\r\n\     width: 500px;\r\n\ }\r\n\ input[name=q]:hover, input[name=q]:focus { \r\n\     border: 1px solid #777;\r\n\ }\r\n\ input[name=btnG] { \r\n\     border: 1px solid rgba(0, 0, 0, 0.400);\r\n\     box-shadow: inset -10px -15px 30px rgba(0, 0, 0, 0.102), inset 1px 1px 1px rgba(255, 255, 255, 0.506);\r\n\     transition: background-color 0.1s;\r\n\     background-color: #1133F7;\r\n\     color: #FFF;\r\n\     font-size: 1rem;\r\n\     padding: 4px 12px 4px 12px;\r\n\     box-sizing: border-box;\r\n\     line-height: 1.24;\r\n\     vertical-align: middle;\r\n\     cursor: pointer;\r\n\ }\r\n\ input[name=btnG]:hover { \r\n\     color: #FFF;\r\n\     background-color: #14F;\r\n\ }\r\n\ #userjs-block { \r\n\     float: right;\r\n\     box-sizing: border-box;\r\n\     padding: 15px 30px;\r\n\     width: 45%;\r\n\ }\r\n\ .userjs-image { \r\n\     -o-object-fit: cover;\r\n\     -o-object-position: top left;\r\n\     color: #00C;\r\n\     background: #111;\r\n\     overflow: hidden;\r\n\     margin: 3px;\r\n\ }\r\n\ .userjs-image-link { \r\n\     margin: 2px;\r\n\     border-bottom: 1px solid #666;\r\n\     border-left: 1px solid #999;\r\n\     border-right: 1px solid #666;\r\n\     border-top: 1px solid #999;\r\n\     overflow: hidden;\r\n\     display: inline-block;\r\n\ }\r\n\ .userjs-video { \r\n\     -o-object-fit: cover;\r\n\     float: left;\r\n\     -o-object-position: top left;\r\n\     border-bottom: 1px solid #666;\r\n\     border-left: 1px solid #999;\r\n\     border-right: 1px solid #666;\r\n\     border-top: 1px solid #999;\r\n\     padding: 2px;\r\n\     color: #00C;\r\n\     background: #FFF;\r\n\     overflow: hidden;\r\n\     margin: 3px 3px 3px 0;\r\n\     vertical-align: top;\r\n\ }\r\n\ .userjs-video-link { \r\n\     margin: 2px;\r\n\     margin-top: 20px;\r\n\     overflow: hidden;\r\n\     display: block;\r\n\     text-decoration: none;\r\n\ }\r\n\ .userjs-video-text { \r\n\     padding: 10px 0 0 5px;\r\n\     display: inline-block;\r\n\     color: #000;\r\n\     font-size: 14px;\r\n\     font-weight: bold;\r\n\     width: 300px;\r\n\     white-space: nowrap;\r\n\     overflow: hidden;\r\n\     text-overflow: ellipsis;\r\n\ }\r\n\ .userjs-video-link:hover, .userjs-video-text:hover, .userjs-more-link:hover { \r\n\     text-decoration: underline;\r\n\ } \r\n\ .userjs-video-desc { \r\n\     display: block;\r\n\     padding: 10px 0 0 5px;\r\n\     font-weight: normal;\r\n\     font-size: 12px;\r\n\     line-height: 1;\r\n\     text-decoration: none;\r\n\     color: #000;\r\n\     float: left;\r\n\     width: 300px;\r\n\ }\r\n\ .userjs-more-link { \r\n\     overflow: hidden;\r\n\     color: #000;\r\n\     font-size: 14px;\r\n\     font-weight: bold;\r\n\     display: block;\r\n\     text-decoration: none;\r\n\     text-overflow: ellipsis;\r\n\ }\r\n\ @media all and (max-width: 69rem) {\r\n\     #userjs-block { \r\n\     display: none;\r\n\     }\r\n\ }\r\n\ @media all and (max-width: 55rem) {\r\n\     .tc img { \r\n\         display: none;\r\n\     }\r\n\     input[name=q] { \r\n\         width: 300px;\r\n\     }\r\n\ }\r\n\ @media all and (max-width: 80rem) { \r\n\     body { \r\n\         padding: 20px;\r\n\     }\r\n\ }\r\n',         head = document.getElementsByTagName('head')[0],         style = document.createElement('style');          if (style.styleSheet){      style.styleSheet.cssText = css;     } else {      style.appendChild(document.createTextNode(css));     }     head.appendChild(style); }); 

Just install it in your userJS capable browser (Opera

(PS: the WOT rings don’t belong to this script, that’s another one – not the official extension, but something lightweight.)

5 replies on “Google custom search, the simple side of google”

  1. Nice userJS [b]but[/b]…
    Unfortunately AFAIK as all other userJSs it won’t run on Opera except you have JS enabled globally.
    That’s a major shortcoming of Opera Presto and all user requests to remedy it fell on deaf ears.

  2. True, [b]but…[/b]
    It is quite easy to block any other script from executing in Presto/Caracan by the use of another userJS or an Extension because it has built in all that nice [i]before[/i]Foo stuff and because userJS in Presto start before any of the scripts on the page can start 🙂

  3. While simply loading my BlogSpot Blog in recent times, I finally hit a point where I officially seriously wondered what the blazes Google was up to behind the scenes.

    I was watching the activity down in the Opera Extended Progress Bar. Suddenly I saw something about something from Popular Mechanics being loaded. It was then that I went, “Whoa Whoa WHOA! Hold the phone! What the heck is ANYTHING from Popular Mechanics doing being loaded? I have absolutlely nothing from Popular Mechanics on my Blog. Not in my Blog Design and not in my Blog’s content. None of my visitors have put up anything in the comments from Popular Mechanics. Why should there be any loading activity involving Popular Mechanics?”

  4. I mean, not that Popular Mechanics is to be feared like the Boogey Man or the Borg. Still, it made me wonder just what Google was up to. Especially considering that my Blog Spot Blog takes like twice as long to load as my MyOpera Blog. And most of that extra loading activity appears to take place AFTER my Blog Design and everything else has already displayed.

    So what IS Google up to behind the scenes? Why does my BlogSpot Blog need to load about 2 Meg more than my MyOpera Blog when my MyOpera Blog Design is even more intricate than my BlogSpot one?

  5. Oh, that is simple – Google is selling adds for a living. To sell ads it is necessary to know the customers. Simple as that. No plan for world domination etc. – at least as far as I know….

    … but I’ll transfer one of my articles from myop to here, which might make you wonder if my assumption is true – stay tuned …

Comments are closed.