<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Troy Fawkes</title>
	<atom:link href="https://www.troyfawkes.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.troyfawkes.com/</link>
	<description>Networking and Social Skills</description>
	<lastBuildDate>Mon, 08 Dec 2025 22:49:24 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>Learning How to use the ChatGPT API with Google Sheets &#038; Apps Script</title>
		<link>https://www.troyfawkes.com/learn-chatgpt-api/</link>
					<comments>https://www.troyfawkes.com/learn-chatgpt-api/#disqus_thread</comments>
		
		<dc:creator><![CDATA[Troy Fawkes]]></dc:creator>
		<pubDate>Sun, 05 May 2024 21:57:56 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://www.troyfawkes.com/?p=1857</guid>

					<description><![CDATA[<p>I write articles like this as part of my learning process. I may not explain every concept because that’s not what I was learning while writing the article. If you like learning with me and can Google, “What is an API,” then this is the right place for you! If my rambling inspired you, connect &#8230;</p>
<p class="read-more"> <a class="" href="https://www.troyfawkes.com/learn-chatgpt-api/"> <span class="screen-reader-text">Learning How to use the ChatGPT API with Google Sheets &#38; Apps Script</span> Read More &#187;</a></p>
<p>The post <a href="https://www.troyfawkes.com/learn-chatgpt-api/">Learning How to use the ChatGPT API with Google Sheets &amp; Apps Script</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><a href="https://www.troyfawkes.com/wordpress/wp-content/uploads/2024/05/ai-in-google-apps-script-google-sheets.jpg"><img fetchpriority="high" decoding="async" width="1024" height="1024" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2024/05/ai-in-google-apps-script-google-sheets-1024x1024.jpg" alt="" class="wp-image-1879" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2024/05/ai-in-google-apps-script-google-sheets-1024x1024.jpg 1024w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2024/05/ai-in-google-apps-script-google-sheets-300x300.jpg 300w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2024/05/ai-in-google-apps-script-google-sheets-150x150.jpg 150w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2024/05/ai-in-google-apps-script-google-sheets-768x768.jpg 768w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2024/05/ai-in-google-apps-script-google-sheets.jpg 1200w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>I write articles like this as part of my learning process. I may not explain every concept because that’s not what I was learning while writing the article. If you like learning with me and can Google, “What is an API,” then this is the right place for you!  If my rambling inspired you, <a href="https://www.linkedin.com/in/troyboileau/">connect with me on LinkedIn</a> and hit me up with any thoughts! I’m always interested in quick chats where you’re not trying to sell me links!</p>
</blockquote>



<p><strong>Updated 2025-12-09</strong>: Just keeping the code up to date.</p>



<p>For about a year I taught an evening SEO course at HackerYou, now <a href="https://junocollege.com/">Juno College</a>, and I got to chat with the students and teachers attending the coding bootcamps. One of the assignments given to the development students was to connect to the <a href="https://publicapis.io/lcbo-api-api">LCBO API</a> to get information about different types of alcohol in Ontario. It’s taught because it is a super easy to use.</p>



<p>ChatGPT’s API is just as easy as the LCBO API. If a Juno College student with less than 3 months of total time programming can do it, so can we!</p>



<p>Both the LCBO and ChatGPT APIs are RESTful. I associate this type of API with not having a headache. So, good start!</p>



<p>Now, how hard is it to get onto the bleeding edge of technology?</p>



<h2 class="wp-block-heading">Google Sheets &amp; Google Apps Script</h2>



<p>Most of my programming starts here. Here’s the quick tutorial to get set up:</p>



<ol class="wp-block-list">
<li>Go to Google Drive and create a new Google Sheet.</li>



<li>In the menu, click “Extensions” and “Apps Script”</li>



<li>Change the code to:</li>
</ol>



<div class="hcb_wrap"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>function myFunction(name) {
  return &quot;Hello &quot; + name;
}</code></pre></div>



<ol start="4" class="wp-block-list">
<li>Hit <strong>Save Project to Drive</strong>.</li>



<li>Back in the sheet, in <strong>A1</strong>, enter your name. In <strong>A2</strong>, enter =myFunction(A1)</li>
</ol>



<p>Now you should see “Hello Troy” (or your name) as an output in <strong>A2</strong>.</p>



<figure class="wp-block-image size-full"><a href="https://www.troyfawkes.com/wordpress/wp-content/uploads/2024/05/apps-script-open.gif"><img decoding="async" width="710" height="591" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2024/05/apps-script-open.gif" alt="" class="wp-image-1871" /></a></figure>



<p>What we just did was write some code that takes in a value and outputs some different value. You’re a developer Harry!</p>



<p>What’s cool about Google Sheets and Apps Script is that, if you’re like me, this is your default environment anyway. And what we can do now is take any little piece of knowledge we have or learn about programming and apply it immediately. No complex setup, no environments, no installing or updating, we’re just good to go.</p>



<h2 class="wp-block-heading">Our First ChatGPT Call</h2>



<p>If you have a trusting friend with ChatGPT Plus, ask them to get your their API key. Otherwise, you have to do the following.</p>



<ol class="wp-block-list">
<li>Sign up for <a href="https://openai.com/chatgpt/pricing">ChatGPT Plus</a>. This is $20 USD / month.</li>



<li>Go to the <a href="https://platform.openai.com/settings/organization/billing/overview">Billing Overview</a> and <strong>Add to credit balance</strong> under Pay as You Go. You could add as little as $5 here really.
<ul class="wp-block-list">
<li>As of 2025-12-05, If you&#8217;re going to do this a lot with non-sensitive data, you can get a large number of free tokens if you allow OpenAI to see your requests and completions. You can trade Big Brother over your shoulder for free experimentation. </li>
</ul>
</li>



<li>Under <a href="https://platform.openai.com/api-keys">API Keys</a>, click <strong>Create new secret key</strong> and copy it down. It should look something like: sk-proj-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.</li>
</ol>



<p>Great, now let’s write our first ChatGPT call!</p>



<p>Back in the Apps Script window, delete all of the code and replace it with this and save it:</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>const AIAPIKEY = &quot;{{PASTE YOUR API KEY HERE}}&quot;;

function hit_ai(system_prompt,user_prompt) {
    var requestOptions = {
      &quot;method&quot;: &#39;POST&#39;,
      &quot;headers&quot;: {
        &quot;Content-Type&quot;: &quot;application/json&quot;,
        &quot;Authorization&quot;: `Bearer ${AIAPIKEY}`
      },
      &quot;payload&quot;: JSON.stringify({
        &quot;model&quot;: &#39;gpt-5-nano&#39;,
        &quot;messages&quot;:[
          {&quot;role&quot;: &quot;system&quot;, &quot;content&quot;: system_prompt},
          {&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: user_prompt}
        ],
        &quot;max_completion_tokens&quot;:500
      })
    };

  var response = UrlFetchApp.fetch(&quot;https://api.openai.com/v1/chat/completions&quot;, requestOptions);
  if (response.getResponseCode() !== 200) {
    Logger.log(response.getContentText());
    throw new Error(&quot;aiRequest Failed: &quot; + response.getContentText());
  }
  
  response = JSON.parse(response);

  return response.choices[0].message.content;
}

function animal_or_fruit_ai(text) {
  var system_prompt = `You will respond only with Animal, Fruit, or Neither.`
  var user_prompt = `${text}`;

  return hit_ai(system_prompt, user_prompt);
}</code></pre></div>



<p>First we’ve defined our API key.</p>



<p><strong>Make SURE you replaced that text with your actual bought or borrowed API key.</strong></p>



<p>Then we’re building a function called <strong>hit_ai</strong> which accepts a system and user prompt, and then passes those on to ChatGPT and returns the response.</p>



<p>Lastly we’ve built a function called <strong>animal_or_fruit_ai</strong>. If you give it some text, it passes it onto ChatGPT and ChatGPT will tell us if what we entered was an animal, or a fruit.</p>



<p>When we&#8217;re building queries in the future we&#8217;ll likely make <strong>hit_ai</strong> a lot more robust and snazzier, and then all we&#8217;ll be changing is the function equivalent to <strong>animal_or_fruit_ai</strong> when we need to. That should take 5-10 minutes every time you need to solve a big problem!</p>



<p>In your spreadsheet:</p>



<ol class="wp-block-list">
<li>In column A, write out some names of animals, fruits, or something random.</li>



<li>In B1, enter: =animal_or_fruit_ai(A1)</li>



<li>Fill B1 down to the last row in which you have data in column A.</li>
</ol>



<p>You should be getting results like this, where our ChatGPT function has correctly classified the words we added in column A:</p>



<figure class="wp-block-image size-full"><a href="https://www.troyfawkes.com/wordpress/wp-content/uploads/2024/05/animal_or_fruit.gif"><img decoding="async" width="710" height="591" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2024/05/animal_or_fruit.gif" alt="" class="wp-image-1872" /></a></figure>



<p>Just to show you how amazing this is already, let&#8217;s duplicate this function to return a sentiment analysis by just altering the prompt.</p>



<p>Add this code at the bottom:</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>function sentiment_analysis_ai(text) {
  var system_prompt = `You will respond only with Positive, Negative, or Neutral. This represents the sentiment in the provided text.`
  var user_prompt = `${text}`;

  return hit_ai(system_prompt, user_prompt);
}</code></pre></div>



<p>And try it on a couple of sample texts:</p>



<figure class="wp-block-image size-full"><a href="https://www.troyfawkes.com/wordpress/wp-content/uploads/2024/05/sentiment_analysis.gif"><img loading="lazy" decoding="async" width="710" height="252" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2024/05/sentiment_analysis.gif" alt="" class="wp-image-1873" /></a></figure>



<p>So&#8230; Here we&#8217;re doing bulk sentiment analysis just by changing a line of text. We&#8217;re not even really coding.</p>



<p>This is a very quick and very dirty example, but now I can do to spreadsheet data what I could have done in a ChatGPT chat.</p>



<h2 class="wp-block-heading">More Complex ChatGPT API Queries</h2>



<p>I used this learning to solve a real business problem, taking in over 240,000 characters of information to rename 150 products using detailed descriptions and meta data. It took a couple of hours of figuring things out, and 2 minutes for ChatGPT to run.</p>



<p>&#8230; But I can&#8217;t show you that; so let&#8217;s instead <strong>write SEO-Friendly Title Tags for each of these product and category pages</strong>. This is crude and for example use only.</p>



<p>To follow along, use spreadsheet data that looks like this:</p>



<div id="wp-block-themeisle-blocks-accordion-6a890ccc" class="wp-block-themeisle-blocks-accordion exclusive">
<details class="wp-block-themeisle-blocks-accordion-item"><summary class="wp-block-themeisle-blocks-accordion-item__title"><div>Spreadsheet Data</div></summary><div class="wp-block-themeisle-blocks-accordion-item__content">
<figure class="wp-block-table"><table><tbody><tr><td>Page Name</td><td>Internal Description</td><td>Page Category</td><td>Keywords</td></tr><tr><td>Anvil</td><td>The quintessential tool of the aspiring prankster, the ACME Anvil embodies durability and gravity-defying impact. Crafted from the finest iron alloys, this timeless classic promises a symphony of clangs and a crescendo of laughs. Whether you&#8217;re plotting the ultimate gag or in dire need of swift justice, the ACME Anvil delivers with unwavering reliability. From surprise birthday parties to impromptu talent shows, let the weight of this iconic device elevate your comedic genius to new heights.</td><td>Product</td><td>Anvil for sale (250)<br>Buy Anvil online (180)<br>Heavy-duty Anvil (120)<br>Cartoon Anvil (90)<br>Prank Anvil (70)<br>ACME Anvil (200)<br>Anvil for gags (50)<br>Anvil for pranks (40)<br>Durable Anvil (110)<br>Anvil with free shipping (150)</td></tr><tr><td>Rocket Powered Roller Skates</td><td>Strap in and brace for exhilaration with the ACME Rocket Powered Roller Skates. Engineered for thrill-seekers and adventurers alike, these skates redefine the boundaries of speed and excitement. Powered by cutting-edge rocket propulsion technology, each stride propels you into a whirlwind of adrenaline-fueled velocity. Whether you&#8217;re chasing after a fleeting moment of glory or simply outrunning your mundane routine, these skates are your ticket to boundless escapades.</td><td>Product</td><td>Rocket Roller Skates (300)<br>Buy Rocket Skates (180)<br>Rocket Powered Skates (250)<br>ACME Rocket Skates (220)<br>Speedy Roller Skates (110)<br>High-speed Skates (90)<br>Rocket-powered Wheels (80)<br>Roller Skates for sale (200)<br>Thrill-seeking Skates (150)<br>Rocket Skates online (170)</td></tr><tr><td>Giant Kite Kit</td><td>Soar to new heights of fun and adventure with the ACME Giant Kite Kit. Designed to ignite imaginations and elevate leisure time, this kit is your gateway to the skies. Crafted from lightweight yet durable materials, each component is meticulously engineered to withstand gusts and glides effortlessly through the air. Whether you&#8217;re a novice dreamer or a seasoned kite enthusiast, the ACME Giant Kite Kit promises endless hours of airborne excitement and unforgettable memories.</td><td>Product</td><td>Giant Kite for sale (200)<br>Buy Giant Kite online (150)<br>ACME Kite Kit (180)<br>High-flying Kite (120)<br>Kite Kit for beginners (90)<br>Outdoor Kite Kit (100)<br>Kite Kit with string (80)<br>Easy-to-fly Kite (110)<br>Giant Kite with handle (70)<br>Kite Kit assembly (60)</td></tr><tr><td>Artificial Rock</td><td>Transform your landscape into a rugged oasis with the ACME Artificial Rock. Crafted with meticulous attention to detail, each rock exudes the timeless charm of nature&#8217;s handiwork. Whether you&#8217;re concealing unsightly utilities or creating a captivating focal point, these faux rocks blend seamlessly into any environment. Made from weather-resistant materials, they withstand the test of time and the elements, ensuring years of aesthetic enhancement for your outdoor space.</td><td>Product</td><td>Artificial Rock for landscaping (180)<br>Buy Artificial Rock online (140)<br>ACME Rock (160)<br>Faux Rock for sale (120)<br>Outdoor Rock decor (90)<br>Weather-resistant Rock (110)<br>Garden Rock cover (80)<br>Realistic Artificial Rock (100)<br>Rock disguise (70)<br>Rock camouflage (60)</td></tr><tr><td>Disguises</td><td>Embrace the art of deception with the ACME Disguises collection. Whether you&#8217;re plotting a prank or attending a masquerade ball, these clever disguises are your key to anonymity and amusement. From whimsical masks to elaborate costumes, each ensemble is meticulously crafted to conceal your identity while showcasing your creativity. Unleash your inner chameleon and embark on a journey of disguise and delight with ACME&#8217;s unparalleled selection of costumes and accessories.</td><td>Category</td><td>Disguises for sale (180)<br>Buy Disguises online (150)<br>ACME Disguise collection (170)<br>Costume Disguises (140)<br>Masked Disguises (110)<br>Female roadrunner disguises (90)<br>Party Disguises (120)<br>Fancy Dress Disguises (100)<br>Secret Agent Disguises (80)<br>Creative Disguises (70)</td></tr></tbody></table></figure>
</div></details>
</div>



<p>The parameters for our SEO friendly (ish) title tags are that they:</p>



<ul class="wp-block-list">
<li>Have to be under 60 characters in length</li>



<li>End with “ | ACME”</li>



<li>Use as many of the keywords in some variations as possible, with the top keywords being the most important to be included.</li>



<li>Use Title Case.</li>



<li>Be easy to read for humans.</li>
</ul>



<p>So, let’s write our prompt and use some code to get this done.</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>function get_seo_title(pageName,description,category,keywords) {
  // If any variable is falsey just return nothing.
  if (!pageName || !description || !category || !keywords) {
    return &quot;&quot;;
  }

  var system_prompt = `We want to write SEO-Friendly Title Tags for each of these product and category pages. These Title Tags
- Have to be under 60 characters in length
- End with &quot; | ACME&quot;
- Use as many of the keywords in some variations as possible, with the top keywords being the most important to be included.
- Use Title Case.
- Be easy to read for humans.`
  var user_prompt = `
  Page Name: ${pageName}
  Description: ${description}
  Category: ${category}
  Keywords: ${keywords}
  `;

  return hit_ai(system_prompt, user_prompt);
}</code></pre></div>



<p>This is what I get (I’ve run this a couple times to get different issues. <strong>Note: This was from GPT-3.5 turbo, newer models will do better!</strong>):</p>



<figure class="wp-block-table"><table><tbody><tr><td>Page Name</td><td>Title</td></tr><tr><td>Anvil</td><td>&#8220;Buy ACME Anvil Online for Heavy-Duty Gags | ACME&#8221;</td></tr><tr><td>Rocket Powered Roller Skates</td><td>&#8220;ACME Rocket Roller Skates for Sale&#8221;</td></tr><tr><td>Giant Kite Kit</td><td>Title Tag: Buy Giant Kite Kit Online for High-Flying Fun | ACME</td></tr><tr><td>Artificial Rock</td><td>&#8220;ACME Artificial Rock for Landscaping | ACME&#8221;</td></tr><tr><td>Disguises</td><td>1. Buy Disguises Online | ACME<br>2. ACME Disguise Collection for Sale | ACME<br>3. Creative Costume Disguises | ACME<br>4. Party &amp; Fancy Dress Disguises | ACME<br>5. Masked &amp; Secret Agent Disguises | ACME<br>6. Female Roadrunner &amp; Creative Disguises | ACME</td></tr></tbody></table></figure>



<p>There are lots of problems already.</p>



<ol class="wp-block-list">
<li>The length is often much shorter than 60 characters.</li>



<li>The ending isn’t consistent.</li>



<li>The result is wrapped in quotation marks.</li>



<li>The result is provided with “Title Tag:” at the beginning</li>



<li>Multiple responses are provided.</li>
</ol>



<p>Let’s try to resolve all of these.</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>function get_seo_title(pageName,description,category,keywords) {
  var system_prompt = `We want to write SEO-Friendly Title Tags for each of these product and category pages. These Title Tags
- Have to be under 53 characters in length but no shorter than 45 characters.
- Prioritized from top down, use as many of the words in the provided Keywords as possible. E.g. if &quot;buy rocket-skates online&quot; is the first keyword, use each of &quot;buy&quot; &quot;rocket-skates&quot; and &quot;online&quot; once in the title.
- Use Title Case.
- Be easy to read for humans.

Respond with three variations using only RFC8259 compliant JSON in this format including the character count and a selected best variation with the closest character count and solution:
[
  {
    &quot;TitleTagVar1&quot;: {
      &quot;text&quot;: &quot;Buy Giant Kite Kit Online for High-Flying Fun&quot;,
      &quot;chars&quot;: 45
    },
    &quot;TitleTagVar2&quot;: {
      &quot;text&quot;: &quot;Buy Giant Kite Kit Online: High-Flying Kite Kit for Sale&quot;,
      &quot;chars&quot;: 56
    },
    &quot;TitleTagVar3&quot;: {
      &quot;text&quot;: &quot;Buy Giant Kite Kit Online: Outdoor Kite Kit for Sale&quot;,
      &quot;chars&quot;: 52
    },
    &quot;bestVar&quot;: &quot;TitleTagVar2&quot;
  }
]`;

  var user_prompt = `
  Page Name: ${pageName}
  Description: ${description}
  Category: ${category}
  Keywords: ${keywords}
  `;

  var response = JSON.parse( hit_ai(system_prompt, user_prompt) );
  var bestVarKey = response[0].bestVar;
  var bestTitleTag = response[0][bestVarKey].text;
  return bestTitleTag + &quot; | ACME&quot;;
}</code></pre></div>



<p>Here’s the response:</p>



<figure class="wp-block-table"><table><tbody><tr><td>Page Name</td><td>Title</td></tr><tr><td>Anvil</td><td>Buy ACME Anvil Online: Heavy-Duty Anvil for Sale | ACME</td></tr><tr><td>Rocket Powered Roller Skates</td><td>High-speed Rocket Roller Skates for Sale Online | ACME</td></tr><tr><td>Giant Kite Kit</td><td>Buy Giant Kite Kit Online: High-Flying Fun for Sale | ACME</td></tr><tr><td>Artificial Rock</td><td>Buy Realistic Artificial Rock Online: ACME Garden Decor | ACME</td></tr><tr><td>Disguises</td><td>Buy ACME Disguises Online: Costume &amp; Masked Disguises | ACME</td></tr></tbody></table></figure>



<p>None of the previous issues have arisen. Here’s what changed:</p>



<ol class="wp-block-list">
<li>The length is often much shorter than 60 characters.
<ol class="wp-block-list">
<li>ChatGPT and AI in general seems to suck at hitting exact character counts. Asking for three variations doesn’t exactly or always hit it, but it does let the AI think a bit more step-wise and then evaluate its own work and suggest the best outcome.</li>
</ol>
</li>



<li>The ending isn’t consistent.
<ol class="wp-block-list">
<li>Any consistent elements I’ve switched to manually adding. Here I removed 7 characters from the character count target and then appended the desired characters myself at the end.</li>
</ol>
</li>



<li>The result is wrapped in quotation marks.
<ol class="wp-block-list">
<li>For formatting and character wrapping etc. I really like just forcing JSON as a response type, it’s eloquent and generally keeps undesirable characters out.</li>
</ol>
</li>



<li>The result is provided with “Title Tag:” at the beginning
<ol class="wp-block-list">
<li>Again with JSON as a solution. The AI likes to sometimes tag its answers even if you’re pretty specific about the format you want your response in. With JSON it’s tagged already.</li>



<li>I also used something called “Few Shot Training” here where I provided example responses in the format that I like.</li>
</ol>
</li>



<li>Multiple responses are provided.
<ol class="wp-block-list">
<li>In this case I’ve specified the format and the number of responses I want. Actually if the AI makes a mistake and provides titleTagVar8 the code would still work.</li>
</ol>
</li>
</ol>



<h2 class="wp-block-heading">ChatGPT API Tips &amp; Tricks</h2>



<p>Here were my biggest take-aways from my learning so far as it relates to what we covered here:</p>



<ul class="wp-block-list">
<li><strong>Default to JSON</strong>: Request every response to come in as JSON, even if I just want one response. It solves a lot of problems before they even arise, so I’m just defaulting to this for now.</li>



<li><strong>Specify Format</strong>: Include the response format exactly as you want it to appear, don’t just ask for JSON.</li>



<li><strong>Include Examples</strong>: Provide “Few Shot Training” (examples) in the prompt. To save space, include the examples in the prompt where you’re including the response format.</li>



<li><strong>Multiple Attempts</strong>: Let ChatGPT try several times and pick its best solution. It’s fast and cheap to get multiple responses. Assume that it “thinks on paper,” so the selection of the best solution has to be last.</li>



<li><strong>Use Code Checks</strong>: Use code where necessary and have ChatGPT try again. Not included in the example above, but if you regularly get specific issues, use your code to check for them and resubmit the request to the API and hope the next one works. Some quick examples:
<ul class="wp-block-list">
<li>Making claims. “Free Shipping,” “Same Day Delivery,” etc. come up pretty often in marketing-related queries. If they don’t apply in your situation, I’d ask to exclude them via the prompt but also use code to remove them as they’re a big no-no.</li>



<li>I’ve had “NoArgsConstructor” come in as a response for whatever reason.</li>



<li>Character count is a huge issue when it’s relevant. If it comes up a lot I’d add more steps to the request (give me 10 for example) and just check the character count in my code for the best response and send it back if it’s still too far off.</li>



<li>I sometimes use variables in my example format, e.g. “text&#8221;: &#8220;{{TEXT HERE}}&#8221;, and sometimes ChatGPT (especially 3.5) literally just returns {{TEXT HERE}}.</li>
</ul>
</li>



<li><strong>Cheapest Required Model</strong>: Use the lowest required GPT. This whole article is using 3.5 Turbo, and it would not have benefited greatly from using 4.0.</li>
</ul>



<h2 class="wp-block-heading">ChatGPT API Pricing &amp; Costs</h2>



<p>At the time of writing, pricing was $0.05 / 1M tokens for the prompt and $0.40 / 1M tokens for the completion (output) for gpt-5-nano. You can see how many tokens were used in a particular query in the object that it returns.</p>



<p>To keep this concise, I’ve been using the API for a month and made hundreds of queries, frequently with a lot of data provided and text in the prompt passed back and forth. I’ve spent a grand total of $0.08.</p>



<p>ChatGPT is dirt cheap for what it does, so much so that I’d encourage looking for ways to replace other APIs you use, as long as some hallucination won’t kill you. Try asking about:</p>



<ul class="wp-block-list">
<li><strong>Weather data</strong>: Respond in JSON with 1 or 0 for each day of March 2025 that it rained for most of the day in the GTA.</li>



<li><strong>Currency Conversion</strong>: Respond in JSON with monthly currency conversion data from CAD to USD for 2025.</li>



<li><strong>Map Data</strong>: Respond in JSON with the latidude and longitude map boundary coordinates for The Junction neighbourhood in Toronto.</li>



<li><strong>Travel Time Data</strong>: Respond in JSON with the walking time from 1 Yonge St, Toronto, ON M5E 1E5 to each of: a grocery store, a park, a subway station.</li>
</ul>



<p>I imagine that, frequently, this data can be cheaper and more accessible than getting it via specific APIs.</p>



<h2 class="wp-block-heading">What’s Next?</h2>



<p>I’ll be working on learning and writing about these two techniques:</p>



<ul class="wp-block-list">
<li><strong>Prompt Chaining</strong>: Writing a prompt and feeding its response into another. Ideally here I want to go a bit absurd, like chaining 5 prompts and responses together, or getting a hyper accurate solution to a problem that’s generally challenging for AI.</li>



<li><strong>Fine Tuning / Training</strong>: Training a model with 50-100 examples of prompts and desirable and undesirable responses to get a better outcome from a prompt. I really want to learn the whole process of testing the accuracy of the responses, adding human validation and building a system to feed the human-validation back into the example prompts and model training. I especially want to come up with some benchmark numbers in my head for how many examples I’d need in a new project, how many times I’d need to run it (epochs?) and how much it would cost to train a model for a given task.</li>
</ul>



<p>I don’t have a newsletter, so if this article inspired you, <a href="https://www.linkedin.com/in/troyboileau/">connect with me on LinkedIn</a> and hit me up with any thoughts! I’m always interested in quick chats where you’re not trying to sell me links!</p>
<p>The post <a href="https://www.troyfawkes.com/learn-chatgpt-api/">Learning How to use the ChatGPT API with Google Sheets &amp; Apps Script</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.troyfawkes.com/learn-chatgpt-api/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>The Six Hour Work Day, Thirty Hour Work Week</title>
		<link>https://www.troyfawkes.com/six-hour-work-day/</link>
					<comments>https://www.troyfawkes.com/six-hour-work-day/#disqus_thread</comments>
		
		<dc:creator><![CDATA[Troy Fawkes]]></dc:creator>
		<pubDate>Fri, 23 Sep 2022 15:55:46 +0000</pubDate>
				<category><![CDATA[Management]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://www.troyfawkes.com/?p=1772</guid>

					<description><![CDATA[<p>After over five years of running Delta Growth, a Toronto-based digital marketing agency with a six hour work day and twenty full time employees, I feel very confident in saying that this was a hilariously easy gift for my business partner and I to give our team. I know that from the outside the six &#8230;</p>
<p class="read-more"> <a class="" href="https://www.troyfawkes.com/six-hour-work-day/"> <span class="screen-reader-text">The Six Hour Work Day, Thirty Hour Work Week</span> Read More &#187;</a></p>
<p>The post <a href="https://www.troyfawkes.com/six-hour-work-day/">The Six Hour Work Day, Thirty Hour Work Week</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><a href="https://www.troyfawkes.com/wordpress/wp-content/uploads/2022/09/6-hour-work-day-1.png"><img loading="lazy" decoding="async" width="1024" height="1024" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2022/09/6-hour-work-day-1-1024x1024.png" alt="" class="wp-image-1807" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2022/09/6-hour-work-day-1-1024x1024.png 1024w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2022/09/6-hour-work-day-1-300x300.png 300w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2022/09/6-hour-work-day-1-150x150.png 150w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2022/09/6-hour-work-day-1-768x768.png 768w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2022/09/6-hour-work-day-1.png 1200w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p>After over five years of running Delta Growth, a Toronto-based digital marketing agency with a six hour work day and twenty full time employees, I feel very confident in saying that this was a hilariously easy gift for my business partner and I to give our team. I know that from the outside the six hour work day may seem extreme, unlikely, or something that would never happen in our lifetimes.</p>



<p>Let&#8217;s talk about how and why we&#8217;ve used the six hour work day for over five years.</p>



<pre class="wp-block-verse">This article is part of a series on <a href="https://dg.agency/">Delta Growth</a>, a 20 FTE digital marketing agency I founded in 2017 with Brendan Philp, which I successfully exited in 2022. I'm writing this for my younger self, who, like you, had great intentions and talent and probably would have benefited from some of these ideas.

<strong>Hey! I'm actively looking for a new home as a marketing executive (Director / VP of Digital, Growth or Demand Gen) for a company that is passionate about enriching human lives. If that's you, <a href="mailto:troy@troyfawkes.com">say hi</a>.</strong>

Have questions or interested in more articles like this? Connect with me on <a href="https://www.linkedin.com/in/troyboileau/">LinkedIn</a>.</pre>



<h2 class="wp-block-heading">Why did we choose a six hour work day?</h2>



<p>First off let&#8217;s talk about the traditional, forty hour work week, employee / employer agreement. Eight hours a day, five days a week. Each hour is either productive or part of a legally mandated break.</p>



<p>I don&#8217;t know about you but I&#8217;ve never been able to fulfil this agreement.</p>



<p>There was a time in my life where I came close, going from intern to managing six employees and around $3M in ARR for a digital marketing agency and building their SEO and CRO practices over three years. But even then I balanced my ten and twelve hour days with weeks where I could barely scrape coherent thoughts together for two or three hours a day. It wouldn&#8217;t surprise me if, even then, I was averaging three to four productive hours a day even if it felt like I was being overrun.</p>



<p>I&#8217;m fairly sure that all of us&#8211;employers, managers, employees, the cat sitting in your lap&#8211;acknowledge that the reality is that the average office worker puts in much, much less than the eight productive hours that we agreed to. This is not an unstudied belief:</p>



<ul class="wp-block-list"><li>A <a href="https://www.vouchercloud.com/resources/office-worker-productivity">study by Vouchercloud</a> in 2016 suggests that <strong>we work productively for as few as two hours and 23 minutes </strong>a day.</li><li><a href="https://news.wisc.edu/driven-to-distraction-what-causes-cyberloafing-at-work/">A study by Wisconsin School of Business suggests</a> that number could be four and a half hours, and <a href="https://autonomy.work/wp-content/uploads/2021/06/ICELAND_4DW.pdf">Iceland</a> showed that <strong>even a small reduction of weekly hours (40 to 35) showed an <em>increase</em> in productivity</strong>.</li></ul>



<p>It sure seems like my gut, my personal experience, my management experience, and my research all line up: <strong>we don&#8217;t work eight hours a day productively</strong>.</p>



<p>So what do we do with this information?</p>



<p>I think that all relationships should be built on clearly defined, well thought out, evolving expectations and boundaries rather than assumptions and the status quo. The employee / employer relationship is no exception.</p>



<p>When I started Delta Growth, I didn&#8217;t want to build the foundation of my relationship with my team on a lie. The team wasn&#8217;t going to work eight hours a day, and I didn&#8217;t expect them to. Switching from an eight hour work day to a six hour one felt like moving expectations in line with reality.</p>



<p>It felt both like the <strong>right</strong> thing to do, and the <strong>kind</strong> thing to do.</p>



<h2 class="wp-block-heading">How did we still make money?</h2>



<p>Marketing agencies belong to a general category of &#8220;Services&#8221; businesses. We sell employee time for money. <a href="https://www.askcody.com/blog/advertising-agency-profitability-field-guide">Agencies make somewhere between 10% and 40% profit</a>, much less than, say, <a href="https://onplan.co/blog/what-are-the-net-profit-margins-of-a-saas-company-startup/">SaaS, which is between 70% and 80%</a>. So, we don&#8217;t have a ton of margin to begin with. There&#8217;s no giant slush fund of &#8220;Founder Money&#8221; that we can pull from in order to hand wave this whole 25% reduction in billable hours away.</p>



<p>We&#8217;re essentially left with a 25% deficit that we need to make up in the ways available to all agencies. A lot of these are available to any marketing team, or to any business at all.</p>



<ul class="ticss-c9a896ea wp-block-list"><li>We didn&#8217;t <strong>lie</strong>. Almost every company that I&#8217;ve worked for, agency or otherwise, has required that I logged at least 40 hours before they approved my paycheck. Most companies asked me to have at least 80% billable hours. In a marketing agency context, this would mean that even though my employees may have been reading articles, watching videos or playing with their dogs, they would be calling that &#8220;billable time on Project Y.&#8221; Even if it&#8217;s not &#8220;billable time,&#8221; time sheets were intended as HR reporting for planning purposes and were, at the very least, misleading due to this process.<br><br>Delta Growth did not do this, and I think the value of our hourly rate increases significantly here compared to our competition.</li><li>We didn&#8217;t use <strong>value based pricing</strong>. This is the practice of charging based on the value of the delivered product rather than some factor of time spent.</li><li>We did <strong>increase our price</strong>. Essentially we increased our hourly rate by 15% compared to where we saw the industry average. This is such an odd sliding scale in practice, though, because our &#8220;blended rate&#8221; or the average billable rate has stayed the same for 5 years, we haven&#8217;t corrected our pricing for inflation. I feel like this increase in price wasn&#8217;t actually required, and it&#8217;s more a factor of our quality of work being worth the price. Also we should probably increase our blended rate!</li><li>We did focus on <strong>quality, strategy-driven solutions</strong>. In solution selling or challenger selling, there&#8217;s a lot of discussion of what the client needs. This often leads to sales and contracts being sometimes detached from <span style="text-decoration: underline;">what the company can offer</span>. We made sure that the work that we took&#8211;and therefore fees&#8211;were governed by what we could genuinely offer with a clear understanding of our processes, frameworks, strategists, specialists and resources available.</li><li>We did <strong>increase task efficiency</strong>. If we reduce re-work and make executing and delivering tasks easy and clear, we&#8217;re more efficient. I&#8217;ve worked with four marketing agencies and seen the insides of a dozen more. SOPs, frameworks for key structures like strategy, tactics, execution, or any key subject matter expertise were almost completely non-existent in most cases. Strategy was not tied to tactics or hours, and as such couldn&#8217;t realistically be prioritized. Strategists and managers weren&#8217;t trained, there were just promoted. Project management was ad hoc, &#8220;per my last email, please rebuild client website by EOD.&#8221;<br><br>We built SOPs, streamlined frameworks for major repetitive activities, invested in Process over Practice, invested significantly in training, put a large focus on getting strategy and management right, and are religiously involved with project management (hey PM team!).</li><li>We did drastically <strong>reduce emergencies</strong> and <strong>churn</strong>. Much of what makes us efficient also reduced emergencies and fires. Primarily in clients where we didn&#8217;t have to panic every other day because of poor work product going out the door, or being delivered late. This both reduced re-work, unbillable spent time putting out fires that we had set, and client churn because of these issues. Where I&#8217;ve seen emergencies being almost omni-present, at Delta Growth it was a shock every time one came up, and something we would make sure didn&#8217;t happen again.</li><li>We did reduce <strong>employee turn-over</strong>. I believe that clear expectations, solid training and the ability to negotiate their workload helped our team want to stick around. Lack of project management and a belief that the eight hour day is all productive hours seems to force unrealistic expectations on the team which leads to no one winning.</li><li>We did increase <strong>junior hiring and training</strong> programs. Over time our internal billable rate crept up because we were hiring, training and promoting our amazing team. This started me on the track of our junior program and then launching an intensive (yes, well paid and well trained) intern program, both of which have brought in fantastic people. With the right training these folks shot into the lower intermediate bracket fairly quickly and then needed a bunch of time to grow in repetitive practical experience, but this helped us bring our internal billable rate back down to good levels.</li></ul>



<p>At the end of the day we&#8217;ve lived healthily in the range of a profitable marketing agency for over five years without a single month in the red.</p>



<h2 class="wp-block-heading">What did I learn?</h2>



<p>I came into the six hour work day thinking that it was one of the kindest decisions I could make for my team. Part of me saw it as an insurmountable difference between us and our competition with regards to staff&#8211;I&#8217;ve worked grueling days, weeks, and months with other marketing agencies where I&#8217;d be up until after midnight poking around the snack wall that was supposed to make me feel better about sacrificing my time when we ran into planning, delegation, hiring, or sales issues. I figured, this six hour work day is going to make us so unreachable with regards to hiring and retention that our advantage would blow everyone else out of the water. That&#8217;s a bit of an exaggeration, but it paints a picture.</p>



<p>My greatest intention was to be kind, but part of me always had that thought&#8211;I&#8217;ve ground myself down to the bone for other people, surely not asking people to do the same for me was an amazing gift! Yeah, it rings a bit hollow now that I write it out.</p>



<p>I learned that the six hour work day was this:</p>



<ul class="wp-block-list"><li>Being more <strong>truthful</strong> in our relationship with our team.</li><li>Allowing valued team members to protect their <strong>healthy boundaries</strong>, not pushing those midnight bone grinding sessions on them.</li><li>Taking <strong>responsibility for management</strong> issues like resourcing and (in our case) sales rather than pushing those problems into this nebulous bucket of &#8220;employees aren&#8217;t working their full 40 hour weeks, just give it to them!&#8221;</li></ul>



<p>Our expectations out of the gate with employees were slightly more in line with reality. Our billable hours to clients are much more truthful both with the six hour work day and because of our project management system. Our resourcing estimates and planning are much more accurate.</p>



<p>Overall, we all wound up happier.</p>



<p>Would I do it again? <strong>In a heartbeat</strong>.</p>



<p>Many of the lessons that I learned in running Delta Growth had the six hour work day as a catalyst. You might have noticed that it spurred us into better management, better project management, better task delegation, better sales, better strategy, better SOPs, and more. I&#8217;ll be slowly writing out some of these experiences as I go. If you&#8217;re interested in following these thoughts, follow me on <a href="https://www.linkedin.com/in/troyboileau/">LinkedIn</a>.</p>



<pre class="wp-block-verse">I've included a limited number of FAQs below. Feel free to <a href="https://www.linkedin.com/posts/troyboileau_problems-caused-by-our-six-hour-work-day-activity-6979107999294345216-FRfG?utm_source=share&amp;utm_medium=member_desktop">comment on the LinkedIn thread</a> with questions or thoughts and I'll try to include more details or what I gather from the thread in these FAQs below!</pre>



<h2 class="wp-block-heading">Advice &amp; FAQs</h2>



<div id="wp-block-themeisle-blocks-accordion-d0633016" class="wp-block-themeisle-blocks-accordion">
<details class="wp-block-themeisle-blocks-accordion-item"><summary class="wp-block-themeisle-blocks-accordion-item__title"><div>Has a client ever expressed concern over the six hour work day?</div></summary><div class="wp-block-themeisle-blocks-accordion-item__content">
<p>I&#8217;ve heard clients ask about after hours support, but I haven&#8217;t heard anything about the six hour day. My cofounder and I would hop on calls once in a while after hours to handle issues, and if something really blew up (maybe once every six months?) we might need a media specialist to hop on for an hour after 4pm to pause or fix ad campaigns. I think if fires were higher frequency we&#8217;d need some kind of after hours support structure, but again that&#8217;s why we try to avoid them in the first place.</p>



<p>I didn&#8217;t always mention the six hour work day to clients but when I do it&#8217;s in the context of getting all of their hours from a bright eyed, bushy tailed team, not a bleary-eyed beleaguered consultant who just logged forty hours on some other client&#8217;s project.</p>
</div></details>



<details class="wp-block-themeisle-blocks-accordion-item"><summary class="wp-block-themeisle-blocks-accordion-item__title"><div>Would you have made money money with an eight hour day than a six hour one?</div></summary><div class="wp-block-themeisle-blocks-accordion-item__content">
<p>I really don&#8217;t think so. I imagine that we would have had more turn-over (both in employees and clients) if anything.</p>



<p>I suspect that agencies and consultants that are currently committing fraud will lose money switching to a six hour day, because they won&#8217;t be able to ask employees to fill out forty hour time sheets. But uh&#8230; I mean&#8230; Good, right?</p>
</div></details>



<details class="wp-block-themeisle-blocks-accordion-item"><summary class="wp-block-themeisle-blocks-accordion-item__title"><div>What is the reaction from employees to the six hour work day?</div></summary><div class="wp-block-themeisle-blocks-accordion-item__content">
<p>Short version, I think it helps a lot with retention, but not by itself. Paired with the mindset that causes an entire organization to move towards a six hour work day and general efficiency up and down the chain and between teams, I think you really get the full results, again, on retention.</p>



<p>I don&#8217;t think it had a huge impact on hiring until we started getting more and more referral candidates. The reason I think this is is because we&#8217;ve all seen &#8220;unlimited vacation&#8221; companies that work their employees to the bone. Companies with chefs and a snack wall that need you there at 10pm for some arcane ritual. Bonuses that don&#8217;t get paid for reasons outside of your control.</p>



<p>I&#8217;ll try to solicit some of the team&#8217;s feedback in the LinkedIn thread where this is posted and share some screenshots, but you can imagine that that&#8217;ll be a bit biased!</p>
</div></details>
</div>
<p>The post <a href="https://www.troyfawkes.com/six-hour-work-day/">The Six Hour Work Day, Thirty Hour Work Week</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.troyfawkes.com/six-hour-work-day/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Switching to Google Tag Manager for Google Analytics</title>
		<link>https://www.troyfawkes.com/switching-to-google-tag-manager-for-google-analytics/</link>
					<comments>https://www.troyfawkes.com/switching-to-google-tag-manager-for-google-analytics/#disqus_thread</comments>
		
		<dc:creator><![CDATA[Troy Fawkes]]></dc:creator>
		<pubDate>Mon, 03 Jul 2017 00:48:39 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[SEO]]></category>
		<guid isPermaLink="false">https://www.troyfawkes.com/?p=1671</guid>

					<description><![CDATA[<p>Toronto seems to be falling in love with Analytics recently, so it seems like a good idea to put together a quick and dirty Google Tag Manager analytics implementation guide for marketers and developers. I&#8217;m not going to spend a lot of time explaining what, for example, an &#8220;event&#8221; is in Google Analytics; I&#8217;ll instead &#8230;</p>
<p class="read-more"> <a class="" href="https://www.troyfawkes.com/switching-to-google-tag-manager-for-google-analytics/"> <span class="screen-reader-text">Switching to Google Tag Manager for Google Analytics</span> Read More &#187;</a></p>
<p>The post <a href="https://www.troyfawkes.com/switching-to-google-tag-manager-for-google-analytics/">Switching to Google Tag Manager for Google Analytics</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Toronto seems to be falling in love with Analytics recently, so it seems like a good idea to put together a quick and dirty Google Tag Manager analytics implementation guide for marketers and developers.</p>
<p>I&#8217;m not going to spend a lot of time explaining what, for example, an &#8220;event&#8221; is in Google Analytics; I&#8217;ll instead refer you to useful resources. I&#8217;m going to focus both of our times on knowing how to fully configure Google Analytics in Google Tag Manager.</p>
<p>We&#8217;ll cover:</p>
<ol>
<li><a href="#intro-to-gtm">An Intro to Google Tag Manager</a></li>
<li><a href="#intro-data-layer">An Intro to the Data Layer</a></li>
<li><a href="#why-use-gtm">Why to Use Google Tag Manager &amp; the Data Layer</a></li>
<li><a href="#basic-gtm-setup">The Basics of Setting Up Google Tag Manager</a></li>
<li><a href="#ga-snippet-in-gtm">The Google Analytics Snippet in Google Tag Manager</a></li>
<li><a href="#ga-pageviews">Analytics Pageviews in Google Tag Manager</a></li>
<li><a href="#ga-events">Analytics Events in Google Tag Manager</a></li>
<li><a href="#ga-users-cd">Google Analytics Users &amp; Custom Dimensions in Google Tag Manager</a></li>
<li><a href="#ga-ecommerce">Basic Google Analytics eCommerce Setup in Google Tag Manager</a></li>
</ol>
<p><a name="intro-to-gtm"></a></p>
<h2>An Intro to Google Tag Manager</h2>
<p>Google Tag Manager is Google&#8217;s Tag Management System (TMS). Tealium is a common alternative. Both are used to simplify the addition and management of tags on a website.</p>
<p>For example, a common setup for even the smallest marketing-enabled business includes adding 3-4 Google Analytics tracking tags, AdWords Remarketing and Conversion tags, and then generally two or three other codes such as Facebook, Optimizely, or maybe some fancy marketing automation or UX tools.</p>
<p>Generally, these are added piecemeal to the code of a website. If you asked a developer a year later which tags were currently on the site it&#8217;s unlikely that they would be able to give you a clear picture.</p>
<p>Enter Tag Management. Google Tag Manager (GTM) is a single tag that you add to the website. All other tags fire through GTM.</p>
<p><a name="intro-data-layer"></a></p>
<h2>An Intro to the Data Layer</h2>
<p>The Data Layer is a set of information that gets provided by your website to Google Tag Manager every time the two interact.</p>
<p>For example, I might want to tell GTM that the user is accessing my website while vital services are not working and that the user on the current page is not logged in. I could have a Data Layer that looks like the following:</p>
<pre class="">dataLayer.push({
 'serviceStatus': 'Down',
 'userStatus': 'notLoggedIn'
 });</pre>
<p>When we next interact with GTM the information in the Data Layer will be usable by any tag that we&#8217;ve configured. If we associate this information with Google Analytics custom dimensions, for example, we could view a report of the experience of users who accessed the site while our services were down or compare users who were logged in versus users who were not.</p>
<p><a name="why-use-gtm"></a></p>
<h2>Why to Use Google Tag Manager &amp; the Data Layer</h2>
<p>I&#8217;m going to lead with the negatives:</p>
<ul>
<li>Google Tag Manager is big and scary. Kill it with fire.</li>
<li>The Data Layer is big and scary. Kill it with fire.</li>
</ul>
<p>The positives:</p>
<ul>
<li>Maintenance of tags becomes massively simplified.</li>
<li>Tagging can move outside of web release schedules.</li>
<li>Developers are required much less frequently.</li>
<li>Complexities of the website cause fewer complexities of tagging.</li>
<li>Data is collected once and can be shared among many tags.</li>
<li>Data collection conventions are extremely easy to follow and expand on.</li>
</ul>
<p>I also like to think that once you&#8217;ve finished this article you&#8217;ll feel that the two negatives aren&#8217;t really relevant. I couldn&#8217;t in good faith say that Google Analytics and Google Tag Manager require different training to work with, since&#8211;again&#8211;once you&#8217;ve finished reading this article you&#8217;ll be able to easily do things in GTM that you may have never even considered doing in GA alone.</p>
<p><a name="basic-gtm-setup"></a></p>
<h2>The Basics of Setting Up Google Tag Manager</h2>
<p>I&#8217;m going to assume that you don&#8217;t even have a Google Tag Manager account yet, that you&#8217;re using GTM on a website, and that you&#8217;re going to be using a single UA code within the view.</p>
<p>First off, head over to <a href="https://www.google.com/analytics/tag-manager/">the tag manager page</a> and either sign in or create a Google account. If you&#8217;ve already got an account you might see the dashboard view, which looks like this:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1672" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2017/07/gtm-dashboard.jpg" alt="" width="914" height="295" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2017/07/gtm-dashboard.jpg 914w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2017/07/gtm-dashboard-300x97.jpg 300w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2017/07/gtm-dashboard-768x248.jpg 768w" sizes="auto, (max-width: 914px) 100vw, 914px" /></p>
<p>Just click on &#8220;Create Account&#8221; if that&#8217;s the case.</p>
<p>Next, do this:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1673" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2017/07/gtm-setup.gif" alt="" width="794" height="506" /></p>
<p>It doesn&#8217;t really matter what values you put in, though &#8220;Web&#8221; is the selection you want.</p>
<p>Once you&#8217;ve agreed to the terms and conditions, a popup appears with the installation instructions. Specifically, you need to install the two sections of the Google Tag Manager code snippet in separate places. <a href="https://developers.google.com/tag-manager/quickstart">Here&#8217;s some documentation</a>.</p>
<p>Once the snippet is correctly placed, we&#8217;re good to go.</p>
<p><a name="ga-snippet-in-gtm"></a></p>
<h2>The Google Analytics Snippet in Google Tag Manager</h2>
<p>TLDR: This is a long-winded way to say, &#8220;you don&#8217;t have to set up the GA snippet in GTM.&#8221;</p>
<p>If you&#8217;re coming to GTM from GA, then you&#8217;ve been taught that GA needs to be set up via its &#8220;snippet&#8221; or &#8220;tracking code.&#8221; This thing:</p>
<pre class="">&lt;script&gt;
 (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), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-XXXXXXXX-X', 'auto');
 ga('send', 'pageview');
 &lt;/script&gt;</pre>
<p>It&#8217;s important to note that this snippet does three things.</p>
<ul>
<li>It adds a bunch of new functionality to your website, specifically as it relates to this &#8220;ga()&#8221; thing. If you&#8217;ve ever fired an event in GA before, you know it goes something like ga(&#8220;send&#8221;,&#8221;event&#8221;,&#8230;). Without the part of the snippet that adds functionality, you&#8217;d get an error trying to fire an event or do anything with the &#8220;ga()&#8221; function.</li>
<li>It connects that functionality to a specific analytics view.</li>
<li>It fires a pageview. It says, &#8220;someone has landed on this page,&#8221; and sends a bunch of data related to that page to your analytics profile.</li>
</ul>
<p>In Google Tag Manager, we don&#8217;t need to add &#8220;the analytics snippet&#8221; anywhere. The functionality and the connection to the analytics view occur within GTM itself. Pageviews, on the other hand, we need to track explicitly.</p>
<p><a name="ga-pageviews"></a></p>
<h2>Google Analytics Pageviews in Google Tag Manager</h2>
<p>In the previous section I said that we&#8217;re going to need to explicitly send Pageviews in Google Tag Manager, so here we are.</p>
<p>I&#8217;m going to derail this article briefly to introduce you to &#8220;variables,&#8221; which we&#8217;re going to take advantage of so that we never have to remember our UA code ever again.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1676" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2017/07/gtm-ua-variable-setup.gif" alt="" width="931" height="623" /></p>
<p>If you missed that:</p>
<ol>
<li>Click on Variables.</li>
<li>Click on New.</li>
<li>Name the variable UA Code.</li>
<li>Choose &#8220;Constant&#8221;.</li>
<li>Write in the UA Code that&#8217;s provided in Google Analytics.</li>
<li>Click Save.</li>
</ol>
<p>Next I&#8217;m going to do a combination of two things. I&#8217;m going to set up a variable that holds my entire Universal Analytics Configuration, and I&#8217;m going to fire a Pageview on all pages.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1678" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2017/07/gtm-pageview-setup.gif" alt="" width="931" height="623" /></p>
<p>If you missed that:</p>
<ol>
<li>Click on Tags.</li>
<li>Click on New.</li>
<li>Name the tag Universal Analytics Pageview.</li>
<li>Click in the Tag Configuration box.</li>
<li>Select Universal Analytics.</li>
<li>Select Page View in the Track Type dropdown.</li>
<li>Select New Variable in the Google Analytics Settings dropdown.</li>
<li>Name the variable Universal Analytics Configuration.</li>
<li>Put {{UA Code}} in the Tracking ID box.</li>
<li>Click Save.</li>
<li>Click in the Triggering box.</li>
<li>Select All Pages.</li>
<li>Click Save.</li>
</ol>
<p>I&#8217;ll get into a bit more detail about Triggers later, but for now I hope it&#8217;s fairly obvious. &#8220;All Pages&#8221; will trigger &#8220;Universal Analytics Pageview.&#8221; Basically, we&#8217;re sending a pageview every time a page is loaded, just like the standard GA snippet does.</p>
<p>If you don&#8217;t use Events, Custom Dimensions, Custom Metrics or eCommerce (which is entirely possible), you&#8217;ve now got a complete Google Analytics setup in Google Tag Manager. Congrats!</p>
<p>Before moving on you need to know that Google Tag Manager doesn&#8217;t make changes instantly to your website. You have to submit your changes. This also allows you to revert back to previous versions if ever you make a mistake. After every step in this tutorial, feel free to publish your changes.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1680" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2017/07/gtm-publishing-container.gif" alt="" width="931" height="623" /></p>
<p>If you missed that:</p>
<ol>
<li>Click Submit.</li>
<li>Name the changes &#8220;Pageviews Configured.&#8221;</li>
<li>Click Publish.</li>
</ol>
<p><a name="ga-events"></a></p>
<h2>Google Analytics Events in Google Tag Manager</h2>
<p>The next analytics task that businesses usually complete in Google Analytics is the firing of events. I&#8217;m going to show you two ways to do this, from the simplest to the most complex. Each way is effective, but in learning both we&#8217;ve got an opportunity to discover some Google Tag Manager trickery. Starting with Triggers.</p>
<h3>What are Google Tag Manager Triggers?</h3>
<p>Pretty much everything in GTM fits into three major categories:</p>
<ol>
<li>Tags, which are the things that happen, like a pageview being fired, or Optimizely being loaded.</li>
<li>Triggers, which are the scenarios in which a tag might fire, like a page being loaded or an event occurring on a web page.</li>
<li>Variables, which are pieces of information that we store in GTM until we need to refer to them elsewhere, like our UA Code variable that we set up earlier.</li>
</ol>
<p>An example of a trigger is when an event is fired on the website, so it fits nicely as part of our simplest form of event tracking. Let&#8217;s set up a really simple trigger.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1682" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2017/07/gtm-custom-event-trigger.gif" alt="" width="931" height="623" /></p>
<p>If you missed that:</p>
<ol>
<li>Click Triggers.</li>
<li>Click New.</li>
<li>Name the Trigger &#8220;contact-form-trigger.&#8221;</li>
<li>Click in the Trigger Configuration box.</li>
<li>Select Custom Event.</li>
<li>Add &#8220;contact-form-trigger&#8221; in the Event Name text box.</li>
<li>Click Save.</li>
</ol>
<p>This trigger will fire any time an event called &#8220;contact-form-trigger&#8221; is sent to GTM. But how do we send events to GTM?</p>
<p>That&#8217;s a good question!</p>
<h3>How to Send Events Using the Data Layer in Google Tag Manager</h3>
<p>Once you&#8217;ve set up Google Tag Manager, all events are sent to it through the Data Layer. This might sound scary, so instead of talking too much about it I&#8217;m going to show you the code that fires an event in GTM.</p>
<pre class="">&lt;script&gt;
 dataLayer.push({'event':'contact-form-trigger'});
&lt;/script&gt;</pre>
<p>NB: This code (and all event code I discuss hereafter) absolutely must be included after the GTM snippet.</p>
<p>Remember that ga(&#8216;send&#8217;,&#8217;event&#8217;, &#8230;) kind of code? This should look fairly similar. And it is. It&#8217;s just a lot more powerful now.</p>
<p>Let me take a brief moment to speak with the developers out there. When you load the GTM snippet, it overloads the push method on the dataLayer object. It listens for an &#8220;event&#8221; key being added. If an event key is added with any value, it will send the current state of the dataLayer object to Google Tag Manager. Contrary to how it appears, this code isn&#8217;t just adding an item to the object, it is actually sending information to the GTM service.</p>
<p>Uh&#8230; OK, back to everyone.</p>
<p>Now we&#8217;re sending an event to GTM called &#8220;contact-form-trigger&#8221; and we&#8217;ve got a trigger set up that fires any time GTM gets an event called &#8220;contact-form-trigger.&#8221; Unfortunately we&#8217;re not firing anything. And we&#8217;re starting to realize that Triggers fire Tags, so we should poke around our tags.</p>
<p>Let&#8217;s set that tag up really quickly:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1684" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2017/07/gtm-simplest-event.gif" alt="" width="931" height="623" /></p>
<p>If you missed that:</p>
<ol>
<li>Click on Tags.</li>
<li>Click New.</li>
<li>Name the tag, &#8220;UA Simplest Event.&#8221;</li>
<li>Click in the Tag Configuration box and selected Universal Analytics.</li>
<li>Change the Track Type to Event.</li>
<li>Write out a Category, Action and Label for the event.</li>
<li>Change the Google Analytics Settings to the variable we had set up before.</li>
<li>Click in the Triggering box.</li>
<li>Select the &#8216;contact-form-trigger&#8217;.</li>
<li>Click Save.</li>
</ol>
<p>Once we&#8217;ve Published this version of our container, we&#8217;ll have a working Analytics event. Hopefully it&#8217;s not quite as scary anymore. The whole process was:</p>
<ol>
<li>Add the dataLayer.push code to the website.</li>
<li>Create a Custom Event Trigger in GTM.</li>
<li>Create an Event, Universal Analytics Tag in GTM.</li>
</ol>
<p>Now, you might be thinking that this seems kind of limiting. You want to be able to send different Category, Action, Label or Value information every time you send an event. You&#8217;re also very lazy, and having a three step process seems silly when you could have a one step process.</p>
<p>Enter the complicated way of setting up events in GTM.</p>
<p>Here&#8217;s what we&#8217;re going to accomplish during this process:</p>
<ol>
<li>We&#8217;ll change our event code up on the website to support all of the GA event values such as Category, Action, etc.</li>
<li>We&#8217;ll store those values in GTM as Data Layer Variables.</li>
<li>We&#8217;ll set up a trigger that fires any time our event is sent.</li>
<li>We&#8217;ll set up a tag that fires on the trigger and sends in our custom variables.</li>
</ol>
<p>Let&#8217;s start by getting a bit of a better understanding of the Data Layer. When we sent our event, we did this:</p>
<pre class="">dataLayer.push({'event':'contact-form-trigger'});</pre>
<p>If you&#8217;re looking closely, the colon between &#8220;event&#8221; and &#8220;contact-form-trigger&#8221; is a form of association. The &#8220;event&#8221; that we&#8217;re firing is &#8220;contact-form-trigger.&#8221; We call associations like this &#8220;key-value pairs,&#8221; because on the left is the key, and on the right is the value.</p>
<p>The same relationship exists for Categories, Actions, Labels and Values for GA Events, where we could say that the category has a value of &#8220;Contact Form,&#8221; for example. In the Data Layer, we&#8217;d write out this relationship like so:</p>
<pre class="">dataLayer.push({
 'eventCategory':'Contact Form',
 'eventAction':'Submit',
 'eventLabel':'Go',
 'eventValue':10
 });</pre>
<p>These are Data Layer Variables, where the Key is &#8220;eventCategory&#8221; etc, and the values are on the right of the colons. You could feasibly change the values within this to whatever you wanted. However, there are a number of caveats:</p>
<ul>
<li>Google Analytics expects the &#8220;eventValue&#8221; to always be a number, which means you would never want to wrap it with either &#8221; or &#8220;&#8221;.</li>
<li>Due to the nature of the dataLayer, you absolutely never want to leave a variable empty, or leave it out as you might in the ga(&#8216;send&#8217;,&#8217;event&#8217;, &#8230;) style. If you don&#8217;t want to pass in eventLabel and eventValue, for example, you need to set them to undefined (with no &#8221; or &#8220;&#8221;):</li>
</ul>
<pre class="">dataLayer.push({
 'eventCategory':'Contact Form',
 'eventAction':'Submit',
 'eventLabel':undefined,
 'eventValue':undefined
 });</pre>
<ul>
<li>Finally, in order for this information to actually get sent to GTM, we need to include the magic &#8220;event&#8221; key. If you leave it out completely, the data we&#8217;re adding to the Data Layer will never actually be read by GTM. So, our final code should look like this:</li>
</ul>
<pre class="">dataLayer.push({
 'event':'genericEvent',
 'eventCategory':'Contact Form',
 'eventAction':'Submit',
 'eventLabel':undefined,
 'eventValue':undefined
 });</pre>
<p>I&#8217;ve used &#8220;genericEvent&#8221; as my value. Keep that in mind.</p>
<p>Next we need to learn about capturing Data Layer variables in Google Tag Manager.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1686" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2017/07/gtm-data-layer-variables.gif" alt="" width="931" height="623" /></p>
<p>If you missed that:</p>
<ol>
<li>Click Variables.</li>
<li>Click New.</li>
<li>Name the variable &#8220;eventCategory.&#8221;</li>
<li>Click in the Variable Configuration box.</li>
<li>Select Data Layer Variable.</li>
<li>Put &#8220;eventCategory&#8221; into the Data Layer Variable Name text box.</li>
<li>Click Save.</li>
</ol>
<p><strong>NB: Repeat this step for:</strong></p>
<ul>
<li>eventAction</li>
<li>eventLabel</li>
<li>eventValue</li>
</ul>
<p>You&#8217;ve seen variables used before. Remember the UA Code variable? We configured it, and when we needed to use it we referred to it by wrapping it in double curly braces, like this: {{UA Code}}.</p>
<p>We can now do the same thing with all of these variables.</p>
<p>But first, let&#8217;s set up a trigger to watch for our event, which was called &#8220;genericEvent.&#8221;</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1688" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2017/07/gtm-generic-ga-event.gif" alt="" width="931" height="623" /></p>
<p>If you missed that:</p>
<ol>
<li>Click on Triggers.</li>
<li>Click New.</li>
<li>Name the trigger &#8220;genericEvent.&#8221;</li>
<li>Click in the Trigger Configuration box.</li>
<li>Select Custom Event.</li>
<li>Put &#8220;genericEvent&#8221; in the Event name field.</li>
<li>Click Save.</li>
</ol>
<p>Now we&#8217;ve got the code, the variables and the trigger. All we need is the tag.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1690" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2017/07/gtm-generic-ga-event-tag.gif" alt="" width="931" height="623" /></p>
<p>If you missed that:</p>
<ol>
<li>Click on Tags.</li>
<li>Click New.</li>
<li>Name the tag &#8220;UA Generic Event.&#8221;</li>
<li>Click in the Tag Configuration box.</li>
<li>Select Universal Analytics.</li>
<li>Change the Track Type to Event.</li>
<li>Fill in the Category to Value boxes with the associated variables, e.g. {{eventCategory}}.</li>
<li>Change the Google Analytics Settings to Universal Analytics Configuration.</li>
<li>Click in the Triggering box.</li>
<li>Select the genericEvent trigger.</li>
<li>Click Save.</li>
</ol>
<p>Remember to publish your container.</p>
<p>OK so let&#8217;s go over what we did.</p>
<ol>
<li>We changed up our data layer to record all of GA event values.</li>
<li>We recorded them as variables in GTM.</li>
<li>We created a trigger that fires when our event is sent.</li>
<li>We created a tag that sends all of our event variables to GA.</li>
</ol>
<p>If you&#8217;ve gotten this far, you&#8217;re likely as far as you need to be and I&#8217;m about to lose you. If you appreciated this and would like to give back, I&#8217;d very very much appreciate it if you could share a link to this article on your next resource list, blog post or email list!</p>
<p><a name="ga-users-cd"></a></p>
<h2>Google Analytics Users &amp; Custom Dimensions in Google Tag Manager</h2>
<p>Setting Users &amp; Custom Dimensions in GTM is very similar to how we set Events. However, I&#8217;m going to make one small change to how we set it up in order to show you one other aspect of Google Tag Manager.</p>
<p>Let&#8217;s pretend that we&#8217;ve got a logged in user. We&#8217;ve got a unique identifier for them in our database and we know that they&#8217;re a Super User. Our Data Layer might look like this:</p>
<pre class="">dataLayer.push({
 'userId':'asdlkjh-239as-asd92',
 'userType':'Super User'
 });</pre>
<p>Note that the &#8220;event&#8221; key isn&#8217;t included in this declaration. That&#8217;s because we&#8217;re going to do something slightly different here. Remember how I said that we absoutely must include our dataLayer code after the GTM tag? In this case, we want to include our code before the GTM tag. This makes the information within the Data Layer visible to Google Tag Manager right away, as opposed to requiring us to fire any kind of special event.</p>
<p>However, when we do this it&#8217;s best practice to add a special piece of code to make sure we don&#8217;t break anything accidentally. Our final code will end up looking like this:</p>
<pre class="">&lt;script&gt;
 var dataLayer = window.dataLayer = window.dataLayer || [];
 dataLayer.push({
 'userId':'asdlkjh-239as-asd92',
 'userType':'Super User'
 });
 &lt;/script&gt;</pre>
<p>In Google Analytics, I&#8217;ll leave it as an exercise to the reader to set up the User Type custom dimension (in Index 1), and enable User functionality.</p>
<p>I&#8217;ll also leave it as an exercise to the reader to set up Data Layer Variables for both userId and userType, since you should already be fairly capable in that sense now.</p>
<p>But let&#8217;s set up the trigger together. What we need to do here is fire a trigger any time a page loads and both our userId and userType variables (which the reader has gone and done already&#8230; right?) have values. A quick little regular expression that checks for anything at least once is &#8220;.+&#8221; so we&#8217;re going to use that.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1692" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2017/07/gtm-userid-cd-trigger.gif" alt="" width="931" height="623" /></p>
<p>If you missed that:</p>
<ol>
<li>Click on Triggers.</li>
<li>Click New.</li>
<li>Name the trigger &#8220;UserId and UserType.&#8221;</li>
<li>Click in the Trigger Configuration box.</li>
<li>Select Page View.</li>
<li>Select Some Page Views.</li>
<li>Select userId.</li>
<li>Add another row and select userType.</li>
<li>Select Matches Regex in both boxes.</li>
<li>Put &#8220;.+&#8221; in both boxes. NB: This is not &#8220;.*&#8221;</li>
<li>Click Save.</li>
</ol>
<p>This trigger will fire whenever both of these variables are present and not empty.</p>
<p>Next we need to set our userId and send our custom dimension data to Google Analytics. There are a couple of ways to do this, but the approach we&#8217;re using here is the simplest. We&#8217;ll need to send our values along with an event, otherwise it won&#8217;t work in GA.</p>
<p>We&#8217;ll also need to override our Universal Analytics Configuration variable, which sounds really complicated, but it basically allows us to keep using that UA Code but also add in our new fancy features. Let&#8217;s set up the tag together:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1694" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2017/07/gtm-userid-cd-tag.gif" alt="" width="931" height="623" /></p>
<p>If you missed that:</p>
<ol>
<li>Click on Tags.</li>
<li>Click New.</li>
<li>Click in the Tag Configuration box.</li>
<li>Select Universal Analytics.</li>
<li>Select Event from the Track Type dropdown.</li>
<li>Fill in some userful event values.</li>
<li>Select True from the Non-interaction hit dropdown.</li>
<li>Select Universal Analytics Configuration from the Google Analytics Settings dropdown.</li>
<li>Check the Enable overriding settings in this tag</li>
<li>Expand More Settings.</li>
<li>Expand Fields to Set.</li>
<li>Click Add Field</li>
<li>Fill in the Field Name with &#8220;userId&#8221; and the Value with &#8220;{{userId}}&#8221;</li>
<li>Expand Custom Dimensions.</li>
<li>Click Add Custom Dimension.</li>
<li>Fill in the Index with 1 and the Value with &#8220;{{userType}}&#8221;</li>
<li>Click in the Triggering box.</li>
<li>Select the UserId and UserType trigger.</li>
<li>Click Save.</li>
</ol>
<p>Hopefully this is all starting to come together!</p>
<p><a name="ga-ecommerce"></a></p>
<h2>Basic Google Analytics eCommerce Setup in Google Tag Manager</h2>
<p>If you&#8217;re already comfortable setting up eCommerce configurations in Google Analytics-only, you might be panicking about how many variables you might need to set up in Google Tag Manager. Do you need to have a transactionId variable? How about a transactionTotal variable? Oh god.</p>
<p>Don&#8217;t panic.</p>
<p>Google Tag Manager drastically simplifies eCommerce setups compared to how we&#8217;ve set up our event tracking. I&#8217;m going to provide an example, but you may need to modify this to reflect your products and transaction requirements. This is the code we&#8217;d send Google Tag Manager:</p>
<pre class="">dataLayer.push({
 'transactionId': '2901kljs',
 'transactionTotal': 201.23,
 'transactionTax': 12.18,
 'transactionProducts': [{
 'sku': 'sk-2918',
 'name': 'Bicycle',
 'category': 'Toys',
 'price': 187.22,
 'quantity': 1
 }],
 'event': 'eCommercePush'
 });</pre>
<p>In Google Tag Manager, I&#8217;m going to leave it as an exercise to the reader to set up a trigger on the Custom Event of &#8220;eCommercePush&#8221; and I&#8217;ll provide an example of the Tag below.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1696" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2017/07/gtm-ecommerce.gif" alt="" width="931" height="623" /></p>
<p>If you missed that:</p>
<ol>
<li>Click on Tags.</li>
<li>Click New.</li>
<li>Name the tag &#8220;UA eCommerce.&#8221;</li>
<li>Click in the Tag Configuration box.</li>
<li>Select Universal Analytics.</li>
<li>Select Transaction from the Track Type dropdown.</li>
<li>Select Universal Analytics Configuration from the Google Analytics Settings dropdown.</li>
<li>Click in the Trigger box.</li>
<li>Select eCommerce Push.</li>
<li>Click Save.</li>
</ol>
<p>That was a hell of a lot easier than the Events setup, wasn&#8217;t it? I wonder when Google will put together a simpler way to send generic events through tag manager.</p>
<h2>Wrapping Up</h2>
<p>There&#8217;s always more to learn, but the information, skills and experience you&#8217;ve gotten from going through the few exercises in this article put you way ahead of most GTM and even GA implementation specialists.</p>
<p>The post <a href="https://www.troyfawkes.com/switching-to-google-tag-manager-for-google-analytics/">Switching to Google Tag Manager for Google Analytics</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.troyfawkes.com/switching-to-google-tag-manager-for-google-analytics/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Advanced SEO: Pareto Pages, Content Classifications &#038; Market Demand</title>
		<link>https://www.troyfawkes.com/advanced-seo-pareto-pages-content-classifications-market-demand/</link>
					<comments>https://www.troyfawkes.com/advanced-seo-pareto-pages-content-classifications-market-demand/#disqus_thread</comments>
		
		<dc:creator><![CDATA[Troy Fawkes]]></dc:creator>
		<pubDate>Wed, 12 Oct 2016 21:33:09 +0000</pubDate>
				<category><![CDATA[SEO]]></category>
		<guid isPermaLink="false">https://www.troyfawkes.com/?p=1612</guid>

					<description><![CDATA[<p>This is kind of an advanced article in the SEO space, so I&#8217;m not going to make an attempt to address the little things. If you&#8217;re struggling with the details, try to just step back and consider it strategic, even though the strategy itself is data heavy. I remember working with a weight loss company &#8230;</p>
<p class="read-more"> <a class="" href="https://www.troyfawkes.com/advanced-seo-pareto-pages-content-classifications-market-demand/"> <span class="screen-reader-text">Advanced SEO: Pareto Pages, Content Classifications &#038; Market Demand</span> Read More &#187;</a></p>
<p>The post <a href="https://www.troyfawkes.com/advanced-seo-pareto-pages-content-classifications-market-demand/">Advanced SEO: Pareto Pages, Content Classifications &#038; Market Demand</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>This is kind of an advanced article in the SEO space, so I&#8217;m not going to make an attempt to address the little things. If you&#8217;re struggling with the details, try to just step back and consider it strategic, even though the strategy itself is data heavy.</p>
<p>I remember working with a weight loss company that shall not be named due to how frustrating they were to do business with. This particular company had clinics in cities all across Canada and if you&#8217;re Canadian you&#8217;d recognize their brand, so we&#8217;ll say they&#8217;re fairly authoritative. Their website was never very successful and they&#8217;d just redesigned it with a minimalist bent.</p>
<p>Obviously I was tasked with making them more successful. So, here are the facts:</p>
<ul>
<li>Their Domain Authority was slightly higher than their best competitor</li>
<li>Their Technical SEO had some issues but these could easily be resolved</li>
<li>They had a total of five pages on their site.</li>
</ul>
<p>As an SEO, the instinctive thought process should go in this order:</p>
<ol>
<li>Has the client done anything ridiculous from a Technical SEO standpoint like de-index most of their valuable pages or split their brand into 40 different micro sites?</li>
<li>Does the client have a competitive Domain Authority or are they going to struggle until we implement some kind of Authority campaign?</li>
<li>Does the client at least have the 20% of the pages that target 80% of their market (AKA their Pareto Pages)?</li>
</ol>
<p>After that we get into the less needle-moving elements of a campaign.</p>
<p>Remember that that list is the catastrophe list.</p>
<ol>
<li>If their Technical SEO has major issues, the pages in question will never rank for anything. Search engines just can&#8217;t see them.</li>
<li>If their Domain Authority is the pits, no matter what kinds of work we do they&#8217;ll never rank for anything.</li>
<li>If the client hasn&#8217;t even built the pages that address the majority of their market, they&#8217;ll never be in front of that market.</li>
</ol>
<p>I think the SEO industry does a fairly good job of handling the first two points, but we&#8217;re maybe a bit less grounded on the third, and I think the idea of Pareto Pages needs to be top of mind when we&#8217;re thinking about SEO.</p>
<h2>So, What is a Pareto Page?</h2>
<p>Obviously I&#8217;ve stolen the nomenclature from the Pareto Principle, AKA the 80/20 rule where 80% of something is due to 20% of something else. In our case I&#8217;m saying 80% of your market demand is addressed by 20% of the pages on your website. You could also say 80% of your traffic comes from 20% of the pages on your website. The reason this is important is because everything in business fits on some form of Effort/Impact scale, and we&#8217;d ideally like to be getting the biggest Impact for the lowest Effort. Pareto Pages let us do that.</p>
<p>To figure out Pareto Pages, we kind of need to overhaul our thinking about &#8220;Keyword Research&#8221; and Content in general. We also need to start to understand market demand when it comes to SEO, so we&#8217;ll do both of those things at the same time. Let&#8217;s give it a shot by getting back to our weight loss clinic example.</p>
<p>The traditional definiton of market demand is that it is the aggregate demand of all potential customers in a given period of time for a product or service. For our weight loss clinic, we can decide on a service (weight loss programs through a clinic) and a timeline (let&#8217;s say the last 12 months), but how do we figure out demand for that service?</p>
<p>A simplistic approach might be to say, &#8220;well, how many people are Googling &#8216;Weight Loss Clinic&#8217;?&#8221; Let&#8217;s say that number is 22,000, which we grab from Google&#8217;s Keyword Planner. That number is the average number of potential customers demanding a particular service over a monthly period, so this isn&#8217;t a terrible approach. You could kind of use this number to compare apples to apples, like, &#8220;are people more interested in Weight Loss Clinics or Real Estate?&#8221; (If you&#8217;re curious, Real Estate&#8217;s number is 3,350,000). But we can get much more explicit.</p>
<h2>What are Content Classifications?</h2>
<p>I&#8217;ve defined 8 types of Bottom of Funnel&#8211;also referred to as Purchase&#8211;content classifications that address market demand. These are:</p>
<ol>
<li>Product</li>
<li>Service</li>
<li>Location</li>
<li>Industry</li>
<li>Demographic</li>
<li>Problem/Process</li>
<li>Competitor</li>
<li>Seasonal</li>
</ol>
<p>We need to identify whether our weight loss clinic has any market demand in each category. This is a combination of instinct, research and experience.</p>
<ol>
<li><strong>Product:</strong> No, they don&#8217;t sell any products.</li>
<li><strong>Service:</strong> Yes, they offer weight loss programs.</li>
<li><strong>Location:</strong> Yes, they&#8217;re in hundreds of cities in Canada and a basic Keyword Planner search shows lots of volume for &#8220;Weight Loss Clinic Toronto.&#8221;</li>
<li><strong>Industry:</strong> No, unfortunately no potential clients seem to define themselves by their industry, e.g. &#8220;weight loss for retail employees.&#8221; That would be awesome though.</li>
<li><strong>Demographic:</strong> Potential clients define themselves by medical conditions (weight loss for diabetics), gender (weight loss for men) and age (weight loss for kids or weight loss for seniors).</li>
<li><strong>Problem/Process:</strong> Kind of. This isn&#8217;t as easy as, &#8220;my basement is flooded,&#8221; which clearly leads to call a plumber. In the weight loss world, terms like &#8220;obesity treatment&#8221; or &#8220;keeping weight off&#8221; are more informational queries rather than users in the Bottom of the Funnel AKA at the Purchase stage. We should compete for these ideas but they don&#8217;t have nearly the same purchase potential as the other categories. Ignore for this exercise.</li>
<li><strong>Competitor:</strong> No. I did a quick search for users comparing big chain weight loss clinics and none of them have search volume.</li>
<li><strong>Seasonal:</strong> No. While there definitely is a seasonal SPIKE in demand, in my brief poke around I didn&#8217;t find any market demand specifically around spring weight loss specials or anything like that. A good example might be, &#8220;back to school sales.&#8221;</li>
</ol>
<p>This leaves us with only three categories. You might be drawing some parallels already. &#8220;Wouldn&#8217;t it make sense,&#8221; you ask, &#8220;to have a page that directly addresses a specific user need, like &#8216;Weight Loss for Diabetics&#8217;? That would be way more helpful to a user than showing them a generic weight loss page.&#8221; Damn straight.</p>
<p>If we were to build out the research for these categories, we&#8217;d find that there&#8217;s only one service which requires only one page (our home page, most likely). Let&#8217;s say there are 32 Location pages, each targeting a city with a clinic, e.g. &#8220;Weight Loss Clinic in Toronto.&#8221; Finally, there are perhaps five Demographic pages around medical conditions, gender and age.</p>
<p>Personally, my research ends up going into a sheet like this:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1614" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2016/10/keywords.png" alt="keywords" width="696" height="443" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2016/10/keywords.png 696w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2016/10/keywords-300x191.png 300w" sizes="auto, (max-width: 696px) 100vw, 696px" /></p>
<p>With keyword volume magically rolled up so I can see it at the page level:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1615" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2016/10/pages.png" alt="pages" width="791" height="600" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2016/10/pages.png 791w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2016/10/pages-300x228.png 300w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2016/10/pages-768x583.png 768w" sizes="auto, (max-width: 791px) 100vw, 791px" /></p>
<p>I can use this same data in a pivot table to see how the market demand compares from one page type to another, with a nice little total of all demand:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1613" src="https://www.troyfawkes.com/wordpress/wp-content/uploads/2016/10/category-pivot.png" alt="category-pivot" width="205" height="89" /></p>
<p>Having gone through this process, we can easily figure out which are our Pareto Pages. They&#8217;re the 20% of our pages that represent 80% of our market demand, which in our case means we should target our Service keyword with our home page, both genders in the Demographics, as well as Calgary, Toronto, Edmonton, Kingston, Vancouver and Ottawa with Location pages. If that&#8217;s not done, we&#8217;re really messing up. In the future, Location pages will be, by far, our biggest movers and shakers.</p>
<p>You&#8217;ll note that this type of research is foundational. It&#8217;s an amazing framework to build off of as we grow.</p>
<p>This method and ideology works for any industry, even if it results in a frustratingly small market demand. Unfortunately that&#8217;s how the cookie crumbles sometimes. Just keep in mind that this market demand doesn&#8217;t represent your actual traffic; generally a mature search program will hit ten to twenty times this initial volume.</p>
<p>Hope that helps, and if you&#8217;re interested in working with me leave me an email at <a href="mailto:troy@troyfawkes.com">troy@troyfawkes.com</a>; I work on a project-based, hourly model which my clients love.</p>
<p>The post <a href="https://www.troyfawkes.com/advanced-seo-pareto-pages-content-classifications-market-demand/">Advanced SEO: Pareto Pages, Content Classifications &#038; Market Demand</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.troyfawkes.com/advanced-seo-pareto-pages-content-classifications-market-demand/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Today You, Tomorrow Me</title>
		<link>https://www.troyfawkes.com/today-you-tomorrow-me/</link>
					<comments>https://www.troyfawkes.com/today-you-tomorrow-me/#disqus_thread</comments>
		
		<dc:creator><![CDATA[Troy Fawkes]]></dc:creator>
		<pubDate>Sun, 28 Feb 2016 18:45:38 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://www.troyfawkes.com/?p=1484</guid>

					<description><![CDATA[<p>I believe in Karma. It&#8217;s not one of those beliefs that pulls me into a temple, and I don&#8217;t genuinely believe that I&#8217;ve got a bank account for good deeds and good happenings in the future somewhere, but it&#8217;s a useful belief. I like to do positive things just because I can, but when I&#8217;m in a &#8230;</p>
<p class="read-more"> <a class="" href="https://www.troyfawkes.com/today-you-tomorrow-me/"> <span class="screen-reader-text">Today You, Tomorrow Me</span> Read More &#187;</a></p>
<p>The post <a href="https://www.troyfawkes.com/today-you-tomorrow-me/">Today You, Tomorrow Me</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I believe in Karma. It&#8217;s not one of those beliefs that pulls me into a temple, and I don&#8217;t genuinely believe that I&#8217;ve got a bank account for good deeds and good happenings in the future somewhere, but it&#8217;s a useful belief.</p>
<p>I like to do positive things just because I can, but when I&#8217;m in a shitty state of mind it helps to have Karma on my mind. Being frustrated and doing or saying something hurtful is going to bite me in the ass some day, so I should avoid it at all costs. It also helps me to regret those negative things I&#8217;ve done rather than explain them away. &#8220;I was just <em>so frustrated</em>&#8221; isn&#8217;t a good excuse when a big part of me believes that, even so, I&#8217;m going to get what&#8217;s coming to me for being a jerk.</p>
<p>I even feel kind of bad for not doing purely positive things. I could have held that door open, or given a genuine compliment, or tried to make engaging conversation even if my mind was on something else, or I was slightly impaired in a situation. As much as possible, I try to be part of the good in the world.</p>
<p>Today I came across an interesting story on Reddit that really gets to the point. The author is slightly peeved that others aren&#8217;t being as helpful as they could be (in this situation, rightfully so), but his focus is on what <strong>he</strong> can change in <strong>his</strong> life to be better and a greater source of good. Also, Tyler, if you&#8217;re reading this, I realize that this falls into a <a href="https://en.wikipedia.org/wiki/Magical_Negro">special trope</a> only because of you.</p>
<p>Source: <a href="https://www.reddit.com/r/AskReddit/comments/elal2/have_you_ever_picked_up_a_hitchhiker/c18z0z2">Reddit</a> / <a href="https://www.reddit.com/user/rhoner">/u/rhoner</a>, all text below is quoted directly.</p>
<p>Just about every time I see someone I stop. I kind of got out of the habit in the last couple of years, moved to a big city and all that, my girlfriend wasn&#8217;t too stoked on the practice. Then some shit happened to me that changed me and I am back to offering rides habitually. If you would indulge me, it is long story and has almost nothing to do with hitch hiking other than happening on a road.</p>
<p>This past year I have had 3 instances of car trouble. A blow out on a freeway, a bunch of blown fuses and an out of gas situation. All of them were while driving other people&#8217;s cars which, for some reason, makes it worse on an emotional level. It makes it worse on a practical level as well, what with the fact that I carry things like a jack and extra fuses in my car, and know enough not to park, facing downhill, on a steep incline with less than a gallon of fuel.</p>
<p>Anyway, each of these times this shit happened I was DISGUSTED with how people would not bother to help me. I spent hours on the side of the freeway waiting, watching roadside assistance vehicles blow past me, for AAA to show. The 4 gas stations I asked for a gas can at told me that they couldn&#8217;t loan them out &#8220;for my safety&#8221; but I could buy a really shitty 1-gallon one with no cap for $15. It was enough, each time, to make you say shit like &#8220;this country is going to hell in a handbasket.&#8221;</p>
<p>But you know who came to my rescue all three times? Immigrants. Mexican immigrants. None of them spoke a lick of the language. But one of those dudes had a profound affect on me.</p>
<p>He was the guy that stopped to help me with a blow out with his whole family of 6 in tow. I was on the side of the road for close to 4 hours. Big jeep, blown rear tire, had a spare but no jack. I had signs in the windows of the car, big signs that said NEED A JACK and offered money. No dice. Right as I am about to give up and just hitch out there a van pulls over and dude bounds out. He sizes the situation up and calls for his youngest daughter who speaks english. He conveys through her that he has a jack but it is too small for the Jeep so we will need to brace it. He produces a saw from the van and cuts a log out of a downed tree on the side of the road. We rolled it over, put his jack on top, and bam, in business. I start taking the wheel off and, if you can believe it, I broke his tire iron. It was one of those collapsible ones and I wasn&#8217;t careful and I snapped the head I needed clean off. Fuck.</p>
<p>No worries, he runs to the van, gives it to his wife and she is gone in a flash, down the road to buy a tire iron. She is back in 15 minutes, we finish the job with a little sweat and cussing (stupid log was starting to give), and I am a very happy man. We are both filthy and sweaty. The wife produces a large water jug for us to wash our hands in. I tried to put a 20 in the man&#8217;s hand but he wouldn&#8217;t take it so I instead gave it to his wife as quietly as I could. I thanked them up one side and down the other. I asked the little girl where they lived, thinking maybe I could send them a gift for being so awesome. She says they live in Mexico. They are here so mommy and daddy can pick peaches for the next few weeks. After that they are going to pick cherries then go back home. She asks if I have had lunch and when I told her no she gave me a tamale from their cooler, the best fucking tamale I have ever had.</p>
<p>So, to clarify, a family that is undoubtedly poorer than you, me, and just about everyone else on that stretch of road, working on a seasonal basis where time <strong>is</strong> money, took an hour or two out of their day to help some strange dude on the side of the road when people in tow trucks were just passing me by. Wow&#8230;</p>
<p>But we aren&#8217;t done yet. I thank them again and walk back to my car and open the foil on the tamale cause I am starving at this point and what do I find inside? My fucking $20 bill! I whirl around and run up to the van and the guy rolls his window down. He sees the $20 in my hand and just shaking his head no like he won&#8217;t take it. All I can think to say is &#8220;Por Favor, Por Favor, Por Favor&#8221; with my hands out. Dude just smiles, shakes his head and, with what looked like great concentration, tried his hardest to speak to me in English:</p>
<p>&#8220;Today you&#8230;. tomorrow me.&#8221;</p>
<p>Rolled up his window, drove away, his daughter waving to me in the rear view. I sat in my car eating the best fucking tamale of all time and I just cried. Like a little girl. It has been a rough year and nothing has broke my way. This was so out of left field I just couldn&#8217;t deal.</p>
<p>In the 5 months since I have changed a couple of tires, given a few rides to gas stations and, once, went 50 miles out of my way to get a girl to an airport. I won&#8217;t accept money. Every time I tell them the same thing when we are through:</p>
<p>&#8220;Today you&#8230;. tomorrow me.&#8221;</p>
<p><em>I figured I&#8217;d leave you with the image that led me to find the post in the first place, Source is <a href="https://www.reddit.com/r/funny/comments/2hqs02/today_you_tomorrow_me/">Reddit</a> again, obviously.</em></p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-1485 size-full" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/phO81uu.jpg" alt="Today You, Tomorrow Me" width="577" height="1024" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/phO81uu.jpg 577w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/phO81uu-169x300.jpg 169w" sizes="auto, (max-width: 577px) 100vw, 577px" /></p>
<p>The post <a href="https://www.troyfawkes.com/today-you-tomorrow-me/">Today You, Tomorrow Me</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.troyfawkes.com/today-you-tomorrow-me/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Adventures in Kerbal Space Program, kOS &#038; Math (Part 1)</title>
		<link>https://www.troyfawkes.com/adventures-in-ksp-kos-math/</link>
					<comments>https://www.troyfawkes.com/adventures-in-ksp-kos-math/#disqus_thread</comments>
		
		<dc:creator><![CDATA[Troy Fawkes]]></dc:creator>
		<pubDate>Thu, 11 Feb 2016 00:59:52 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<guid isPermaLink="false">http://www.troyfawkes.com/?p=1456</guid>

					<description><![CDATA[<p>For my &#8220;normal&#8221; blog readers, this isn&#8217;t going to make any sense. That&#8217;s why I like to think of this more as my thought dump and less as my place to placate my normal blog readers :) So, I&#8217;ve been more or less consistently playing this game called Kerbal Space Program (KSP) since just before October &#8230;</p>
<p class="read-more"> <a class="" href="https://www.troyfawkes.com/adventures-in-ksp-kos-math/"> <span class="screen-reader-text">Adventures in Kerbal Space Program, kOS &#038; Math (Part 1)</span> Read More &#187;</a></p>
<p>The post <a href="https://www.troyfawkes.com/adventures-in-ksp-kos-math/">Adventures in Kerbal Space Program, kOS &#038; Math (Part 1)</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>For my &#8220;normal&#8221; blog readers, this isn&#8217;t going to make any sense. That&#8217;s why I like to think of this more as my thought dump and less as my place to placate my normal blog readers :)</p>
<p>So, I&#8217;ve been more or less consistently playing this game called Kerbal Space Program (KSP) since just before October 2013. It&#8217;s a game about putting little green people into space, but it&#8217;s realistic enough to keep me intrigued.</p>
<p>As you might know, I&#8217;m also a huge nerd, and some other huge nerd created something called Kerbal Operating System (kOS), which lets you develop programs in Kerbal Space Program to effectively control your rockets. If that sounds simple to you, you&#8217;re going to be in for a shock.</p>
<p>Regardless, I&#8217;m not sure what exact format this is going to take, but I wanted to record my foray into using kOS and diving into the math and science behind rockets. If you hate rockets, space or math, you&#8217;re going to absolutely despise this article.</p>
<h2>Executing Maneuver Nodes &amp; Figuring Out the Rocket Equation</h2>
<p>Let&#8217;s assume you&#8217;ve got a rocket in space. This rocket wants to change where it is in space. To do this it executes a maneuver. In KSP, this in modeled in Maneuver Nodes:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1457" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/KSP-orbits.png" alt="KSP-orbits" width="655" height="583" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/KSP-orbits.png 655w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/KSP-orbits-300x267.png 300w" sizes="auto, (max-width: 655px) 100vw, 655px" /></p>
<p>I&#8217;ve got a couple of scripts written into kOS already that help me execute maneuver nodes, but they&#8217;ve given me some pretty mixed results. I think it&#8217;s because the scripts aren&#8217;t taking into account the change in acceleration due to the loss of mass of a rocket. Basically, rockets aren&#8217;t like cars. To accelerate, they shoot mass out. Hot, fiery mass.</p>
<p>So I&#8217;m going to do <del>some</del> an absurd amount of research and rewrite the script.</p>
<p>First off let&#8217;s break my problem down into the steps of executing a maneuver node.</p>
<p>1) Point at the node.<br />
2) Start accelerating at the correct time.<br />
3) Stop accelerating at the correct time.</p>
<p>That sounds pretty easy.</p>
<p>For #1, we&#8217;re working with nodes in kOS. Luckily there are lots of helpers for nodes, which let us write the following code:</p>
<pre class="lang:java decode:true">SET n TO NEXTNODE.</pre>
<p><strong>n</strong> is now a &#8220;Node&#8221; object, which there&#8217;s lots of data in, including the vector of the node.</p>
<p>I did a lot of digging on vectors since I had zero experience with them, but they&#8217;re basically just directions with magnitude.</p>
<p>If you were to raise your hand and point at a wall in your house, you&#8217;d be identifying a direction. You could imagine that direction being drawn as a line on a graph. But vectors also represent magnitude. If you&#8217;re pointing at the wall, your finger isn&#8217;t really moving towards the wall, it&#8217;s just pointing that way. If you imagine shooting a little bolt of energy out of your finger, that bolt now has a certain velocity or magnitude in the direction you were pointing.</p>
<p>Good to know I guess.</p>
<p>kOS gives us the vector of a node fairly easily, and the cooked steering in kOS works well with vectors, so we can actually just point at the vector.</p>
<pre class="lang:java decode:true ">LOCK STEERING TO n:BURNVECTOR.</pre>
<p>I also want to wait until I&#8217;m pointed the right way, since all the above code says is, &#8220;start turning.&#8221; I know there&#8217;s a function called <strong>VANG</strong> in kOS, which gives you the difference in angles between two vectors (you get it in a positive double, like 35.22767), and I know that one of those vectors is the burnvector. The other is given from kOS, which is <strong>SHIP:FACING:VECTOR</strong>, and means the direction your ship is facing. This is a &#8220;unit vector,&#8221; which is like a normal vector but it has a magnitude of 1. That&#8217;s more or less the written equivalent of pointing your finger at a wall.</p>
<pre class="lang:java decode:true ">WAIT UNTIL VANG(SHIP:FACING:VECTOR, n:BURNVECTOR) &lt; 2.</pre>
<p>So we&#8217;re basically just waiting until we point in the right direction.</p>
<p>Next is where I&#8217;m struggling. To figure out when to accelerate, I need to know the magnitude of the burn (AKA the dV or difference in velocity) which is simply <strong>n:burnvector:mag</strong> (the magnitude of the burnvector in m/s). But I also need to know how long it&#8217;ll take to complete the burn.</p>
<p>That takes a bit more doing, since rockets accelerate faster as they lose mass. Basically you&#8217;re applying the same force to a lighter object, and you get a result like hitting a baseball with a baseball bat later into the burn vs. hitting a truck early in the burn. So if I was to calculate the time it would take to move from point A to point B using my initial maximum acceleration, I&#8217;d end up at point B much sooner than anticipated. So how do I calculate this&#8230;?</p>
<p>Here&#8217;s my thinking.</p>
<p>Let&#8217;s say our initial acceleration is 10m/s^2, and our final acceleration is 20m/s^2. Since we&#8217;re expending fuel (mass) at a constant rate, I&#8217;m assuming that there&#8217;s a linear relationship between the initial acceleration and the final acceleration. So it would be reasonable to take my average acceleration into account when looking for the time it would take to get from point A to point B.</p>
<p>In summary, we need to know:</p>
<ul>
<li>Initial Max Acceleration</li>
<li>Final Max Acceleration</li>
</ul>
<p>SO! Let&#8217;s start by calculating our initial max acceleration. I had to look this up.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1458" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/how-to-calculate-acceleration.png" alt="how-to-calculate-acceleration" width="163" height="44" /></p>
<p>Here, A is given in m/s^2 (which we want), <strong>F</strong> (Force) is expected in Newtons and <strong>m</strong> (Mass) is expected in kilograms. We can actually get these through kOS:</p>
<pre class="lang:java decode:true ">SET a0 TO maxthrust / mass.</pre>
<p>If you check the result of <strong>maxthrust</strong>, though, you&#8217;ll find that it&#8217;s given to us in kilonewtons (1,000 Newtons), and <strong>mass</strong> is given in Tonnes (1,000 kilograms). But since they&#8217;re both 1,000 times too big and we&#8217;re dividing them, they cancel out and we&#8217;re OK.</p>
<p>Now we want to get our acceleration at the end of the burn, or our <strong>final max acceleration</strong>. Looking at the equation we used for the initial acceleration, the only thing that changes for our final acceleration is our mass. Unfortunately we don&#8217;t know what our final mass is, either, so we need to figure out our mass at the end of the burn.</p>
<p>To do this I&#8217;m using the <a href="https://en.wikipedia.org/wiki/Tsiolkovsky_rocket_equation">rocket equation</a>:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1459" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/rocket-equation.png" alt="rocket-equation" width="189" height="72" /></p>
<p>So in English, the change in velocity is equal to the average exhaust speed along the axis of the engine times the natural logarithm of the difference in masses from start to finish. Exhaust speed sounds odd, but it&#8217;s just the mass expended to produce a change in velocity.</p>
<p>The problem is I have no idea what <strong>Ve</strong> is in this game since it&#8217;s not listed anywhere, and it&#8217;s clearly specific to each engine. After <a href="https://en.wikipedia.org/wiki/Specific_impulse">some digging</a> I found that <strong>Ve</strong> is equal to the <strong>Isp</strong> times the force of gravity on earth (<strong>Ve = Isp * g0</strong>). Isp is the value listed on an engine in KSP as Specific Impulse:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1460" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/specific-impulse.png" alt="specific-impulse" width="387" height="293" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/specific-impulse.png 387w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/specific-impulse-300x227.png 300w" sizes="auto, (max-width: 387px) 100vw, 387px" /></p>
<p>And I know both <strong>Isp</strong> and <strong>g0</strong> (g zero), so I can solve for <strong>Ve</strong>.</p>
<p>On a sidenote, holy shit is that Ve and Isp thing confusing. Right now I know of three useful conceptions of g in the sense of gravity. Big G, for the gravitational constant, little g for F = (G * m1 * m2) / r^2, and now another little g that represents the force of gravity on earth. Are these last two actually not different? E.g., does Isp change as little g changes? That doesn&#8217;t make sense to me since it represents the mass ejected from the rocket in this case, and that doesn&#8217;t seem like it should change based on how far you are from a planet, so only Earth standard gravity seems to make sense.</p>
<p>ANYWAY. I&#8217;m still digging myself deeper, because while I was initially just trying to get my final acceleration, I wound up needing my final mass, and now I have to get both the effective Isp and Earth (Kerbin) standard gravity just to solve Ve&#8230; which is what we&#8217;re doing now.</p>
<p>So say I have 2 active engines on my ship, one has an Isp of 120 and a thrust of 20kN, the other has an Isp of 300 and a thrust of 40kN. The effective Isp is closer to 300 than 120 because the engine with the higher Isp is using twice as much fuel as the engine with the lower Isp. This is more or less a weighted average, so I figure that:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1461" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/how-to-calculate-weighted-average-thrust-efficiency.png" alt="how-to-calculate-weighted-average-thrust-efficiency" width="334" height="104" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/how-to-calculate-weighted-average-thrust-efficiency.png 334w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/how-to-calculate-weighted-average-thrust-efficiency-300x93.png 300w" sizes="auto, (max-width: 334px) 100vw, 334px" /></p>
<p>Where t is the thrust of the engine and T is the total thrust of all engines. Just keep adding engines in this way. Codewise, keeping in mind that deactivated engines have an Isp of 0:</p>
<pre class="lang:java decode:true">SET eIsp TO 0.
LIST engines IN my_engines.
FOR eng IN my_engines {
  IF eng:isp &gt; 0 {
    SET eIsp TO eIsp + eng:maxthrust / maxthrust * eng:isp.
  }
}
</pre>
<p><span style="line-height: 1.5;">Thinking about it, since <strong>eng:isp</strong> for a deactivated engine is going to be 0 anyway, a deactivated engine wouldn&#8217;t add anything to the <strong>eIsp</strong> because anything times 0 is 0, so we can get rid of the conditional.</span></p>
<pre class="lang:java decode:true ">SET eIsp TO 0.
LIST engines IN my_engines.
FOR eng IN my_engines {
  SET eIsp TO eIsp + eng:maxthrust / maxthrust * eng:isp.
}</pre>
<p>For Kerbin&#8217;s standard gravity, <strong>I&#8217;m pretty sure we can just use 9.81m/s^2. Am I wrong here?**</strong></p>
<blockquote><p>OK, I&#8217;m NOT wrong in real life, but <a href="http://wiki.kerbalspaceprogram.com/wiki/Specific_impulse">apparently in KSP they use 9.82 m/s^2</a>, so I&#8217;m updating this post to match.</p></blockquote>
<p>So:</p>
<pre class="lang:java decode:true">SET Ve TO eIsp * 9.82.</pre>
<p>Sweet christ. Alright, so I&#8217;m back to solving the rocket equation, but it&#8217;s out of order. I&#8217;ve finally got everything I need in this equation except for the final mass:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1459" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/rocket-equation.png" alt="rocket-equation" width="189" height="72" /></p>
<p>I have no idea how to rearrange this to solve for <strong>m1</strong>, mostly because I&#8217;m pretty clueless about <strong>ln</strong> (natural logarithm or log to base e, where e is some weird constant). Luckily Wikipedia gives this:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1462" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/solve-rocket-equation-for-final-mass.png" alt="solve-rocket-equation-for-final-mass" width="195" height="34" /></p>
<p>Which, let&#8217;s be honest, looks pretty intense anyway. Since I have all of these values though it&#8217;s just a matter of throwing them in, remembering that <strong>e</strong> is Euler&#8217;s number, which kOS gives us as a constant. What is <a href="https://en.wikipedia.org/wiki/E_(mathematical_constant)">Euler&#8217;s number</a>? I don&#8217;t know, but I&#8217;ve seen the movie and he&#8217;s not in class.</p>
<pre class="lang:java decode:true ">SET final_mass TO mass*CONSTANT():e^(-1*n:BURNVECTOR:MAG/Ve).</pre>
<p>How &#8217;bout them apples.</p>
<p>OK, now I&#8217;ve got no idea where I&#8217;m at. We were going to do this:</p>
<p>1) Point at the node.<br />
2) Start accelerating at the correct time.<br />
3) Stop accelerating at the correct time.</p>
<p>Our code right now is:</p>
<pre class="lang:java decode:true">// Point at the node.
SET n TO NEXTNODE.
LOCK STEERING TO n:BURNVECTOR.
WAIT UNTIL VANG(SHIP:FACING:VECTOR, n:BURNVECTOR) &lt; 2.

// Get initial acceleration.
SET a0 TO maxthrust / mass.

// In the pursuit of a1...
// What's our effective ISP?
SET eIsp TO 0.
LIST engines IN my_engines.
FOR eng IN my_engines {
SET eIsp TO eIsp + eng:maxthrust / maxthrust * eng:isp.
}

// What's our effective exhaust velocity?
SET Ve TO eIsp * 9.82.

// What's our final mass?
SET final_mass TO mass*CONSTANT():e^(-1*n:BURNVECTOR:MAG/Ve).</pre>
<p>OK, kind of clear again. So to get <strong>a1</strong>, we just do the acceleration equation again, but this time we use the final mass instead of initial mass:</p>
<pre class="lang:java decode:true ">SET a1 TO maxthrust / final_mass.</pre>
<p>And finally all I wanted from all of this was how long it&#8217;d take to burn through my node. Apparently this comes from a <a href="https://en.wikipedia.org/wiki/Equations_of_motion">SUVAT equation, or an equation of motion</a>, of which we&#8217;re using this guy:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1463" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/suvat-equation-of-motion.png" alt="suvat-equation-of-motion" width="177" height="51" /></p>
<p>Which means that the final velocity is equal to the acceleration times the amount of time you&#8217;re accelerating plus the initial velocity. We&#8217;re trying to solve for t here, so if my steadily improving English major algebra doesn&#8217;t fail me:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1464" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/mL49TWw.png" alt="mL49TWw" width="179" height="75" /></p>
<p>AKA:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1465" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2016/02/how-to-calculate-time-to-acceleration.png" alt="how-to-calculate-time-to-acceleration" width="126" height="77" /></p>
<p>So we decided earlier that the average acceleration can count as my a value in there, which is just <strong>(a0 + a1) / 2,</strong> and the deltaV has always been <strong>n:BURNVECTOR:MAG</strong>, which gives us:</p>
<pre class="lang:java decode:true ">SET t TO n:BURNVECTOR:MAG / ((a0 + a1) / 2).</pre>
<p>That&#8217;s the amount of time it&#8217;ll take to burn through a maneuver node with a rocket that (by definition) changes mass as it accelerates and has varying degrees of efficiency in any number of engines.</p>
<p>Now say the maneuver happens at time A. We want to start out burn before that time and end it afterwards, such that we&#8217;re halfway through our burn by exactly time A. The start time of our burn, then, is <strong>A &#8211; t/2</strong>, and the end time of our burn is exactly <strong>A + t/2</strong>. We can get the exact time of the node by asking kOS for <strong>n:ETA</strong>, and we need to make sure that we&#8217;re doing this relative to some actual timeframe (<strong>TIME:SECONDS</strong>). So we&#8217;ve got:</p>
<pre class="lang:java decode:true ">SET start_time TO TIME:SECONDS + n:ETA - t/2.
SET end_time TO TIME:SECONDS + n:ETA + t/2.</pre>
<p>To actually complete the burn, we just say:</p>
<pre class="lang:java decode:true ">WAIT UNTIL TIME:SECONDS &gt;= start_time.
LOCK throttle TO 1.
WAIT UNTIL TIME:SECONDS &gt;= end_time.
LOCK throttle TO 0.</pre>
<p>Since that &#8220;WAIT UNTIL&#8221; looks makes its check periodically, there&#8217;s some room for error on the start/end times, but it&#8217;s not much.</p>
<p>Finally, and I&#8217;m not 100% sure about this, but since all of this math assumes that you can change your velocity from v0 to v1 instantly, and in our case we&#8217;re doing it over the time of the burn, we&#8217;re probably losing some efficiency and there should be a tiny bit of dV left over for us to burn through, especially on longer burns. I&#8217;ve got some customizations to write for this (next time) anyway, so I&#8217;ll leave solving that issue for later.</p>
<p>Our final code is:</p>
<pre class="lang:java decode:true">// Point at the node.
SET n TO NEXTNODE.
LOCK STEERING TO n:BURNVECTOR.
WAIT UNTIL VANG(SHIP:FACING:VECTOR, n:BURNVECTOR) &lt; 2.

// Get initial acceleration.
SET a0 TO maxthrust / mass.

// In the pursuit of a1...
// What's our effective ISP?
SET eIsp TO 0.
LIST engines IN my_engines.
FOR eng IN my_engines {
SET eIsp TO eIsp + eng:maxthrust / maxthrust * eng:isp.
}

// What's our effective exhaust velocity?
SET Ve TO eIsp * 9.82.

// What's our final mass?
SET final_mass TO mass*CONSTANT():e^(-1*n:BURNVECTOR:MAG/Ve).

// Get our final acceleration.
SET a1 TO maxthrust / final_mass.
// All of that ^ just to get a1..

// Get the time it takes to complete the burn.
SET t TO n:BURNVECTOR:MAG / ((a0 + a1) / 2).

// Set the start and end times.
SET start_time TO TIME:SECONDS + n:ETA - t/2.
SET end_time TO TIME:SECONDS + n:ETA + t/2.

// Complete the burn.
WAIT UNTIL TIME:SECONDS &gt;= start_time.
LOCK throttle TO 1.
WAIT UNTIL TIME:SECONDS &gt;= end_time.
LOCK throttle TO 0.</pre>
<p>The post <a href="https://www.troyfawkes.com/adventures-in-ksp-kos-math/">Adventures in Kerbal Space Program, kOS &#038; Math (Part 1)</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.troyfawkes.com/adventures-in-ksp-kos-math/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>How to Improve Bounce Rate (Tracking) in Google Analytics</title>
		<link>https://www.troyfawkes.com/how-to-improve-bounce-rate-in-google-analytics/</link>
					<comments>https://www.troyfawkes.com/how-to-improve-bounce-rate-in-google-analytics/#disqus_thread</comments>
		
		<dc:creator><![CDATA[Troy Fawkes]]></dc:creator>
		<pubDate>Fri, 25 Sep 2015 16:30:58 +0000</pubDate>
				<category><![CDATA[SEO]]></category>
		<guid isPermaLink="false">http://www.troyfawkes.com/?p=1366</guid>

					<description><![CDATA[<p>Bounce Rate. I think it&#8217;s a dumb metric, for the most part. It&#8217;s so dumb that there&#8217;s no point in &#8220;improving it&#8221; until you&#8217;ve fixed the way it&#8217;s reported. Here&#8217;s what I mean: Person A visits my website. They spend 30 minutes reading my wonderful blog post and then they close the window. They get &#8230;</p>
<p class="read-more"> <a class="" href="https://www.troyfawkes.com/how-to-improve-bounce-rate-in-google-analytics/"> <span class="screen-reader-text">How to Improve Bounce Rate (Tracking) in Google Analytics</span> Read More &#187;</a></p>
<p>The post <a href="https://www.troyfawkes.com/how-to-improve-bounce-rate-in-google-analytics/">How to Improve Bounce Rate (Tracking) in Google Analytics</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Bounce Rate. I think it&#8217;s a dumb metric, for the most part. It&#8217;s so dumb that there&#8217;s no point in &#8220;improving it&#8221; until you&#8217;ve fixed the way it&#8217;s reported. Here&#8217;s what I mean:</p>
<p><img loading="lazy" decoding="async" width="778" height="262" class="aligncenter size-full wp-image-1374" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/ga-bounce-rate-time-on-site-issue.png" alt="ga-bounce-rate-time-on-site-issue" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/ga-bounce-rate-time-on-site-issue.png 778w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/ga-bounce-rate-time-on-site-issue-300x101.png 300w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/ga-bounce-rate-time-on-site-issue-150x51.png 150w" sizes="auto, (max-width: 778px) 100vw, 778px" /></p>
<ul>
<li><strong>Person A</strong> visits my website. They spend 30 minutes reading my wonderful blog post and then they close the window. They get counted as a bounce, and their session is recorded as 0 time on-site.</li>
<li><strong>Person B</strong> visits my website and spends 30s on the first page, but promptly finds the page they&#8217;re looking for. They leave after spending 30 minutes on that page. This isn&#8217;t a bounce, but the session is recorded as a 30s visit.</li>
<li><strong>Person C</strong> visits my website and spend 30 minutes on the first page and moves onto a second page. They leave after spending 30s there. The session is recorded as a 30 minute visit, rather than a 30:30 visit.</li>
</ul>
<p>Since we&#8217;re so wildly inaccurate with our reporting on bounce rate right now, let&#8217;s fix our reporting before we try to &#8220;fix our bounce rate&#8221; by messing with links and user experience and all of that.</p>
<p><span id="more-1366"></span></p>
<p>The reason our bounce rate is so sloppy is because Google Analytics tracks interactions with a website only when interactive elements of the tracking snippet fire. When the page loads, a &#8220;Pageview&#8221; fires. In many cases, this is the only interactive element that is set up.</p>
<p>So, in the case of Person A, the &#8220;Pageview&#8221; fired when they arrived on the site, and, since they left before loading another page, Google Analytics has no idea how long they continued on the website.</p>
<p>In the case of Person B, the &#8220;Pageview&#8221; fired twice. When they got to the first page it fired, and then 30s later when they navigated to their second page. Since they left that second page without loading another page, Google Analytics only knows that they were on the website for 30s and interacted with two pages.</p>
<p>In the case of Person C, we have a better understanding of their visit. We know they&#8217;ve been on the site for at least 30 minutes. The problem here is that the second page, which may be an important page, is tracked as having 0 time on page and a 100% exit rate. This suggests to the analyst that it&#8217;s an awful page, and yet we have no idea how long that user was actually on the page.</p>
<p>Most online marketers know this about Analytics and bounce rates. If you&#8217;ve got a bounce rate problem and you ask your Analytics guy about it, he&#8217;ll say that it&#8217;s not necessarily a bad thing, because this segment might be extremely invested in your content, but since they&#8217;re getting what they want on that single page, they leave.</p>
<p>Consider a website with a listed phone number&#8211;anyone who calls that number has likely gotten what they need out of the website. Then they bounce.</p>
<p>Great, I&#8217;ve explained this away. Unfortunately, that&#8217;s really not insightful and doesn&#8217;t help me understand my traffic. Further, it almost feels like this part of the Analytics experience is broken.</p>
<h2>Solving Google Analytics Bounce Rate Issues</h2>
<p><a href="http://analytics.blogspot.ca/2012/07/tracking-adjusted-bounce-rate-in-google.html">Google itself presented a solution to this issue</a>, and this solution has been improved upon since then. Consider lowly me to be simply documenting what an agency might want to know about the issue, namely solving it on a variety of client setups no matter how absurd those setups might appear to everyone else.</p>
<p>The solution is fairly simple. We&#8217;re going to fire another interactive event to update Google. We&#8217;re going to do this regularly (every 30s) so that we know, within a 30s window, how users are interacting with our site.</p>
<p>I chose 30s because it&#8217;s a nice round number, and because Google only records 1 event per session per second and discards the rest. That means that if you fire two events simultaneously (like a goal conversion through an event as well as this heartbeat), one will clobber the other. If you&#8217;re going to adjust this value (anywhere you see 30000), I&#8217;d suggest adjusting it up.</p>
<p>Also, this doesn&#8217;t improve anything except our understanding of user flow. The amount of time users actually spend on the site doesn&#8217;t actually change. Google doesn&#8217;t bump up your rankings. You won&#8217;t make more money. You&#8217;ll just be more insightful, and you can tell people that you &#8220;just implemented this cool HeartBeat thing,&#8221; and be the life of the party.</p>
<p>There are three variations I want to address:</p>
<ul>
<li>Bounce Rate Issues for Classic Analytics</li>
<li>Bounce Rate Issues for Universal Analytics</li>
<li>Bounce Rate Issues on Google Tag Manager Implementations</li>
</ul>
<p>NB: None of these solutions work interchangeably.</p>
<p>Also NB: The rest of this article is just step-by-step instructions. So comment and tell me something useful, like what your actual bounce rate and time on site are after a couple of days of having implemented this.</p>
<h2>Bounce Rate Issues for Classic Analytics</h2>
<p>This is a copy-paste solution, but first let&#8217;s ensure you&#8217;re actually on Classic Analytics.</p>
<ol>
<li>Go to a page on your website</li>
<li>Right Click somewhere on the page</li>
<li>Select <strong>View Source</strong> (Chrome / IE) or <strong>View Page Source</strong> (Firefox)</li>
<li>Search (CTRL+F for Windows, CMD+F for Macs) for<strong> _gaq</strong></li>
</ol>
<p>If you can&#8217;t find <strong>_gaq</strong> on the page, don&#8217;t use this solution, it won&#8217;t work.</p>
<p>Otherwise, just add the following code anywhere on your website below the Analytics tracking code.</p>
<pre class="javascript">&lt;script&gt;
setInterval(function() {
 _trackEvent('HeartBeat', '30s', '30s', 0, true);
}, 30000);
&lt;/script&gt;</pre>
<p>Did you just copy-paste that without knowing how it works or whether you can trust me? Excellent. Don&#8217;t spend another moment worrying about it. Alternately, take a look at the Mozilla Developer Network&#8217;s JavaScript documentation for the <a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval">setInterval function</a>, and the Google Analytics documentation for the <a href="https://developers.google.com/analytics/devguides/collection/gajs/eventTrackerGuide?hl=en">GA tracker&#8217;s Event Tracking functionality</a>.</p>
<p>Also, you really should <a href="https://developers.google.com/analytics/devguides/collection/upgrade/?hl=en">upgrade to Universal Analytics</a>.</p>
<h2>Bounce Rate Issues for Universal Analytics</h2>
<p>This, too, is a copy-paste solution, but first let&#8217;s ensure you&#8217;re actually on Universal Analytics.</p>
<ol>
<li>Go to a page on your website</li>
<li>Right Click somewhere on the page</li>
<li>Select <strong>View Source</strong> (Chrome / IE) or <strong>View Page Source</strong> (Firefox)</li>
<li>Search (CTRL+F for Windows, CMD+F for Macs) for <strong>ga(</strong></li>
</ol>
<p>If you can&#8217;t find <strong>ga(</strong> on the page, don&#8217;t use this solution, it won&#8217;t work.</p>
<p>Otherwise, just add the following code anywhere on your website below the Analytics tracking code.</p>
<pre class="javascript">&lt;script&gt;
 setInterval(function() {
 ga('send', 'event', 'HeartBeat', '30s');
 }, 30000);
 &lt;/script&gt;</pre>
<p>Did you just copy-paste that without knowing how it works or whether you can trust me? Excellent. Don&#8217;t spend another moment worrying about it. Alternately, take a look at the Mozilla Developer Network&#8217;s JavaScript documentation for the <a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval">setInterval function</a>, and the Google Analytics documentation for the <a href="https://developers.google.com/analytics/devguides/collection/analyticsjs/events?hl=en">GA Universal tracker&#8217;s Event Tracking functionality</a>.</p>
<h2>Bounce Rate Issues on Google Tag Manager Implementations</h2>
<p>Google Tag Manager (GTM) doesn&#8217;t have a copy-paste solution, unfortunately. When you implement your Analytics snippet through GTM it forces you to use a combination of the dataLayer and triggers if you want to fire events the old fashioned way. Luckily, GTM is already very extensible and we can just use its built-in functionality.</p>
<p>If you&#8217;ve implemented GA through GTM (acronyms!), it should look something like this:</p>
<p><img loading="lazy" decoding="async" width="508" height="37" class=" size-full wp-image-1368 aligncenter" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/ga-universal-gtm.png" alt="ga-universal-gtm" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/ga-universal-gtm.png 508w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/ga-universal-gtm-300x22.png 300w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/ga-universal-gtm-150x11.png 150w" sizes="auto, (max-width: 508px) 100vw, 508px" /></p>
<p>If you have no idea what&#8217;s happening in this screenshot, this tutorial probably isn&#8217;t for you. <a href="https://support.google.com/analytics/answer/6163791?hl=en">Start here</a>.</p>
<p>Before we get started, some old GTM installs don&#8217;t have some useful features enabled. Just click into Variables and make sure your panel looks like mine. Not super relevant, but it&#8217;s annoying when this isn&#8217;t done.</p>
<p><img loading="lazy" decoding="async" width="651" height="324" class="aligncenter size-full wp-image-1369" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/gtm-variables.png" alt="gtm-variables" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/gtm-variables.png 651w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/gtm-variables-300x149.png 300w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/gtm-variables-150x75.png 150w" sizes="auto, (max-width: 651px) 100vw, 651px" /></p>
<p>Now, we need to do two things. One, we need a trigger that fires every 15s. Next, we need an event tag that fires our HeartBeat and attaches to that trigger.</p>
<p>First, the trigger:</p>
<ol>
<li>Click into your <strong>Container</strong>.</li>
<li>Click on <strong>Triggers</strong> in the left navigation.</li>
<li>Click <strong>New</strong>.</li>
<li>Select <strong>Timer</strong>.</li>
<li>Set the <strong>Interval</strong> to <strong>30000</strong>.</li>
<li>Set the <strong>Limit</strong> to <strong>80</strong> (that&#8217;s 40 minutes)</li>
<li>Click <strong>Continue</strong>.</li>
<li>Under <strong>Enable When,</strong> select <strong>url</strong>, then <strong>matches RegEx</strong>, then <strong>.*</strong></li>
</ol>
<p><img loading="lazy" decoding="async" width="857" height="181" class="aligncenter size-full wp-image-1370" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/gtm-timer-enable-when.png" alt="gtm-timer-enable-when" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/gtm-timer-enable-when.png 857w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/gtm-timer-enable-when-300x63.png 300w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/gtm-timer-enable-when-150x32.png 150w" sizes="auto, (max-width: 857px) 100vw, 857px" /></p>
<ol>
<li>Click <strong>Continue</strong>.</li>
<li>Click <strong>Create Trigger</strong>.</li>
<li>Name it something you&#8217;ll remember, like &#8220;<strong>What the hell does this do7</strong>&#8220;</li>
</ol>
<p>Now we&#8217;ll create the tag that will fire every 30s.</p>
<ol>
<li>Click on <strong>Tags</strong> in the left navigation.</li>
<li>Click <strong>New</strong>.</li>
<li>Select <strong>Google Analytics</strong>.</li>
<li>Select your flavour of Analytics and click <strong>Continue</strong>.</li>
<li>Enter your <a href="https://support.google.com/analytics/answer/1032385?hl=en">tracking ID</a> or the <a href="http://www.simoahava.com/analytics/variable-guide-google-tag-manager/">GTM Tracking ID variable that you&#8217;ve created because you&#8217;re so pro at GTM</a>.</li>
<li>From the <strong>Track Type</strong> dropdown, select <strong>Event</strong>.</li>
<li>Set the <strong>Category</strong> to &#8220;<strong>HeartBeat</strong>&#8221; and <strong>Action</strong> to &#8220;<strong>30s</strong>&#8221; (Ignore the 15s, I changed it!)</li>
</ol>
<p><img loading="lazy" decoding="async" width="378" height="610" class="aligncenter size-full wp-image-1371" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/gtm-heartbeat-tag-event.png" alt="gtm-heartbeat-tag-event" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/gtm-heartbeat-tag-event.png 378w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/gtm-heartbeat-tag-event-186x300.png 186w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/gtm-heartbeat-tag-event-93x150.png 93w" sizes="auto, (max-width: 378px) 100vw, 378px" /></p>
<ol>
<li>Click <strong>Continue</strong>.</li>
<li>In the <strong>Fires On</strong> section, we&#8217;re assigning the tag to a trigger. Since we created this trigger already, we just need to find it. <strong>Click More</strong> and select the timer trigger that you created.</li>
</ol>
<p><img loading="lazy" decoding="async" width="434" height="371" class="aligncenter size-full wp-image-1372" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/gtm-tag-timer-mapping.png" alt="gtm-tag-timer-mapping" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/gtm-tag-timer-mapping.png 434w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/gtm-tag-timer-mapping-300x256.png 300w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/gtm-tag-timer-mapping-150x128.png 150w" sizes="auto, (max-width: 434px) 100vw, 434px" /></p>
<ol>
<li>Click <strong>Save</strong>, then <strong>Create Tag</strong> and name it something catchy like, &#8220;<strong>TroyFawkes&#8217; HeartBeat Tag Of Awesomeness</strong>&#8220;</li>
</ol>
<p>It should look like this:</p>
<p><img loading="lazy" decoding="async" width="609" height="56" class="aligncenter size-full wp-image-1373" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/heartbeat-tag-of-awesomeness.png" alt="heartbeat-tag-of-awesomeness" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/heartbeat-tag-of-awesomeness.png 609w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/heartbeat-tag-of-awesomeness-300x28.png 300w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/09/heartbeat-tag-of-awesomeness-150x14.png 150w" sizes="auto, (max-width: 609px) 100vw, 609px" /></p>
<p>Now just <strong>Publish</strong> your container.</p>
<p>The post <a href="https://www.troyfawkes.com/how-to-improve-bounce-rate-in-google-analytics/">How to Improve Bounce Rate (Tracking) in Google Analytics</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.troyfawkes.com/how-to-improve-bounce-rate-in-google-analytics/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>My First Week in Lima</title>
		<link>https://www.troyfawkes.com/my-first-week-in-lima/</link>
					<comments>https://www.troyfawkes.com/my-first-week-in-lima/#disqus_thread</comments>
		
		<dc:creator><![CDATA[Troy Fawkes]]></dc:creator>
		<pubDate>Thu, 09 Apr 2015 15:24:15 +0000</pubDate>
				<category><![CDATA[Travel]]></category>
		<guid isPermaLink="false">http://www.troyfawkes.com/?p=1159</guid>

					<description><![CDATA[<p>I wrote this mostly so I could remember all of the great stuff that happened on my first week in Lima, and so I could just say, &#8220;read this post,&#8221; any time someone asked about it :D I don&#8217;t think I&#8217;ll spend much energy on travel-related posts after this but I&#8217;ll keep up with Facebook! &#8230;</p>
<p class="read-more"> <a class="" href="https://www.troyfawkes.com/my-first-week-in-lima/"> <span class="screen-reader-text">My First Week in Lima</span> Read More &#187;</a></p>
<p>The post <a href="https://www.troyfawkes.com/my-first-week-in-lima/">My First Week in Lima</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I wrote this mostly so I could remember all of the great stuff that happened on my first week in Lima, and so I could just say, &#8220;read this post,&#8221; any time someone asked about it :D</p>
<p>I don&#8217;t think I&#8217;ll spend much energy on travel-related posts after this but I&#8217;ll keep up with Facebook!</p>
<p>Here&#8217;s my first week in Lima, Peru.</p>
<p><img loading="lazy" decoding="async" width="600" height="450" class="alignnone size-full wp-image-1155" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/lima-sunset.jpg" alt="lima-sunset" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/lima-sunset.jpg 600w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/lima-sunset-300x225.jpg 300w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/lima-sunset-150x113.jpg 150w" sizes="auto, (max-width: 600px) 100vw, 600px" /></p>
<h2>Lunes // Monday</h2>
<p>Unless you&#8217;re a gifted empath&#8211;or you&#8217;ve done it yourself&#8211;I don&#8217;t think it&#8217;s possible to grasp the feeling of expatriating yourself.</p>
<p>I had an excellent job, an amazing group of friends, a home with possessions, a routine, and a familiarity with the city. When I left Monday morning, I had one piece of luggage, a laptop bag and the knowledge that I&#8217;d be heading to a country with a dramatically different culture and whose language I didn&#8217;t speak. For an indefinite amount of time.</p>
<p>I&#8217;m not sure how to explain how I felt; it doesn&#8217;t fit nicely into words. Freeing, maybe. Exciting. Frightening.</p>
<p>I told a very close friend that, &#8220;it feels like standing at the edge of a massive waterfall, where you can&#8217;t see the sides or the bottom through the mist. Just a really loud noise and the knowledge that you&#8217;ll be going down into it.&#8221;</p>
<p>The trip itself was very&#8230; trip-like. There&#8217;s nothing special about airports once you&#8217;ve been to one. At 3am I exchanged a ninja turtle handshake with one of my best friends and grabbed a cab to the airport. Two planes, a 6 hour layover in Newark and the fresh feeling of warmth and humidity brought me to Lima, the capital city of Peru.</p>
<p>https://youtube.com/watch?v=00kj_F6gNnE</p>
<p>My hostel has dorms of 18 and 8, of which I got into the latter at 10pm Monday night.</p>
<p>What&#8217;s Lima like? I feel like that&#8217;s not the kind of question I can answer right away, even writing this a week in. I don&#8217;t have any idea where the locals are coming from, and I&#8217;m living in the wealthiest neighbourhood in the entire country. I&#8217;ve seen pictures and spoke at length with another traveller of the rest, and the vast majority of the country is nothing at all like Lima.</p>
<p>I&#8217;m not sure how I feel about that. When I just finished high school I&#8217;d have wanted to go see the &#8220;real&#8221; Peru, and I still do. But I&#8217;m more inclined to find a fun place to build my own life than I am to explore the tragedies and glories of every nook and cranny of every country. I&#8217;m a dabbler at travelling, I guess.</p>
<p>I do recall that the two hour walk I took before passing out in my bunk was just enough to calm my nerves and introduce some items to my mental checklist of, &#8220;things I have to do to feel more comfortable here,&#8221; like:</p>
<ul>
<li>Navigate to a couple new places without excessively relying on a map</li>
<li>Buy something from a street vendor</li>
<li>Take a taxi off the street (you have to negotiate the price before you get in)</li>
<li>Order food at a restaurant</li>
</ul>
<p>Once I do it once it becomes part of my map and there&#8217;s no fear of trying it again later. Unless, of course, I get horrifically sick while trying multiple new things all at once, which happened later this week and makes me extremely sensitive about surfing. Cliff hanger?</p>
<h2>Martes // Tuesday</h2>
<p>I&#8217;ve usually had a good time at hostels by meeting folks in the evening, but I ran into John around 8am during breakfast. I&#8217;d just woken up on my first morning in South America, so it was nice to start the morning with a conversation. He&#8217;s a traveller with a bit of an entrepreneurial bent as well, so hopefully you&#8217;ll see his name on a couple Cevicherias in the U.S. soon.</p>
<p>I&#8217;ll also add that travelling solo is just something that I expect to do, so it&#8217;s not brave at all. There are backpackers who move in groups, but expats tend to either travel solo or with SOs. I just happen to be solo, and the nerve-wracking bit about whether I&#8217;ll meet people or not comes later. I&#8217;ve come across that tattered old ghost, trying to scare me with loneliness, before, though, so it doesn&#8217;t bother me.</p>
<p>What I found surprisingly bothersome was that the combination of the lack of confidence in completing every day tasks (due to language and culture issues) and hanging out with backpackers who live a much more mobile life made me pretty quiet. It also didn&#8217;t help that I have no time to recharge here&#8211;I&#8217;m always around and chatting with people, even as I&#8217;m typing this. When I want to get to know someone here, I tend to ask questions and try to avoid answering any of my own, shifting the conversation away. I also expect that they&#8217;re going to be leaving anywhere from 6 hours to 3 days from the first time I talk to them. It&#8217;s an odd set of feelings.</p>
<p>After breakfast I was hoping to check out the rock climbing place I&#8217;d found online before heading to Lima. Turns out it was closed, so I ended up wandering down to the cliffs overlooking the water:</p>
<p>https://youtube.com/watch?v=T9mHH-UzMmY</p>
<p>Just walking down the street is a new experience for me in Lima. Most of the streets are one-ways. There are street vendors everywhere. There&#8217;s not a huge press of people, and the ones walking around are generally pretty relaxed and chatting happily in Spanish. The stores are all unfamiliar and a bit intimidating to someone as miserable at the language as I am. My only understanding of the route came from a glance at a map, and the street names are all new and confusing (Jose Larco, Diagonal, Calle Schell, Malecon de la Marina, Malecón 28 de Julio). The architecture is new to me and varied. The street signs use familiar expressions in odd ways, (Playa=Beach, but also Parking?) The further southwest I walked, the more the roads were covered in a fog that smelled like the sea.</p>
<p>This all makes even a short walk into an adventure.</p>
<p>Lunch was out in an awesome restaurant in La Victoria with John (US), Chris (AUS) and Miles (AUS). I&#8217;d never tried Ceviche before, and if you can find it con leche de tigre anywhere I highly recommend it.</p>
<p>I had met John and Chris in the morning, but tonight was their going away party. It included Pisco Sours and meeting some new folks&#8211;Ben, Ilia (Israelis) and Darie (Ireland). We hit up a casino, failed miserably at finding a bar open past 1am, and recovered by getting some fantastic sandwhiches.</p>
<h2>Miercoles // Wednesday</h2>
<p>Darie, an Irish guy I met the night before, and I went to check out the rock climbing place when it opened around noon. The moment I walked in the door I met a kiwi named Beni. I think the conversation went, &#8220;Hey! Need a partner?&#8221; &#8220;Yeah!&#8221; &#8220;Do you lead?&#8221; &#8220;Yeah!&#8221; &#8220;Give me your number, I&#8217;m back in a week!&#8221; Which is actually kind of what I expected.</p>
<p><a href="http://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/PIRQA-Lima-1.jpg"><img loading="lazy" decoding="async" width="600" height="800" class="alignnone size-full wp-image-1144" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/PIRQA-Lima-1.jpg" alt="PIRQA-Lima-1" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/PIRQA-Lima-1.jpg 600w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/PIRQA-Lima-1-225x300.jpg 225w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/PIRQA-Lima-1-113x150.jpg 113w" sizes="auto, (max-width: 600px) 100vw, 600px" /></a></p>
<p>After checking out PIRQA (the climbing place) we stopped for food at a turistico&#8211;which I think just means, literally, &#8220;tourist,&#8221; but seems to be short for restaurante turistico and represents a place where you can get an entree and segundo for 10 soles ($4)&#8211;and we walked back to the hostel through Kennedy Park, AKA the cat park. Which is a park&#8230; full of cats. Yup. They&#8217;re really cute :)</p>
<p><a href="http://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/CatPark1.jpg"><img loading="lazy" decoding="async" width="600" height="450" class="alignnone size-full wp-image-1145" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/CatPark1.jpg" alt="CatPark1" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/CatPark1.jpg 600w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/CatPark1-300x225.jpg 300w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/CatPark1-150x113.jpg 150w" sizes="auto, (max-width: 600px) 100vw, 600px" /></a></p>
<p>Popped back to PIRQA with Jake (UK) for some climbing. It&#8217;s much harder than I thought to climb in the heat and humidity; we both got wrecked pretty early.</p>
<p>We were supposed to check out a club called &#8220;Help&#8221; in Barranco, but the hostel handed us a dozen wrist bands for Bizaro, which was just across the street. The whole crew that went out was a massive group of the folks from the previous two days, as well as two UK girls (Anna and Rhiannon), and an Aussie girl (Shansal). Beni found us as well since he was hanging out with the girls. &#8220;Che Lagarto? I just met someone from there&#8230;&#8221;</p>
<p><a href="http://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/fun-shots.jpg"><img loading="lazy" decoding="async" width="600" height="533" class="alignnone size-full wp-image-1146" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/fun-shots.jpg" alt="fun-shots" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/fun-shots.jpg 600w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/fun-shots-300x267.jpg 300w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/fun-shots-150x133.jpg 150w" sizes="auto, (max-width: 600px) 100vw, 600px" /></a></p>
<p>The club was&#8230; a club! Except full of mostly Peruvians. I&#8217;ve done the club thing in Canada, the U.S., England, Sweden and China before this. This one didn&#8217;t really stand out that much from what you might expect in Canada, though they call rum and cokes, &#8220;Cuba Libres,&#8221; and people smoke inside. I did bump into my first Canadian on my way out, which was nice.</p>
<p>That was about it; hangovers are the same no matter where in the world you wake up.</p>
<h2>Jueves // Thursday</h2>
<p>Thursday morning I was a bit sore. I managed to get about 4 hours of work done, though, which was the first bit of work I had gotten done since showing up on Monday. I mostly spent my time researching what the hard science and peer reviewed studies had to say about conversation and communication skills. <strong>If anyone has anything to recommend taking a look at along this vein, I&#8217;d love to hear it!</strong> I&#8217;m not talking about motivational speakers or life coaches, studies and empirical evidence only here :)</p>
<p>Jake and I grabbed some lunch and headed down to the beach. I wasn&#8217;t feeling the best, so when he asked if I wanted to give surfing a go I was extremely hesitant. But then, since when have I said no to an adventure?</p>
<p><a href="http://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/playa-miraflores-1.jpg"><img loading="lazy" decoding="async" width="600" height="450" class="alignnone size-full wp-image-1150" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/playa-miraflores-1.jpg" alt="playa-miraflores-1" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/playa-miraflores-1.jpg 600w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/playa-miraflores-1-300x225.jpg 300w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/playa-miraflores-1-150x113.jpg 150w" sizes="auto, (max-width: 600px) 100vw, 600px" /></a></p>
<p>I came out of the salty sea water feeling like all of the shitty things I&#8217;d ever done to my body were coming back to haunt me. After returning the surf board and paying with soggy soles, I tried not to die on the beach, more or less successfully.</p>
<p>I think that was the first time I was ever in the ocean, unless you count hopping in the English Channel at Brighton. I&#8217;m not very intimidated by water, though if you know me well you&#8217;ll know that I have massive respect for big bodies of water and can just sit and watch for hours. I really enjoyed the exercise of surfing, the adventure of trying something new and the water around me.</p>
<p>But I was so sick that it took me about 15 minutes to get back to shore and even then picking up the board and carrying higher up on the beach was a gargantuan effort. I sat down and focused intently on not vomiting, noting the displeasure of my organs and muscles, and waited until I thought I could hike the 2 minutes back to the stand we rented the boards from. I wouldn&#8217;t be surprised if I was turning colours; I didn&#8217;t even want to speak as I paid the guy and stumbled to sit on the uncomfortable rocky beach for fear of losing focus.</p>
<p>I&#8217;d like to think that I hid it pretty well though :)</p>
<p>The consolation prize for coming in last in surfing was that I look fantastic in a wet suit and I finally caught up on my sleep when we got back.</p>
<p>PS: I didn&#8217;t bring my camera that day, but here&#8217;s what I saw from the road down:</p>
<p>https://youtube.com/watch?v=qVsuJCB-n1U</p>
<h2>Viernes // Friday</h2>
<p>Turns out it wasn&#8217;t me being out of shape or hung over that was the issue with surfing. I woke up with a fever and some other wonderful complications. I couldn&#8217;t focus on abstracts and such so I just went through some extra Spanish words and slept all day. It was pretty abysmal.</p>
<p>I did head out solo for lunch and forced some ceviche on myself (was the more common lemon sauce rather than leche de tigre), for some odd reason finding eating uncooked fish while flu-sick to be a good idea. Maybe I was just proving to myself that I wasn&#8217;t THAT sick. I did fumble pretty much all of the interaction with the server, but even that reinforced some words / expressions that I needed to pick up faster ([somethingsuperfast] ¿Como? Mi español es bastante malo. Puedes hablar más despacio, por favor? [Algún más?] No más, gracias. Puedo tenar la cuenta?).</p>
<p>By the evening I recovered enough to play a couple games of pool and have a couple beers with the crew, plus Lesley (U.S., from whatever state where they say, &#8220;pap,&#8221; instead of, &#8220;pop&#8221;).</p>
<p>Random note: the Israelis taught me a game that&#8217;s kind of like Kill. My 3-person game, Kill, assigns people numbered balls (so 1-5, 6-10, 11-15). Once those are sunk, you &#8220;die.&#8221; Their version was that the first ball you sink is your series, (again 1-5, 6-10, 11-15), and you win when you sink all of those balls. Both games work with 3 or 5 players.</p>
<h2>Sabados // Saturday</h2>
<p>Saturday was arguably my busiest day so far. I can&#8217;t sleep past 7am even if I&#8217;ve gotten to sleep after midnight, so I was up having breakfast and studying Spanish when Jake asked if I wanted to buy 2 hours of Spanish classes off of him. We wandered down to the class to ask, but got shot down. I might take some classes there anyway&#8211;it&#8217;s a beautiful place and the teacher I met was fantastic at getting me to use what little Spanish I had to figure out what kind of class I wanted to try.</p>
<p><strong>Future me</strong> might as well interject here&#8211;I did sign up for classes, they start on the 13th. My goal is to master the simple past and future tenses for the top 20 verbs and figure out a couple of issues I have with basic grammar before I show up on Monday. I&#8217;m mostly looking for practice and improvement in spoken and heard Spanish anyway; I can do a lot of the grammar stuff either on my own or by bothering all of my AWESOME SPANISH PEOPLES :)</p>
<p>Since I couldn&#8217;t take the class that morning, I wandered down to the beach sometime near 9am and chilled there for a couple of hours. It&#8217;s so incredibly beautiful, I can&#8217;t get enough of the water.</p>
<p>https://youtube.com/watch?v=aJyYmb5LYws</p>
<p>By the time I came back it was almost lunch time, so bumping into Lesley and Justin (U.S., Alaska) meant we were right back out. We hit up another turistico (I&#8217;m starting to think this isn&#8217;t the right name for them), and ended up wandering through Kennedy Park, a Starbucks, and the Larcomar shopping centre down by the water. Hell of a lot of walking by this point.</p>
<p>When we got back, I just managed to chill for 45 minutes before I was on my feet again to check out an apartment on Malecón de la Marina. My first solo taxi adventure taught me that it&#8217;s easy to negotiate with a cabby as long as you know what a reasonable rate is and can argue over prices in Spanish (really just knowing numbers, &#8220;Voy a [address]; es 5 soles ok?&#8221; &#8220;Entonces, ¿cuanto cuesta?&#8221; &#8220;Es muy caro.. 10 soles ok?&#8221;). I also learned that Malecón is not pronounced the way I thought it was, much to the confusion of the cabby.</p>
<p>Anyway, the area we pulled up to was beautiful. It&#8217;s on the cliffs overlooking the water, with just a cute road and a pretty park being the only things separating the apartments from the edge of the cliffs. There&#8217;s a little structure built for pull ups, dips and various exercises right out front. The inside has a pool and a rooftop patio, and the apartment and owners were great folks.</p>
<p>The only things that turned me off were that it was really just a box to stay in, and it&#8217;s about 30 minutes walking from Kennedy Park (and all of the good food, shopping, rock climbing and Spanish classes). I was hoping for roommates to spend down time with. I ended up politely declining, but I was happy to have checked it out.</p>
<p>I took advantage of being in the area to take a walk by the cliffs, grab a churro and a coffee and watch the sun set. Definitely not a waste.</p>
<p><a href="http://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/lima-sunset.jpg"><img loading="lazy" decoding="async" width="600" height="450" class="alignnone size-full wp-image-1155" src="http://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/lima-sunset.jpg" alt="lima-sunset" srcset="https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/lima-sunset.jpg 600w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/lima-sunset-300x225.jpg 300w, https://www.troyfawkes.com/wordpress/wp-content/uploads/2015/04/lima-sunset-150x113.jpg 150w" sizes="auto, (max-width: 600px) 100vw, 600px" /></a></p>
<p>https://youtube.com/watch?v=MQfx7B6KF4c</p>
<p>When I finally made it back I was handed a beer. Chilled for a bit over an hour with the crew before heading out to the Parque de la Reservá, which is a big park full of fountains in the (I think) Downtown area. It was nice, but touristy in the, &#8220;lookit the pretty fountains for two hours&#8221; kind of way that doesn&#8217;t really arouse my interest. I took a couple pictures and videos just in case though :)</p>
<p>https://youtube.com/watch?v=BxXKnQL9t5Y</p>
<p>Instead of stepping back into the hostel, we reached a bar on Calle Berlin around midnight. A couple of beers in and I realized that I had absolutely no energy left; I was more or less passing out on the spot. An Irish exit later, I fell asleep to the thought that maybe I should take it easy if I&#8217;m going to do this full time.</p>
<p>I definitely felt like I was socialized to excess pretty early, but didn&#8217;t want to tap out with any form of excuse. This is where having my own room and a bit of separation, e.g. phone or SMS, between me and the world helps a lot. My lack of energy for social stuff is probably from a mix of being constantly with people and having a whole lot of other pressures&#8211;still sick but ignoring it, brand new country, new language to learn, and folks back home who my mind&#8217;s with a lot. It&#8217;d be a lot easier if I could get a room in a house or an apartment!</p>
<h2>Domingo // Sunday</h2>
<p>I wrote most of whatever this is on Sunday morning, eschewing my adventuring responsibilities for you to have something to read. I also just needed a good reason to sit in front of a computer and smash keys instead of going skydiving or joyriding up the coast in a rental car or something.</p>
<p>Besides, I had plans for the afternoon to do some rock climbing with Ilia and Ben. I had told them that it was going to be closed (the owners and instructors were out on a climbing trip), but Ilia didn&#8217;t believe me, so I figured we&#8217;d meet there and then be doing something random.</p>
<p>It was very random indeed; we hit up a chess park for a couple games, then they showed me a store called 5cuenta which was a much better (and cheaper!) experience than Larcomar. It involved digging through piles of clothes at each individual stand, which were independently operated so that you had to haggle with and pay the separate owners. They were very nice and taught me that &#8220;brighter&#8221; is &#8220;más claro,&#8221; as opposed to my first attempt along the lines of, &#8220;more white.&#8221;</p>
<p>Ilia and I walked down to Parque de la Amor (that&#8217;s probably the right name?), which Ilia calls Malecón, to try to do some slack lining. We ended up meeting Nathaly (Paraguay), who we knew through Ben, and she convinced us to go for a walk to find, &#8220;los gentes muy locos.&#8221;</p>
<p>I had actually been to Malecón the day before, so I knew the park. It was a bit different tonight, though; we passed a dog that was skateboarding along the path on our way to this little dip in the cliff filled with palm trees and, as we half fell down the slope, about 50 people either sitting around and relaxing or playing some kind of instrument, most noticeably drums.</p>
<p>https://youtube.com/watch?v=KBCROzMu4ww</p>
<p>It was a bit of an intimidating feeling to sit by the same fire as all of these folks, especially when he organizer started on an empassioned speech that I only half-understood (which was worse, &#8220;Capitalists..&#8221; &#8220;Lawyers, Bankers..&#8221; &#8220;BAD! .. BAD!..&#8221;) in the midst of which he&#8217;d pause to blow a conch until he turned red. Apparently he was mostly focussed on peace, but it was a bit intimidating to be sitting there in jeans and a nice silver dress shirt when he was bashing everyone from lawyers to teachers.</p>
<p>https://youtube.com/watch?v=4N2bguO2qSM</p>
<p>Of course Nathaly then volunteered that Ilia and I were Israeli and Canadian, which immediately had me wondering if I&#8217;d survive a jump off the cliff if it came to that.</p>
<p>It got a lot more chill when the speech was over and it was just music. The organizer handed me a small piece of wood and asked me to say a prayer and put it in the fire, so I said a nice little prayer for togetherness and a small reprieve to everyone&#8217;s shackles and hoped the fire would do something to share it.</p>
<p>https://youtube.com/watch?v=Q3WLdVK_LoQ</p>
<p>Overall it was a great night :)</p>
<p><strong>Future me again:</strong> By Wednesday I had a pretty solid feel for the city and felt a hell of a lot more comfortable with everything. It&#8217;s still a bit awkward speaking with backpackers, &#8220;6 WEEKS!? THAT&#8217;S A LONG TIME! YOU COULD SEE EVERY COUNTRY IN S.A.!&#8221; They don&#8217;t really get why I&#8217;m here, which is fine, but since they flow through in small groups and last only a couple days, it&#8217;s the same conversation a couple times a day.</p>
<p>That having been said, once I&#8217;ve had the chance to get Spanish down (3 weeks of classes and my pretty ingrained study habit should help) and get into a habit with work, I&#8217;d definitely like to see a couple more cities, though exactly how I&#8217;m not sure yet. I know a couple folks want to see different places, like Machu Picchu and Chile, so it might make sense to plan around them. Cuzco/Machu Picchu isn&#8217;t a long term venture, but I wouldn&#8217;t mind being in Chile for a bit. I want to see Colombia, Panama and Cuba as well, probably for a couple months at a time.</p>
<p>So excited!</p>
<p>The post <a href="https://www.troyfawkes.com/my-first-week-in-lima/">My First Week in Lima</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.troyfawkes.com/my-first-week-in-lima/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Spirituality, Karma, and the Little Things</title>
		<link>https://www.troyfawkes.com/spirituality-karma-little-things/</link>
					<comments>https://www.troyfawkes.com/spirituality-karma-little-things/#disqus_thread</comments>
		
		<dc:creator><![CDATA[Troy Fawkes]]></dc:creator>
		<pubDate>Wed, 19 Nov 2014 01:53:15 +0000</pubDate>
				<category><![CDATA[Social Skills]]></category>
		<guid isPermaLink="false">http://www.troyfawkes.com/?p=1108</guid>

					<description><![CDATA[<p>The end of high school and beginning of University, for me, was defined by a girl. She was smart, pretty, crazy in bed and just as romantic as I was at the time. I once gave her a silver rose to represent eternal love, though I later decided that that was a horrible symbol. Fortunately, &#8230;</p>
<p class="read-more"> <a class="" href="https://www.troyfawkes.com/spirituality-karma-little-things/"> <span class="screen-reader-text">Spirituality, Karma, and the Little Things</span> Read More &#187;</a></p>
<p>The post <a href="https://www.troyfawkes.com/spirituality-karma-little-things/">Spirituality, Karma, and the Little Things</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The end of high school and beginning of University, for me, was defined by a girl. She was smart, pretty, crazy in bed and just as romantic as I was at the time. I once gave her a silver rose to represent eternal love, though I later decided that that was a horrible symbol.</p>
<p>Fortunately, she gave me a much better symbol that I wear and have worn ever since it came to me. You&#8217;ve probably noticed it, and wondered about it, or asked about it. Or you don&#8217;t really care. That&#8217;s fine with me. Personally I&#8217;m just impressed that it&#8217;s been around so long and I haven&#8217;t either broken or lost it, given some of the absurd places it has wound up and been recovered from.</p>
<p>It doesn&#8217;t even matter what the symbol is. I&#8217;ve decided that when I do lose or break it, I&#8217;m going to find another trinket, of whichever variety, and put that in its place. I&#8217;m grateful that love, wisdom, time, and pain have imbued it with the characteristics that it has, but I&#8217;m also sure that those have the same haunting effect of standing out in a humid, rainy night with your lover; no matter which specifics you replace, you can&#8217;t escape the warm and fuzzies.</p>
<p>This meaning is one of my defining bits, so it&#8217;s not simple to share. I don&#8217;t know if you&#8217;ve ever told someone important to you about your passions, goals, dreams or accomplishments and had them scoff at it or give you a less than welcoming response. It&#8217;s almost as painful to see them respond the same way they did to your story about a co-worker&#8217;s cat. That&#8217;s generally how I expect to feel when I share something deep. What pushes me to share regardless of my worry is that even though I hardly know you, I&#8217;d much rather be hurt than pretend not to be me.</p>
<p>Plus, I have a sneaking suspicion that, if you&#8217;ve actually read this far, you&#8217;re open to my eccentricities, and just maybe you&#8217;ll feel closer to me knowing this little &#8220;secret.&#8221;</p>
<p>So what does my symbol mean to me? Well, it&#8217;s a conceit in the literary sense; an expanded metaphor. It helps me to think of it as one of my muses. An embodiment of an idea, with way too many pictures and backdrops to fully express, and one of the few parts of my life that I&#8217;m happy to leave unsimplified. Unfortunately for you, that means it&#8217;s a challenge to sum it up in a word, though I might say, &#8220;spirituality.&#8221;</p>
<p>I have other muses. These were easier to understand and explain when I wrote poetry, because it&#8217;s so expressive and complex (I try to use really simple, quick sentences in prose and I edit out uncommon words and sentence structures).</p>
<p>Love is an odd one, but I won&#8217;t have to try too hard to describe it since I wrote some poems on the subject back in the day:</p>
<blockquote><p><strong>Of a Perfect Love</strong></p>
<p>Quite often I dreamt thee<br />
In all thy beauty<br />
Heaven forgive, O Love<br />
Love, that I knew thee</p>
<p>There are pains in mine heart<br />
For summer&#8217;s flowers<br />
And memories of thine part<br />
In warm spring showers</p>
<p>Would that thee could exist<br />
Out of fantasy,<br />
O my love would persist<br />
If but once could I see&#8211;</p>
<p>Thyne starfall of eyes<br />
Silken moon-kissed hair<br />
Skin touched by sunrise<br />
I know thee so fair</p>
<p>Now if I should touch thee,<br />
Or meet thee in time<br />
Would that you could love me<br />
O dream of mine.</p>
<p><em>I believe this was inspired by <a href="http://www.bartleby.com/101/597.html">Byron</a>, &#8220;if I should meet thee after long years.&#8221;</em></p></blockquote>
<p>Alternately (titled as the first line, and a reference to one of my most influential relationships):</p>
<blockquote><p>This Song is worth the world to me<br />
Softly, it dances through the trees:<br />
It&#8217;s the air before the sun has risen<br />
The smile on the lips of the horizon.<br />
It reaches out and swooning speaks<br />
Of laughing children and of upturned beaks<br />
Little birds lively chirp its tune to me<br />
It crashes regularly as the sea<br />
And rushes forcefully as the buck through brush<br />
To pass and circle with a lover&#8217;s touch.</p>
<p>Why scared am I to hear you sing this Song?<br />
Will it glide right by me and move along<br />
Or break into unsweet bitter discord<br />
And shatter this chorus forever more?<br />
But sing again, ignore my frail heart,<br />
There is no end to such as did not start<br />
And Gods what start this Song has made in love<br />
A loss hurts less than never having does.<br />
And so I give to you my every thought<br />
And such as you can touch that I have wrought.</p>
<p>And so you hear my Muse upon her lyre,<br />
My words that leave sweet murmurs as they expire,<br />
My song that holds you in its mild embrace,<br />
Its ringing strings that set your heart to race,<br />
My thoughts that follow your every step<br />
My love that has never slept.<br />
But the walls dissolve,<br />
the roof falls,<br />
the sleeper wakes,<br />
the siren slithers beneath the waves,<br />
and all that&#8217;s left<br />
is golden boards and running paint&#8211;<br />
broken beneath the crag.</p></blockquote>
<p>And lastly:</p>
<blockquote><p><strong>The Tree</strong></p>
<p>She was the tree under which I lay;<br />
The dreams I had when I was young.</p>
<p>Her hair was green, wild, tied in leather,<br />
Her legs were roots, softened with rain,<br />
Her skin was bark, smelled lightly of heather,<br />
Acorns were eyes,<br />
Those hazelnut smiles,<br />
Whispery kisses,<br />
Unrelenting embraces.</p>
<p>Now she walks beside me,<br />
Now she touches my hand,<br />
Now she smiles and sings to me,<br />
A song I&#8217;ll never understand.</p></blockquote>
<p>To make matters worse, I read once of Cupid having two sets of arrows. One was tipped in gold, the other lead. The golden arrows made those hit fall in love, the lead arrows filled the target with hate. Cupid, of course, being a blind child, had no idea which arrow he was grabbing for, whatever his intentions might be. Even considering those intentions, we all know that just because one is in love doesn&#8217;t make them happy; what of the lover that relentlessly follows? Ignoring how he feels of the pursuit (though we shouldn&#8217;t, he probably feels like ass), you can imagine the problems if she isn&#8217;t interested.</p>
<p>Add to the emotions in the poems an image of a grown Cupid standing in the middle of a great hall surrounded by those he has hit with his arrows throughout the years. He takes off the blindfold and looks around. How does he feel?</p>
<p>Finally, you can take a read through <a href="http://www.troyfawkes.com/my-chinese-baby/">My Chinese Baby</a>, a story that led to one of the most beautiful periods in my life. You can maybe weakly summarize it by the line, &#8220;The problem with my lifestyle is that it’s dotted with missed chances &#8230; [I travel a lot] &#8230; I’m not holding my breath for one of these gems to look at me, smile, and say, &#8216;that sounds fun, can I join you?'&#8221;</p>
<p>And yet that isn&#8217;t even close to covering what I consider my muse for Love.</p>
<p>All of that to say, take whatever understanding you get of my Spirituality and broaden it 100 fold. The map isn&#8217;t the territory, it&#8217;s more of a kid messing around with crayons. Maybe, more of an emotion than a thought. It has pieces that come out and pieces that come in, and I&#8217;m not picky on the topic of whether to call it by the same name after everything&#8217;s been moved around (<a href="http://en.wikipedia.org/wiki/Ship_of_Theseus">thinking of this</a>).</p>
<p>My Spirituality has, as a center piece, the not well defined space of time when Christ was dead for three days. I&#8217;m not going to spend a lot of time defending the imagery; if you think this makes me Christian then go ahead :) It&#8217;s a book I&#8217;m very familiar with from my education. Christ can&#8217;t really die, right? What was he up to for three days?</p>
<p>I can&#8217;t remember where I got this concept, I just re-read the relevant biblical passages, an essay I wrote on the subject and three of the N-Town Plays (don&#8217;t ask) and can&#8217;t find it. But for some reason, I vividly recall the story of two farmers walking home the day after Christ died, and one turns to the other and says, &#8220;wasn&#8217;t there another walking with us?&#8221;</p>
<p>That&#8217;s it; it sounds really, horribly boring. But think of it. The bible is really heavy handed, usually. That&#8217;s one of the reasons I&#8217;m not a fan. In this case, the idea is very simple. Here he isn&#8217;t a physical embodiment, he&#8217;s just a presence the farmers felt with them on the road, listening. Of course, we know that he just happens to have an Arthurian sense of righteousness and very high standards.</p>
<p>Let&#8217;s pull it away from Christianity since that&#8217;s not really the scope. It&#8217;s a presence that I feel with me all of the time. It knows all of the scary little details about me. It knows that I haven&#8217;t called my grandma in a while. It knows I&#8217;m a pitiful excuse for a present wrapper. It knows what kind of porn I watch. And yeah, it judges me, and lets me know how it feels about really intense yoga sex (honestly, not super offended).</p>
<p>That&#8217;s kind of the key. It&#8217;s rigid in the sense that it&#8217;s imbued with all of my experiences, what I&#8217;ve seen bring good to the world and what I&#8217;ve seen bring bad.</p>
<p>It knows what happened when I tried the open relationship thing with a girl who didn&#8217;t really want it. I thought it&#8217;d be OK since we had &#8220;the conversation&#8221; before we got serious. She said that she would rather just have me, but understood that I wasn&#8217;t at that point in my life and, if it was what we could have together, she was OK with it. I didn&#8217;t believe her, but at the time I decided that she had agreed to both of us having the privilege to love each other but not exclusively, and therefore it was OK. Guess how that turned out.</p>
<p>It knows that I once was a home wrecker with strict morality around, &#8220;she must pass these three absurd criteria.&#8221; Those criteria being, she must be the one to initiate anything physical, she must explicitly ask for sex, and she must tell me outright that she wants to cheat on her boyfriend. Despite how ridiculous it sounds, no that wasn&#8217;t enough to prevent catastrophe. The only time I&#8217;ve had this experience afterwards was when the girl just didn&#8217;t tell me she had a boyfriend. It&#8217;s now to the point that I need her to explicitly say, &#8220;I don&#8217;t have a boyfriend.&#8221; If you know me extremely well, you might already know of the wonderful email I have sitting in my archives for reference in case I get murdered the next time I go to Sweden, from an otherwise lovely girl I dated for three weeks who apparently had a long-time boyfriend at the time. That experience haunts me, even though I had no idea and would never have hooked up with her knowing it given my past experiences.</p>
<p>It also knows that I&#8217;m the guy who does little, thoughtful things for people on a daily basis without expecting anything in return. It knows I&#8217;m a fantastic wingman, to my own detriment. It knows that I&#8217;m the one standing outside of the bus shelter in the cold, windy night so that you can fit snugly in, and I tried to make my leaving look natural so that you didn&#8217;t feel the uncomfortable need to owe me a favour.</p>
<p>It knows that I&#8217;m the guy who gets people jobs, leads and clients. It knows that I stay up late making sure you&#8217;re OK, even though you haven&#8217;t called in years. It knows that I fought for you behind closed doors, but didn&#8217;t take credit for the positive things that happened in your life; I was just happy to see you get what you deserved.</p>
<p>The presence is also imbued with some rules I&#8217;ve found to hold true in general, but they&#8217;re even more complex. You can read about some of them <a href="http://www.troyfawkes.com/the-presuppositions-of-nlp/">here</a> and <a href="http://www.troyfawkes.com/one-last-presupposition-of-nlp/">here</a>.</p>
<p>But the act of waking up every morning, as I have every morning for the past six years or so, and putting that symbol around my neck, constantly reminds me of all of the aspects of my spirituality. It reminds me to be a bit better every day, to question comfortable states since they might not match my criteria, and most importantly to try to understand myself a bit better so as not to be such a dick tomorrow.</p>
<p>It&#8217;s nice having something with a physical weight, that I can touch, that reminds me of what I aspire to be.</p>
<p>The post <a href="https://www.troyfawkes.com/spirituality-karma-little-things/">Spirituality, Karma, and the Little Things</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.troyfawkes.com/spirituality-karma-little-things/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>The Basics of Python Multithreading and Queues</title>
		<link>https://www.troyfawkes.com/learn-python-multithreading-queues-basics/</link>
					<comments>https://www.troyfawkes.com/learn-python-multithreading-queues-basics/#disqus_thread</comments>
		
		<dc:creator><![CDATA[Troy Fawkes]]></dc:creator>
		<pubDate>Fri, 24 Jan 2014 03:13:23 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<guid isPermaLink="false">http://www.troyfawkes.com/?p=1055</guid>

					<description><![CDATA[<p>I&#8217;ve never been a fan of programmer-speak. It sometimes feels like people make code, processes and even documentation opaque on purpose. Multithreading in Python, for example. Or how to use Queues. So here&#8217;s something for myself next time I need a refresher. It&#8217;s the bare-bones concepts of Queuing and Threading in Python. Let&#8217;s start with &#8230;</p>
<p class="read-more"> <a class="" href="https://www.troyfawkes.com/learn-python-multithreading-queues-basics/"> <span class="screen-reader-text">The Basics of Python Multithreading and Queues</span> Read More &#187;</a></p>
<p>The post <a href="https://www.troyfawkes.com/learn-python-multithreading-queues-basics/">The Basics of Python Multithreading and Queues</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>I&#8217;ve never been a fan of programmer-speak. It sometimes feels like people make code, processes and even documentation opaque on purpose.</p>



<p>Multithreading in Python, for example. Or how to use Queues.</p>



<p>So here&#8217;s something for myself next time I need a refresher. It&#8217;s the bare-bones concepts of Queuing and Threading in Python.</p>



<h2 class="wp-block-heading">Let&#8217;s start with Queuing in Python.</h2>



<p>Before you do anything else, import Queue.</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>from Queue import Queue</code></pre></div>



<p>A queue is kind of like a list:</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>my_list = []
my_list.append(1)
my_list.append(2)
my_list.append(3)
print my_list.pop(0)
# Outputs: 1</code></pre></div>



<p>The above code creates a list, assigns it three values, then removes the first value in so the list now has only 2 values (which are 2 and 3).</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>my_queue = Queue(maxsize=0)
my_queue.put(1)
my_queue.put(2)
my_queue.put(3)
print my_queue.get()
my_queue.task_done()
# Outputs: 1</code></pre></div>



<p>There are only a couple differences in how queues work visually. First we set a maximum size to the queue, where 0 means infinite. It&#8217;s pretty dumb but I&#8217;m sure it&#8217;s useful somehow.</p>



<p>The second visual difference is the <strong>task_done()</strong> bit at the end. That tells the queue that not only have I retrieved the information from the list, but I&#8217;ve finished with it. If I don&#8217;t call task_done() then I run into trouble in threading. So let&#8217;s just say in Queues, you have to call this.</p>



<p>The big important point about Queues is that they work really well with threading. In fact, you just can&#8217;t use lists the way you can use queues in threading. That&#8217;s why I&#8217;m even bothering to bring them up here.</p>



<p>Here&#8217;s an example of a simple program that uses Queues:</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>from Queue import Queue

def do_stuff(q):
  while not q.empty():
    print q.get()
    q.task_done()

q = Queue(maxsize=0)

for x in range(20):
  q.put(x)

do_stuff(q)</code></pre></div>



<p>It outputs 0-19. In like the most complicated way possible to output 0-19.</p>



<p>Notice how do_stuff() is just whipping through the whole queue. That&#8217;s nice. But what if it was trying to do a big task, or a task that required a lot of waiting (like pulling data from APIs)? Assume for example that do_stuff() takes 30 second to run each time and it&#8217;s just waiting on stupid APIs to return something. The function would take 30 seconds every time it ran, and it would run 20 times so it would take 10 minutes to get through just 20 items. That&#8217;s really shitty.</p>



<h2 class="wp-block-heading">Enter Python Threading.</h2>



<p>Start with importing the right stuff:</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>from Queue import Queue
from threading import Thread</code></pre></div>



<p>Threads are probably really complex. Or so I&#8217;m lead to believe. All you need to know for now, though, is that they use a worker function to get stuff done, they run at the same time, and you can pull them all together when they&#8217;re done. So first you need to set up a worker function:</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>def do_stuff(q):
  while True:
    print q.get()
    q.task_done()</code></pre></div>



<p>We&#8217;re more or less just stealing the function from the last bit except we&#8217;re setting it up for an infinite loop (while True). It just means that I want my threads always ready to accept new tasks.</p>



<p>Now I want to create the actual threads and set them running. <strong>Before I do that, though</strong>, I need to give them a Queue to work with. The Queue doesn&#8217;t have to have anything on it, it just needs to be defined so that my threads know what they&#8217;ll be working on. Here&#8217;s how I set my (10) threads running:</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>q = Queue(maxsize=0)
num_threads = 10

for i in range(num_threads):
  worker = Thread(target=do_stuff, args=(q,))
  worker.setDaemon(True)
  worker.start()</code></pre></div>



<p>So you see the Queue set up (as &#8220;q&#8221;), then I define a loop to run the thread creation bits 10 times. The first line in the loop sets up a thread and points it first at the do_stuff function, and then passes it &#8220;q&#8221; which is the Queue we just defined. Then something about a daemon, and we start the bugger. That&#8217;s 10 threads running (remember the infinite loop in do_stuff()?) and waiting for me to put something in the Queue.</p>



<p>The rest of the code is the same as the Queue example so I&#8217;m just going to put it all together and let you figure it out:</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>from Queue import Queue
from threading import Thread

def do_stuff(q):
  while True:
    print q.get()
    q.task_done()

q = Queue(maxsize=0)
num_threads = 10

for i in range(num_threads):
  worker = Thread(target=do_stuff, args=(q,))
  worker.setDaemon(True)
  worker.start()

for x in range(100):
  q.put(x)

q.join()</code></pre></div>



<p>The only bit that should be new is the <strong>q.join()</strong> bit right at the end. This basically just waits until the queue is empty and all of the threads are done working (which it knows because <strong>task_done()</strong> will have been called on every element of the queue). If you were running a program in batches, you might use q.join() to wait for the batch to finish and then write the results to a file, and then just throw more tasks into the queue.</p>



<p>Consider revising the last 3 lines into a loop:</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python"><code>for y in range (10):
  for x in range(100):
    q.put(x + y * 100)
  q.join()
  print &quot;Batch &quot; + str(y) + &quot; Done&quot;</code></pre></div>



<p>It&#8217;s cool that Queues can get added to willy nilly and these Threads will just pick them up, and whenever I want to I can stop and join all of them together for a second so I can check in, maybe write to a file or database or just let the user know that I&#8217;m still working away.</p>



<p>Remember the example I gave before about each run of do_stuff() taking 30 seconds? And since I had to run it 20 times it&#8217;d take 10 minutes? Now I can just run 20 different threads and the whole program will be done in about 30 seconds rather than 10 minutes. Obviously your results may vary, but it&#8217;s definitely faster.</p>



<p>In any case, hope this helped. If you want the nitty gritty details, go read the documentation. This should get you started though.</p>
<p>The post <a href="https://www.troyfawkes.com/learn-python-multithreading-queues-basics/">The Basics of Python Multithreading and Queues</a> appeared first on <a href="https://www.troyfawkes.com">Troy Fawkes</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.troyfawkes.com/learn-python-multithreading-queues-basics/feed/</wfw:commentRss>
			<slash:comments>56</slash:comments>
		
		
			</item>
	</channel>
</rss>
