Track Copied Text SiteCatalyst Plugin

UPDATED: March 29, 2013 – Track Copied Text plugin version 2.0k

This was a bit of code that was in desperate need of an update, so thats exactly what it got. Here I have the updated version of the Track Copied Text plugin, version 2.0k.

Improvements with this version include:

  • The entire code has been completely rewritten and is now in a standard SiteCatalyst plugin format.
  • The ability to set any combination of eVars, props, events, or nothing but an empty custom link call.
  • Prevents copied text longer than 255 characters from being set in any variable (100 characters in a prop).
  • Prevents the same highlighted text to be copied multiple times in a row.
  • The ability to include or not include variables set in s.linkTrackVars or s.linkTrackEvents.
  • The ability to use a custom link name.

Implementing this version is quick and easy. First include the Track Copied Text plugin code below in your s_code file with all the rest of your plugins:

/* Track Copied Text v2.0k */
s.trackCopiedText=new Function("v","e","a","n",""
+"var s=this,x=arguments;s.ea=!1;if(!s.ea){s.ea=!0;!1;function t"
+"ct(x){if(!{var b=s.linkTrackVars,c=s.linkTrackEvents,d=',event"
+"s',g=h='',f,i;e=e?e:'';n=n?n:'text copied';if(a){if(b&&b!='None')g="
+",n);!0}};function gct(){if(s.d.selection){return s.d.selection"
+".createRange().text}else if(s.wd.getSelection){return s.wd.getSelec"
+"tion()}return ''};if(s.wd.attachEvent){s.wd.attachEvent('oncopy',tc"
+"t)}else if(s.wd.addEventListener){s.wd.addEventListener('copy',tct,"

Next add a call to the plugin in the s_doPlugins section of your s_code file (preferably near the bottom of the s_doPlugins section). The plugin call will accept 4 parameters, all of them being optional.


v = The variable’s that you would like the copied text recorded to. Insert as many as you would like, each one comma separated. Any copied text will be trimmed to 255 characters, except for props which will get trimmed to 100 characters.
e = The events that you would like to set when text is copied. Again, feel free to set as many as you would like, or you can choose not to set any events.
a = This is a flag that when set to 1 indicates if you have s.linkTrackVars or s.linkTrackEvents set on any page to also include those variables with the Copied Text function call. If this variable is not included then no additional variables will be included with the call.
n = This is the name of the call that will appear in the Custom Links report in SiteCatalyst. If this is not set then the default value of “text copied” will be used.


To capture the copied text in s.eVar20 and set event15 (this is how I have it set on this site):


To capture the copied text in s.eVar20, s.prop35, set event25, and include anything currently set in s.linkTrackVars or s.linkTrackEvents:


To capture the copied text in s.prop30 and use the custom link name of “visitor selection”:

s.trackCopiedText('prop30','','','visitor selection');

To just fire a custom link call when the visitor copies some text (not capturing the copied text or setting any events):


As with all code, make sure you fully test it to ensure it works with your site. Also let me know of any changes or additions you’d like to see with this plugin, and of any insights you were able to gain by using this plugin. I’d love to hear how its working for your site.


Original Post: December 21, 2009

To me Web Analytics is the science of analyzing visitor behavior in order to improve the Web Site for the purpose of increasing conversion. Anytime I can use web analytics to help the visitor find what they are looking for, I feel I’m doing my job. But lets say your visitors are finding what they are looking for, but it is just not as easy as it could be? How would I know?

One thing I have been playing with is to monitor what content my visitors are selecting and copying from the site. If I see a lot of visitors copying my email address, maybe I should make the contact form a little easier to be found. If I see a lot of copying of some sample code, maybe I should make it easier to download it, or include a pdf copy. But how do I find out how to capture what my visitors copy? Here you go.

This is all done by adding a plug-in and a bit of code to the s_code file. This code looks for any time some text is copied and sets it in a prop and fires an event. This will work if the visitor highlights text and goes the right click/copy route, or by hitting Control/Command + C. You will need either 1 eVar and 1 event, or a 1 prop to use. If you want to go the eVar and event route, take this code and place it some where BEFORE the function s_doPlugins(s) call:

var eventAttached=false; 
if(!eventAttached){eventAttached = true;
function trackCopy(){
var overrides = {'events':'event8','eVar18':getCopiedText()};
   	s.linkTrackVars='eVar18,events';'event8';, 'o', 'Text Copied', overrides);
	if(s.templtv) s.linkTrackVars=s.templtv;
	if(s.templte) s.linkTrackEvents=s.templte; 

Insert the eVar and event you are going to use where you see them in the code. If you decide to just use a single prop instead, then use this bit of code, again before the function s_doPlugins(s) call:

var eventAttached=false;
if(!eventAttached){eventAttached = true;
function trackCopy(){
var overrides = {'prop49':getCopiedText()};
   	s.linkTrackVars='prop49';, 'o', 'Text Copied', overrides);
	if(s.templtv) s.linkTrackVars=s.templtv;

Insert the prop you want to use where you see it set. Next take this code and put it in the plug-in’s section of the s_code file:

function getCopiedText() {
if (document.selection){return document.selection.createRange().text;}
else if (window.getSelection){return window.getSelection();}return '';}
if(document.body && document.body.attachEvent){
document.body.attachEvent("oncopy", trackCopy);}
else if (document.body && document.body.addEventListener){
document.body.addEventListener('copy',trackCopy, false);}}

What are we going to end up with? You will get a report that looks like this:
Copied Text Report

It’s pretty interesting to see what your visitors are choosing to copy. Now do I expect to find huge some game changing incite that will lead me to make a change to the Web Site that will increase my conversion rate 100% with this report? Probably not. Do I expect to find one more place that allows me to make another 1% improvement? I sure do. Remember, all those 1% improvements add up. ;)

Big thanks to kgs/ksmith in the Omniture Developer Connection for the original idea to do this.


Additional Methods To Measure Interaction Using The Get Time To Complete Plug-In

Recently there was a great article on the Omniture Blog all about Capturing Time Spent on . . . well, just about anything. It’s a great post and definitely worth checking out. After reading it I was wondering if there was another way to do it? Of course there is! I present the Time To Complete Plug-in.

The getTimeToComplete plug-in will track the time it takes a user to complete some process on your site. The “clock” begins when you call the plug-in with the value “start” and stops when the plug-in with the value “stop”. The plug-in can be used to track the time to complete a checkout process, to track the time to complete an application process, to track the time a user spends viewing/using Rich Internet Applications (RIA), or to track the time between a download and a purchase.

s.getTimeToComplete( v, cn, e )

v is the Value – ‘start’ or ‘stop’
cn is the Cookie Name – example: ‘ttc’
e is the Expiration – days to expiration of the cookie, 0 for session
This function will return an empty string ” or a value in days, hours, minutes or seconds

There is a bunch of different ways to use this plug-in. I like this first method because you do not have to add a single of code to the page to make it work (I have found it is much easier to get a development team to simply upload a new s_code file as opposed to adding additional code to the site.) Lets say you want to track a form on your site. Lets say the form is at /my-form.php. Once the visitor fills out the form, they are taken to the thank you page which lets say is at /my-form-thanks.php. I would add this bit of code to the s_code file:

if (window.location.pathname=='/my-form.php') s.ttc='start';
if (window.location.pathname=='/my-form-thanks.php') s.ttc='stop';

What this does is looks for the path in the URL for /my-form.php and sets start in s.ttc. When the plug-in see’s this it set’s the cookie ttc with a start time Then when the URL path is /my-form-thanks.php stop is set. When the plug-in see’s stop, it then reads the ttc plug-in and records the time difference in s.prop1. The time value that you will get will have days and hours rounded to .2 (e.g. 1.4 days), minutes to .5 (e.g. 2.5 minutes), and seconds to 5 (e.g. 15 seconds).

NOTE:When this is implemented, if you check the debugger you will not see any value for s.prop1 until you have reached the stop point of the process.

Here is another way to use the code. Let’s say you have some events set right on the pages of your site. We want to know how long it takes to get from when event1 is set to when event2 is set. I would add this code into the s_code file:

if('event1')>-1) s.ttc='start';
if('event2')>-1) s.ttc='stop';

