Environments
Besides production, you can run Trackingplan on other environments, such as staging or development, to catch problems before any release.
You set your “environment” dynamically, at run time. That lets you:
- Keep the data and specs of each environment apart.
- Compare environments to catch mistakes before they reach production. For example, compare staging data with your master specification baseline to catch bugs or regressions early.
- Create as many environments as you need. Most teams have about 3 (production, staging, and development) to check changes before a release. Some Trackingplan users even have one environment per branch or per automated test, to find errors with more granularity.
Setting up Trackingplan for different environments
Trackingplan supports complex deployment setups with custom preproduction environments.
Change this init with your settings and your own TP_ID. Then add it at the top of the <head> section of your site (instructions here), or as a new Google Tag Manager Script (instructions here).
<script type="text/javascript">
(function(){function a(a){var b={method:"POST",endpoint:"TRACKINGPLAN",payload:JSON.stringify(a)};m(b)}function b(a){if($.includes("img"))try{f(a)}catch(a){E(a)}if($.includes("xhr"))try{h(a)}catch(a){E(a)}if($.includes("beacon"))try{i(a)}catch(a){E(a)}if($.includes("form"))try{l(a)}catch(a){E(a)}if($.includes("ws"))try{k(a)}catch(a){E(a)}if($.includes("fetch"))try{j(a)}catch(a){E(a)}}function c(){var a=d();if(null!==a&&!Y)return!1;var b={landing:document.location.href,referrer:document.referrer};return H.setItem("_trackingplan_initial",JSON.stringify(b)),!0}function d(){return JSON.parse(H.getItem("_trackingplan_initial"))}function e(){try{if(H.setItem("_tp_t","a"),"a"!==H.getItem("_tp_t"))return!1;if(H.removeItem("_tp_t"),"function"!=typeof navigator.sendBeacon)return!1}catch(a){return!1}return!0}function f(a){var b=a.Object.getOwnPropertyDescriptor(a.HTMLImageElement.prototype,"src").set;a.Object.defineProperty(a.HTMLImageElement.prototype,"src",{set:function(a){return 2048<a.length?b.apply(this,arguments):(m({method:"GET",endpoint:a,protocol:"img"}),b.apply(this,arguments))}});var c=a.HTMLImageElement.prototype.setAttribute;a.HTMLImageElement.prototype.setAttribute=function(a,b){if("src"==a.toLowerCase()){if(b.length>2048)return c.apply(this,arguments);m({method:"GET",endpoint:b,protocol:"img"})}return c.apply(this,arguments)}}function g(a){var b=a;try{b instanceof FormData&&(b=JSON.stringify(Object.fromEntries(b)))}catch(a){}return b}function h(a){var b=a.XMLHttpRequest.prototype.open,c=a.XMLHttpRequest.prototype.send;a.XMLHttpRequest.prototype.open=function(a,c){return this._tpUrl=c,this._tpMethod=a,b.apply(this,arguments)},a.XMLHttpRequest.prototype.send=function(a){var b=g(a);return m({method:this._tpMethod,endpoint:this._tpUrl,payload:b,protocol:"xhr"}),c.apply(this,arguments)}}function i(a){var b=a.navigator.sendBeacon;a.navigator.sendBeacon=function(a,c){if(2048<a.length)return b.apply(this,arguments);var d=g(c);return m({method:"POST",endpoint:a,payload:d,protocol:"beacon"}),b.apply(this,arguments)}}function j(a){var b=a.fetch;a.fetch=function(a,c){if(2048<a.length)return b.apply(this,arguments);var d="GET",e=null;return void 0!==c&&(void 0!==c.method&&(d=c.method.toUpperCase()),void 0!==c.body&&(e=g(c.body))),m({method:d,endpoint:a,payload:e,protocol:"fetch"}),b.apply(this,arguments)}}function k(a){var c=a.WebSocket;a.WebSocket=function(d,a){return a?new c(d,a):new c(d)};var b=c.prototype.send;c.prototype.send=function(a){({method:"WS",endpoint:this.url,payload:a,protocol:"ws"});return m({method:"WS",endpoint:this.url,payload:a,protocol:"ws"}),b.apply(this,arguments)},a.WebSocket.prototype=c.prototype}function l(a){a.addEventListener("submit",function(a){try{var b=a?a.target:this,c={method:b.method,endpoint:b.action,payload:JSON.stringify({location:I.location.href,form_id:b.id,method:b.method,form_data:Object.fromEntries(new FormData(b))}),protocol:"form"};m(c)}catch(a){}},!0)}function m(a,b){setTimeout(function(){try{var c=C(a);if("TRACKINGPLAN"==a.endpoint&&(c="trackingplan"),!c)return;var d=A();return!1===d?(ea.push(a),E({m:"Pre queued, queue length = "+ea.length}),setTimeout(y,T),!1):(null===ha&&(ha=u(),ia=JSON.stringify(ha).length),!r(V,d))?(E({m:"Request ignored (sampling)",mode:V,dict:d}),!0):(n(s(a,c)),"function"==typeof b&&b(),!0)}catch(b){F({m:"Trackingplan process error",error:b,request:a})}},0)}function n(a){aa(a);var b=JSON.stringify(a);if(2e5<b.length&&E({m:"Track Too big, ignored: "+b.length}),b.length+2+ia>W)return q("["+b+"]",P),void E({m:"Track > Batch Size: "+b.length});var c=fa.length+b.length+ia;c>W&&(E({m:"Batch reaching limit: "+c}),o(P)),c=fa.length+b.length+ia,E({m:"Queue len: "+c,rawTrack:a}),0!==fa.length&&(fa+=","),fa+=b}function o(a){if(0!=fa.length){var b=fa;fa="";var c={requests:JSON.parse("["+b+"]"),common:ha};q(c,a)}}function p(){var a=R+M;return ca&&(a+="?debug=true"),a}function q(a,b){return("function"==typeof ba&&(a=ba(a)),E({m:"Sent",payload:a}),Z)?void E("Not sending, is dry run"):void("xhr"===b?function(a){var b=new XMLHttpRequest;b.open("POST",p(),!0),b.onreadystatechange=function(){if(4===b.readyState)try{E({m:"Parsed",response:JSON.parse(b.response)}),_(a,b.response)}catch(a){}},b.send(a)}(JSON.stringify(a)):"beacon"===b?function(a){navigator.sendBeacon(p(),a)}(JSON.stringify(a)):void 0)}function r(a,b){switch(a){case"user":return 1===b.isSampledUser;case"track":return Math.random()<1/b.sampleRate;case"all":return!0;case"none":default:return!1;}}function s(a,b){return{provider:b,request:{endpoint:a.endpoint,method:a.method,post_payload:a.payload||null,protocol:a.protocol,href:I.location.href}}}function t(){return D({hostname:I.location.hostname,user_agent:navigator.userAgent,load_url:ga},d())}function u(){return{context:t(),tp_id:M,source_alias:O,environment:N,sdk:ja.sdk,sdk_version:ja.sdkVersion,sampling_rate:A().sampleRate,debug:Q}}function v(){try{for(var a=window.performance.getEntriesByType("resource"),b={},c=[],d=0;d<a.length;d++){c.push(a[d].name);var e="",f=a[d].name.replace(/(^\w+:|^)\/\//,""),g=f.split("?"),h=g[0];g=h.split("/"),e=1<g.length?g[0]+"/"+g[1]:g[0];var j=e;b.hasOwnProperty(j)||(b[j]=0),b[j]++}return b}catch(a){return null}}function w(){for(;ea.length;){var a=ea.shift();m(a)}}function x(a,b){var c=Object.prototype.hasOwnProperty;return c.call(a,"environment_rates")&&c.call(a.environment_rates,b)?a.environment_rates[b]:a.sample_rate}function y(){if(!da){var b=new XMLHttpRequest,c=S+"config-"+M+".json";b.onreadystatechange=function(){if(4==this.readyState)try{z(x(JSON.parse(this.responseText),N)),a({event_name:"new_dau"}),w()}catch(a){}da=!1},b.open("GET",c,!0),da=!0,b.send()}}function z(a){if(!1===a)return H.removeItem("_trackingplan_sample_rate"),H.removeItem("_trackingplan_sample_rate_ts"),void H.removeItem("_trackingplan_is_sampled_user");var b=Math.random()<1/a?1:0;E({m:"Trackingplan sample rate = "+a+". isSampledUser "+b}),H.setItem("_trackingplan_sample_rate_ts",new Date().getTime()),H.setItem("_trackingplan_sample_rate",a),H.setItem("_trackingplan_is_sampled_user",b)}function A(){var a=H.getItem("_trackingplan_sample_rate_ts");return null!==a&&(parseInt(a)+1e3*U<new Date().getTime()?(E({m:"Trackingplan sample rate expired"}),z(!1),!1):{sampleRate:parseInt(H.getItem("_trackingplan_sample_rate")),isSampledUser:parseInt(H.getItem("_trackingplan_is_sampled_user"))})}function B(a,b){if(null===a||null===b)return!0;if("/"===a[0]){var c=new RegExp(a.slice(1,-1));return c.test(b)}return-1!==b.indexOf(a)}function C(a){var b=a.endpoint,c=a.payload;if("string"==typeof b||b instanceof String){for(var d in L){var e=d.split("%"),f=e[0],g=2===e.length?e[1]:null;if(B(f,b)&&B(g,c))return L[d]}return!1}}function D(b,c){for(var d in c)b[d]=c[d];return b}function E(a){Q&&J.log("TP "+M,a)}function F(a){I.console&&J.warn&&J.warn(a)}function G(){function a(){for(var a=document.getElementsByTagName("IFRAME"),b=0;b<a.length;b++)d(a[b])}function c(a){try{return!!a.contentDocument}catch(a){return!1}}function d(a){try{c(a)&&(b(a.contentWindow),E("Intercepted frame "+a.id))}catch(a){}}function e(){var a=new MutationObserver(function(a){a.forEach(function(a){a.addedNodes.forEach(function(a){"IFRAME"==a.tagName&&d(a)})})});a.observe(document,{subtree:!0,childList:!0,attributes:!1,characterData:!1}),setTimeout(a.disconnect(),4e3)}"complete"===document.readyState?(a(),e()):document.onreadystatechange=function(){"complete"===document.readyState&&(a(),e())}}var H=localStorage,I=window,J=console;if(I.Trackingplan)return void F("Trackingplan snippet included twice.");var K={"google-analytics.com":"googleanalytics","analytics.google.com":"googleanalytics","api.segment.io":"segment",segmentapi:"segment","seg-api":"segment","segment-api":"segment","/.*api-iam.intercom.io/messenger/web/(ping|events|metrics|open).*/":"intercom","api.amplitude.com":"amplitude","ping.chartbeat.net":"chartbeat","/.*api(-eu)?(-js)?.mixpanel.com.*/":"mixpanel","trk.kissmetrics.io":"kissmetrics","ct.pinterest.com":"pinterest","facebook.com/tr/":"facebook","track.hubspot.com/__":"hubspot","/.*.heapanalytics.com/(h|api).*/":"heap","/.*snowplow.*/":"snowplow","/.*ws.*.hotjar.com/api/v2/client/ws/%identify_user":"hotjar","/.*ws.*.hotjar.com/api/v2/client/ws/%tag_recording":"hotjar","klaviyo.com/api/track":"klaviyo","app.pendo.io/data":"pendo","matomo.php":"matomo","rs.fullstory.com/rec%8137":"fullstory","rs.fullstory.com/rec%8193":"fullstory","logx.optimizely.com/v1/events":"optimizely","track.customer.io/events/":"customerio","alb.reddit.com/rp.gif":"reddit","px.ads.linkedin.com":"linkedin","/i/adsct":"twitter","bat.bing.com":"bing","pdst.fm":"podsights"},L={},M=null,N="PRODUCTION",O=null,P="xhr",Q=!1,R="https://tracks.trackingplan.com/v1/",S="https://config.trackingplan.com/",T=0,U=86400,V="user",W=6e4,X=20,Y=!1,Z=!1,$=["img","xhr","beacon","ws","fetch"],_=function(){},aa=function(){},ba=function(a){return a},ca=!1,da=!1,ea=[],fa="",ga="",ha=null,ia=0,ja=I.Trackingplan={sdk:"js",sdkVersion:"1.11.0",setOptions:function(a,b){b=b||{},M=a,N=b.environment||N,O=b.sourceAlias||O,P=b.sendMethod||P,L=D(K,b.customDomains||{}),Q=b.debug||Q,R=b.tracksEndPoint||R,S=b.configEndPoint||S,T=b.delayConfigDownload||T,U=b.sampleRateTTL||U,V=b.samplingMode||V,W=b.batchSize||W,X=b.batchInterval||X,Y=b.alwaysSendNewUser||Y,Z=b.dryRun||Z,$=b.intercept||$,_=b.onSubmit||_,ca=b.parse||ca,aa=b.onQueue||aa,ba=b.onBeforeSubmit||ba,E({m:"TP options updated",options:b})},init:function(d,f){f=f||{};try{if(!e())throw new Error("TP Not compatible browser");if(null!==M)throw new Error("TP Init already happened");ja.setOptions(d,f),ga=I.location.href,b(window),$.includes("frame")&&G(),document.addEventListener("visibilitychange",function(){"hidden"===document.visibilityState&&o("beacon")}),I.addEventListener("pagehide",function(){o("beacon")}),c()&&a({event_name:"new_user"}),a({event_name:"page_load"}),setTimeout(function(){a({event_name:"pixels",properties:{pixels:v()}})},1e4),setInterval(function(){o(P)},1e3*X),E({m:"TP init finished",options:f})}catch(a){F({m:"TP init error",error:a})}}}})();
Trackingplan.init("your TP_ID", {
'environment': 'how you want to name the environment (e.g. testing, staging)',
});
</script>It is the same installation you followed when you first installed Trackingplan. The only change is the environment variable in the init above.
- Note: The same goes for iOS and Android: just set the
environmentvariable in the init.
Once that's done, you'll see each environment documented in Trackingplan’s Dashboard and in automated digests (e.g. reports on your daily or weekly development cycles).
- Note: To use different environments with Segment, add the query parameter
&environment=<environment_name>to your webhook endpoint. For production, use PRODUCTION.
Connect your staging and testing environments and compare them with your baseline. You'll see what changed between one release and the next, and catch broken events or schemas before they ship. Any automated QA you already run, such as functional or non-functional regression testing (e.g. with Cypress), puts your analytics to work while Trackingplan watches.
So your current release testing also covers your analytics integrations, just by adding Trackingplan, with no change to your feature or test code.