What this does is look for when event1 happens, then set start in s.ttc. When event2 happens stop is set, and the time value is set in s.prop1.

NOTE: Another thing to remember is this can be used to record the time of many different processes or paths on your site. If you do that I suggest using a different cookie name and variable value in each one so there are no issues.

Here is the actual plug-in code:
The getTimeToComplete plug-in returns the time to complete a task. When v is ‘start’ a cookie is written with the timestamp. When v is ‘stop’ the cookie is read and the expired time is returned in days, hours, minutes, or seconds.

 * Plugin: getTimeToComplete
s.getTimeToComplete=new Function("v","cn","e",""
+"var s=this,d=new Date,x=d,k;if(!s.ttcr){e=e?e:0;if(v=='start'||v=='"
+"_w(cn,d.getTime(),e?x:0);return '';}if(v=='stop'){k=s.c_r(cn);if(!s"
+".c_w(cn,'',d)||!k)return '';v=(d.getTime()-k)/1000;var td=86400,th="
+"3600,tm=60,r=5,u,un;if(v>td){u=td;un='days';}else if(v>th){u=th;un="
+"'hours';}else if(v>tm){r=2;u=tm;un='minutes';}else{r=.2;u=1;un='sec"
+"onds';}v=v*r/u;return (Math.round(v)/r)+' '+un;}}return '';");

I really like this plug-in because you end up with a report that is completely dedicated to the time it takes to complete that exact action.


Three SiteCatalyst Plugins To Add Detail To Visits

Here are three different plugins that have to do with your site visits. If you have not read it yet, be sure to check out Omniture’s Matt Belkin’s view on visits. It is one of the most important metrics to use, and here are a few plugins that will give you a little more insight to your site’s visits.

1. New/Repeat Visit
This plugin takes a look at each visit and sets the value of either “New” or “Repeat” right in a prop or eVar. One thing about this plugin is that it will set the value on every page view. One thing I recommend is to contact Client Care and have them enable visits for for the prop you plan to use with this plugin. Here is what you should get:
New/Repeat Visit Report

Here is the actual code:


 * Plugin: getNewRepeat
s.getNewRepeat=new Function(""
+"var s=this,e=new Date(),cval,ct=e.getTime(),y=e.getYear();e.setTime"
+"'s_nr',ct,e);return 'New';}if(cval.length!=0&amp;&amp;ct-cval<30*60*1000){s"
+".c_w('s_nr',ct,e);return 'New';}if(cval<1123916400001){e.setTime(cv"
+"al+30*24*60*60*1000);s.c_w('s_nr',ct,e);return 'Repeat';}else retur"
+"n 'Repeat';");

2. Visit Number
This plugin counts the number of visits that an individual visitor has. This is neat to see how users on their 9th or 10th visit interact with the site, as opposed to their 3rd or 4th visit. The report you will get with this is just a list of numbers, which you can correlate with other traffic items.

Here is the actual code:


 * Plugin: getVisitNum
s.getVisitNum=new Function("" 
+"var s=this,e=new Date(),cval,cvisit,ct=e.getTime(),c='s_vnum',c2='s" 
+" i=cval.indexOf('&amp;vn='),str=cval.substring(i+4,cval.length),k;}cvis" 
+"true',e);return str;}else return 'unknown visit number';}else{if(st" 
+";e.setTime(ct+30*60*1000);s.c_w(c2,'true',e);return str;}else{s.c_w" 
+",'true',e);return 1;}}"); 

3. Days Since Last Visit
This report looks at all of your visits, and tells you how long it has been since the previous visit. As with the previous two, this is going to be set on every page of the site, so make sure you enable visits. Here is what the report would look like:
Days Since Last Visit Report
As you can see it takes each visit and categorizes each one as being First Visit, Less than 1 day, Less than 7 days, More than 7 days, and More than 30 days.

Here is the actual code:


 * Plugin: Days since last Visit
s.getDaysSinceLastVisit=new Function("c",""
+"var s=this,e=new Date(),es=new Date(),cval,cval_s,cval_ss,ct=e.getT"
+"etTime(ct+30*60*1000);f0='Cookies Not Supported';f1='First Visit';f"
+"2='More than 30 days';f3='More than 7 days';f4='Less than 7 days';f"
+"5='Less than 1 day';cval=s.c_r(c);if(cval.length==0){s.c_w(c,ct,e);"
+"s.c_w(c+'_s',f1,es);}else{var d=ct-cval;if(d>30*60*1000){if(d>30*da"
+"y){s.c_w(c,ct,e);s.c_w(c+'_s',f2,es);}else if(d<30*day+1 &amp;&amp; d>7*day"
+"){s.c_w(c,ct,e);s.c_w(c+'_s',f3,es);}else if(d<7*day+1 &amp;&amp; d>day){s."
+"c_w(c,ct,e);s.c_w(c+'_s',f4,es);}else if(d<day+1){s.c_w(c,ct,e);s.c"
+"+'_s',cval_ss,es);}}cval_s=s.c_r(c+'_s');if(cval_s.length==0) retur"
+"n f0;else if(cval_s!=f1&amp;&amp;cval_s!=f2&amp;&amp;cval_s!=f3&amp;&amp;cval_s!=f4&amp;&amp;cval_s"
+"!=f5) return '';else return cval_s;");

Any of these can also be used to populate an eVar, and you can use them with the getValOnce plugin to grab each value one time per visit, then you can use these in conjunction with any of your success events to give you a greater insight on your site’s visits.

Please consult Client Care before using any of these to see if they are a good fit for your site and what you are trying to accomplish with your analytics investment.

Using Visitor Intentions To Track Your Web Site

Implementing basic web analytics on your web site should be pretty straight forward. Add the code to every page and your on your way. Once you start getting creative with your site elements is when you really need to look at which elements you are tracking as basic traffic metrics. Just blindly adding tracking code to every single page you have listed on your server can lead to miscounting what is really going on. Let me explain.

The two biggest things that I have seen a problem with is pop-ups and iframes. These elements while both technically can be additional pages to your site, they should not be considered as additional page views. The main thing to consider here is visitor intention. Consider the following example. If you take a look at this page on Boat, you will see a form at the bottom of the page. While everything looks nice and seamless, that form is actually a iframed in page. Even though you are viewing two pages here, the visitors intention is not to see two pages but a single page. That iframed form should not be tracked as a page view. This can easily be overlooked if adding code to everything you see. Still looking at that page we see a link near the top of the page that says “Send to Friend”. Clicking this brings up a pop-up form which is also another seperate page, presented as a pop-up. Again, the visitor did not intend to view another page of the site so that pop-up should also not be considered another page view of the site. All of this should be pretty simple to figure out. Nothing really ground breaking yet.

When I talk about this to others the largest debate I come across is tracking outsourced sections of your site. Content syndication has been around for a long time and comes in many different forms. But when it comes to tracking these pages is where it gets a little hairly and we need to rely on visitor intention to help us out.

Lets look at another example. If you visit Walmart’s site, you will see a link on their left nav, for Job Classifieds. Clicking on that link takes you to a Walmart Job Classified page. Now this page is completely outsourced and is actually a subdomain of Oodle. Looking at the page it is branded and styled to look just like a page of Walmart’s intention is to let the user feel like they are still on their own site, and this is just another page. Walmart should count this as another page view of their site. Now lets look at this from Oodle’s side of things. This page is ‘technically’ a part of, with all of Oodle’s content. So what do they do? Does Oodle get credit for another visit, visitor or page view? Looking at the visitors intentions, they never intended to visit They intended to visit Walmart did all the legwork to attract that visitor to their site, and should get credit for everything that happens with that visitor. That is Walmarts visit, visitor and page view and should be credited toward the report suite.

But that is Oodle’s content. It is Oodle’s advertisers that are getting impressions and the leads. What do they get out of the deal? How does Oodle tell their advertisers that their ad recieved 2 leads with 0 visitors? This page still needs to be tracked by Oodle in some fashion, but in a separate report suite than the main site. To someone in this situation I would recommend that they create a new report suite and call it ‘affiliate network’. Then they have the ability to track all of the leads generated from this page to their advertisers, but without artificially inflating the number of visitors who actually intended to visit Then by using the SiteCatalyst Excel client you can bring in both site’s metrics on to a single spread sheet and you have the ability to report on the performance of main site and the affiliate network of sites.

I can see where it would be tempting by the crew over at Oodle to call that another page view of their site to bump up their traffic numbers, but that is misleading. Our sites are built for our visitors, and should be tracked using their intentions.