Sagnik Nandy, Distinguished Engineer, Google Analytics

Sagnik Nandy, Distinguished Engineer, Google Analytics

Integrations are among the most important value adds that Google Analytics provides, making it possible to combine both pre visit and visit data to paint a complete end-to-end picture of a visitor’s journey through a business. Integrations provide several kinds of important insights/analysis ranging from providing deep insights into what ads lead to high quality traffic (e.g. AdWords integration) to how to better monetize your content (e.g. AdSense integration). Also, Daniel is one of the best people to educate folks on the value and power of these integrations. I have known Daniel for several years now and he is easily among the most knowledgeable people I know when it comes to Analytics. He has worked closely with several businesses and publishers and helped them succeed and it is great to get these deep insights directly from him.


Online Behavior – Marketing Measurement & Optimization

FacebookTwitterGoogle+LinkedInEmailPinterest

Google Photos: Your New Photo App

Well, Google has just released the world’s smartest Photo App, one that is powered by some serious machine learning tech so that it can automatically catalogue, learn and organise your photos for you. With Facial, Location and Object recognition (eg. Google Photos automatically detects 250,000 popular landmarks worldwide) the Photos app does a great job […]


Digital Buzz Blog

FacebookTwitterGoogle+LinkedInEmailPinterest

Recreating Photoshop Effects in CSS – Part 2 – The CSS Code

In part 1 of this tutorial series I demonstrated how to create vector shape buttons with layer styles in Photoshop. For part 2 I’ll explain how to write code to recreate these layer styles in CSS.

Modern development techniques have advanced along with browser support to make CSS3 a viable option for everyone. Photoshop layer styles such as drop shadows and gradients originally required images. Now it’s possible to create these effects with nothing more than CSS3.

css3 buttons final preview screenshot

If you want to see the final outcome check out my preview on CodePen which you can edit and reuse for your own project work.

View Full Source Code

HTML/CSS Document Structure

First we need to create the document for housing this code. It’s a good idea to use the HTML5 doctype and possibly create a new stylesheet for the CSS code.

<!doctype html> <html lang="en-US"> <head>   <meta charset="utf-8">   <meta http-equiv="Content-Type" content="text/html">   <title>SpyreStudios Buttons in CSS3</title> </head>  <body> </body> </html> 

Notice I have a very barren header with only the essentials. This is going to be a really simple document because we’re just creating a few buttons, so there really isn’t a lot to worry about.

In the page body we need a couple elements for containing the buttons. I’m creating an outer container with the ID #wrapper to center everything on the page. Inside the wrapper are two containers with the class .btnrow.

Each button row holds an individual button. We actually could use anchor elements but I’ve gone the traditional route and used HTML button elements. Here’s what my body HTML looks like:

<body>   <div id="wrapper">     <div class="btnrow">       <button class="btn1">Click Me</button>     </div>          <div class="btnrow">       <button class="btn2">Click Me</button>     </div>   </div>  </body> 

Now that each button has been defined with a unique class we can go ahead and work in CSS.

Styling Button Set #1

During the CSS development process it will help to keep your PSD file open as a reference. This way you can check layer style values for shadow sizes and gradient colors.

My first button class .btn1 is 200px wide and 40px tall. Obviously in CSS this is flexible, but in Photoshop we used these numbers just because we needed to pick something.

.btn1 {   cursor: pointer;   width: 200px;   height: 40px;   text-align: center;   color: #fff;   font-size: 16px;   font-weight: bold;   text-shadow: 1px 1px 0 #3d628f;   border: 1px solid #3980d2;   background: #68a2f0;   background: -moz-linear-gradient(top,  #68a2f0 0%, #4b83c3 100%);   background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#68a2f0), color-stop(100%,#4b83c3));   background: -webkit-linear-gradient(top,  #68a2f0 0%,#4b83c3 100%);   background: -o-linear-gradient(top,  #68a2f0 0%,#4b83c3 100%);   background: -ms-linear-gradient(top,  #68a2f0 0%,#4b83c3 100%);   background: linear-gradient(to bottom,  #68a2f0 0%,#4b83c3 100%);   filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#68a2f0', endColorstr='#4b83c3',GradientType=0 );   border-radius: 5px;   outline: none; } 

First off each button needs to give the impression of a natural link hover. This is created by forcing the cursor to look like a pointer hand at all times. Next I’ve defined text colors and text shadow effects.

The gradient is undoubtedly the trickiest part. CSS3 has various prefixes for gradients that allow developers to maintain integrity dating back to IE6. I’ve used the ColorZilla Generator to create the base code for this tutorial.

Just select your button’s layer styles and open the gradient editor. From here you can copy both color values into Notepad or a blank document and then copy them into the ColorZilla webapp. This way you’ll save time and generate more accurate gradients.

The last point to make is my use of the outline property. In certain WebKit browsers(particularly Chrome) a blue outline is added to active elements. This is distracting and takes away from the inset shadow effect, so I’ve remove the outline entirely. In most cases you should remove the outline globally using a CSS reset snippet like Eric Meyer’s template.

.btn1:hover {   background: #8cbaf8;   background: -moz-linear-gradient(top,  #8cbaf8 0%, #5c93d5 100%);   background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#8cbaf8), color-stop(100%,#5c93d5));   background: -webkit-linear-gradient(top,  #8cbaf8 0%,#5c93d5 100%);   background: -o-linear-gradient(top,  #8cbaf8 0%,#5c93d5 100%);   background: -ms-linear-gradient(top,  #8cbaf8 0%,#5c93d5 100%);   background: linear-gradient(to bottom,  #8cbaf8 0%,#5c93d5 100%);   filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#8cbaf8', endColorstr='#5c93d5',GradientType=0 ); } .btn1:active {   color: #afc3da;   border: 0;   background: #2e4a6b;   background: -moz-linear-gradient(top,  #2e4a6b 0%, #34639a 100%);   background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#2e4a6b), color-stop(100%,#34639a));   background: -webkit-linear-gradient(top,  #2e4a6b 0%,#34639a 100%);   background: -o-linear-gradient(top,  #2e4a6b 0%,#34639a 100%);   background: -ms-linear-gradient(top,  #2e4a6b 0%,#34639a 100%);   background: linear-gradient(to bottom,  #2e4a6b 0%,#34639a 100%);   filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#2e4a6b', endColorstr='#34639a',GradientType=0 );   -webkit-box-shadow: inset 3px 0 10px #21364f;   -moz-box-shadow: inset 3px 0 10px #21364f;   box-shadow: inset 3px 0 10px #21364f; } 

Both hover & active states are created using very similar syntax. Gradients are updated when the user clicks or hovers over the button. Additionally during the active state the text color changes and the button gains an inner shadow.

If you don’t need all of these gradient properties feel free to removes the extraneous ones. I’ve written this code to be as compatible as possible to reach the widest audience of Internet users.

Styling Button Set #2

The second button style is a bit more complicated, but follows many of the same rules. We’re using the typical HTML button attribute with a class of .btn2.

I’ve copied many of the same styles for text color, button size, and mouse cursor icon. One major difference is the gradient code which now includes two distinct stops around 50%.

.btn2 {   cursor: pointer;   width: 200px;   height: 50px;   text-align: center;   color: #fff;   font-size: 20px;   font-weight: bold;   text-shadow: 2px 1px 1px #386379;   border: 1px solid #3180a7;   background: #6dbfe8;   background: -moz-linear-gradient(top,  #6dbfe8 0%, #28a1de 50%, #28a1de 50%, #1f8cc2 51%, #1f8cc2 51%, #33a0d6 100%);   background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#6dbfe8), color-stop(50%,#28a1de), color-stop(50%,#28a1de), color-stop(51%,#1f8cc2), color-stop(51%,#1f8cc2), color-stop(100%,#33a0d6));   background: -webkit-linear-gradient(top,  #6dbfe8 0%,#28a1de 50%,#28a1de 50%,#1f8cc2 51%,#1f8cc2 51%,#33a0d6 100%);   background: -o-linear-gradient(top,  #6dbfe8 0%,#28a1de 50%,#28a1de 50%,#1f8cc2 51%,#1f8cc2 51%,#33a0d6 100%);   background: -ms-linear-gradient(top,  #6dbfe8 0%,#28a1de 50%,#28a1de 50%,#1f8cc2 51%,#1f8cc2 51%,#33a0d6 100%);   background: linear-gradient(to bottom,  #6dbfe8 0%,#28a1de 50%,#28a1de 50%,#1f8cc2 51%,#1f8cc2 51%,#33a0d6 100%);   filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#6dbfe8', endColorstr='#33a0d6',GradientType=0 );   border-radius: 3px;   outline: none;   box-shadow: inset 0 1px 1px rgba(255,255,255,0.7); } 

Take note that CSS gradient syntax is very flexible and allows for anything you can imagine. It works very much like Photoshop where you can specifically force certain colors to appear at certain intervals.

.btn2:hover {   background: #5ba8d5;   background: -moz-linear-gradient(top,  #5ba8d5 0%, #2c8cc0 50%, #267eac 51%, #3190c2 100%);   background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#5ba8d5), color-stop(50%,#2c8cc0), color-stop(51%,#267eac), color-stop(100%,#3190c2));   background: -webkit-linear-gradient(top,  #5ba8d5 0%,#2c8cc0 50%,#267eac 51%,#3190c2 100%);   background: -o-linear-gradient(top,  #5ba8d5 0%,#2c8cc0 50%,#267eac 51%,#3190c2 100%);   background: -ms-linear-gradient(top,  #5ba8d5 0%,#2c8cc0 50%,#267eac 51%,#3190c2 100%);   background: linear-gradient(to bottom,  #5ba8d5 0%,#2c8cc0 50%,#267eac 51%,#3190c2 100%);   filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#5ba8d5', endColorstr='#3190c2',GradientType=0 ); } .btn2:active {   color: #add1e4;   border: 0;   background: #155f86;   background: -moz-linear-gradient(top,  #155f86 0%, #2880ae 75%);   background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#155f86), color-stop(75%,#2880ae));   background: -webkit-linear-gradient(top,  #155f86 0%,#2880ae 75%);   background: -o-linear-gradient(top,  #155f86 0%,#2880ae 75%);   background: -ms-linear-gradient(top,  #155f86 0%,#2880ae 75%);   background: linear-gradient(to bottom,  #155f86 0%,#2880ae 75%);   filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#155f86', endColorstr='#2880ae',GradientType=0 );   box-shadow: inset 0 4px 15px rgba(0,0,0,0.3), 0 1px 0 0 rgba(255,255,255,0.7);   } 

The hover class basically uses the exact same code but with a darker gradient.

Looking over the :active pseudo-class you’ll notice that it’s got a few interesting properties. I’ve updated the text color and shadow just like in the first button.

The button border has also been removed to create the effect of recession into the page.

What’s different this time is that I’m using two distinct box shadow effects. The first is an inset shadow which spreads out at 15px blur streaming down from the top. It makes the button feel more 3D as if a shadow is being cast on top of the gradient.

The secondary outer shadow becomes a thin 1px edge at the very bottom of the button. This represents a glossy lip at the corner of an edge which becomes more noticeable when the button “moves down” into the page.

All-in-all it’s pretty darn simple to recreate Photoshop styles once you get the hang of CSS3 syntax.

Wrap-Up

In this two-part series I’ve demonstrated how to create stylish buttons from a blank canvas and then transform them into working buttons via CSS3. If you want to improve your design/dev workflow then practice by making little interfaces similar to the buttons we created here.

Also feel free to download a copy of the PSD or edit my HTML/CSS source directly.

With this simple demonstration you should have a much better idea of the steps and skills required to create interactive elements for the web.

The post Recreating Photoshop Effects in CSS – Part 2 – The CSS Code appeared first on SpyreStudios.


SpyreStudios

FacebookTwitterGoogle+LinkedInEmailPinterest

Babak Pahlavan, Director of Product Management, Google Analytics

Babak Pahlavan, Director of Product Management, Google Analytics

Daniel’s insightful recommendations on how to make digital analytics more actionable via integration are well researched and tightly presented in this wonderful book. This is a must read for analytics users and marketers!


Online Behavior – Marketing Measurement & Optimization

FacebookTwitterGoogle+LinkedInEmailPinterest

Sponsor: Hiveage — Fast, Simple, and Free Online Invoicing

Hiveage saves you time and money by automating your invoicing and accounting. Manage your contacts, send estimates, convert them to invoices, track time and expenses and accept online payments, all from one beautiful interface. With a single Hiveage account you can even manage multiple teams and businesses.

Try Hiveage for free!

Direct Link to ArticlePermalink


Sponsor: Hiveage — Fast, Simple, and Free Online Invoicing is a post from CSS-Tricks

CSS-Tricks

FacebookTwitterGoogle+LinkedInEmailPinterest

Meet FOVE VR: The Oculus Rift Killer

FOVE VS is claiming to be the world’s smartest VR Headset system, ultimately powered by advanced eye-tracking technology inside the headset so that you get seamless interactivity in any virtual world you might play. Which arguably makes it an Oculus Rift Killer, if they can get it to market fast enough. FOVE tracks a user’s […]


Digital Buzz Blog

FacebookTwitterGoogle+LinkedInEmailPinterest

Getting Acquainted with Initial

If someone walked up to me the other day and asked me what the difference between inherit and initial is, I may have replied:

“What, there’s a difference?”

I’ve been writing CSS for more than ten years, but I’ve somehow escaped understanding what exactly initial is or does. Call it ignorance, laziness, or luck, but inherit has gotten me by and I never thought to look up when initial might be used instead. So, this post is gonna share some of the things I learned.

What initial means

First off, the spec helps us understand the difference between an initial keyword and an initial value.

  • Initial keyword: If the cascaded value of a property is the initial keyword, the property’s initial value becomes its specified value.
  • Initial value: Each property has an initial value, defined in the property’s definition table. If the property is not an inherited property, and the cascade does not result in a value, then the specified value of the property is its initial value.

Umm, okay. I ran those definitions through Google Translate (joking!) and came out with this:

The initial keyword is what is declared as the property where the initial value is the resulting output, as defined by the browser default.

So, if the initial keyword is used here:

.module {   color: initial; }

…then the initial value might return as black, if black is the browser default for that element’s property.

How it is different from inherit

If you’re thinking this sounds a lot like inherit, then you’re absolutely right. It does sounds a heck of lot like that.

But initial and inherit are distinct in the extra step that inherit takes to check whether there are other properties it can use in the cascade before it moves to the initial value.

H1 is looking to inherit a color value, which it finds in the body element.

H1 is told to use its initial value, so it skips over the body element and goes to its roots.

An example of the difference

See the Pen CSS Initial vs. Inherit by CSS-Tricks (@css-tricks) on CodePen.

See that? The properties in the left box are all set to inherit the values of the .module class since it the parent element. On the flip side, the properties in the right box are set to initial, which resets the element’s properties to the browser defaults.

When to use initial

I like to think of initial as a hard reset. It’s easy for styles to get convoluted as CSS grows, and using initial is a way to clear things out so an element can go back to its natural state of being. If initial were old-school Nintendo, I would use it as the equivalent to pulling out a buggy game cartridge from the console and blowing into it (even though doing so supposedly had no effect).

But that doesn’t mean initial is a silver bullet for resets. That’s because initial values are still subject to browser defaults, which we know can vary from browser to browser.

Oh wait, you use CSS resets? You can expect those to be used as initial values instead.

Bottom line: I would use initial to completely wipe out any inherited styles from an element and use inherit to make sure the element takes its cues from the nearest parent.

A more practical use case

Here’s an example of how initial can be used to create alternating colored lines in tables.

See the Pen CSS Initial by CSS-Tricks (@css-tricks) on CodePen.

Browser Support

MDN has a nice breakdown of the current support for initial. Note the glaring lack of IE support.

Chrome Safari Firefox Opera IE Android iOS
Yes Yes 19 15 No Yes Yes

Wrapping Up

I’ve been racking my brain for some interesting use cases for initial. While I see a lot of potential usefulness in being able to use default styles on an element, I just haven’t come across them in a practical application—though that could say a lot more about me than the property value itself.

Where this will come in real handy is when all gains more support as a property. That would make declaring all: initial a real powerful tool for creating resets on any element.

Please share any situations where initial was something you had to use in a project. Bonus points if you’ve used it for any tricky feats.


Getting Acquainted with Initial is a post from CSS-Tricks

CSS-Tricks

FacebookTwitterGoogle+LinkedInEmailPinterest

Building Google Analytics Powered Widgets

Google Analytics Powered Widgets

There is a lot of useful and interesting data held in your Google Analytics account that could be used to drive content on your site and apps. For example, you might want to show your website visitors what are the most viewed products, or the most viewed articles, or the best performing authors, etc.

In this tutorial I provide a step-by-step guide showing how to create a Top Authors widget using the Google Analytics API, Google App Engine (Python) and Google Tag Manager. You can create a free Google App Engine account that should give you enough allowance to build and use your widget. You can see the end result of this tutorial right there on the right hand side of this site, see “Top Authors” widget.

There are 2 reasons we are using Google App Engine as a proxy instead of just calling the Google Analytics API directly:

  • Avoid exposing any sensitive information held in Google Analytics. Eg. Instead of sharing pageviews we will calculate and share a percentage of the maximum pageviews instead.
  • There is a limit to the number of API calls that can be made and with this method we only need to call the API once a day as we will cache the results. Therefore we don’t risk exceeding the API quota; also, as the data is cached, the results will return a lot faster.

The steps below will take you through all the way from creating your app engine project to adding the widget to your site using Google Tag Manager.

  1. Create a New Google Cloud Project
  2. Create Your Google App Engine App
  3. Enable the Google Analytics API
  4. Use Import.io To Scrape Extra Data
  5. Create the Top Authors API
  6. Serve the Widget using Google Tag Manager

1. Create a New Google Cloud Project

If you have not used Google cloud before sign up and create a new project at https://console.developers.google.com. For this tutorial you will be using the free version of App Engine and therefore you do not need to enable billing. Name the project and create a brand friendly project id as this will become your appspot domain, eg. yourbrandwidgets.appspot.com

Google Cloud Project

2. Create Your Google App Engine App

Download the Google App Engine SDK for Python and create a folder on your computer called yourbrandwidgets.

In the folder create a file called app.yaml and add the code below. This is the configuration file and it is important that the application name matches the the project ID created in the first step.

application: onlinebehaviorwidgets
version: 1
runtime: python27
api_version: 1
threadsafe: yes

handlers:
- url: .*
  script: main.app

libraries:
- name: jinja2
  version: "2.6"
- name: markupsafe
  version: "0.15"

In the folder create a file called main.py and add the following code

from flask import Flask

app = Flask(__name__)
app.config['DEBUG'] = True

# Note: We don't need to call run() since our application is embedded within the App Engine WSGI application server.

@app.route('/')
def home():
    """Return a friendly HTTP greeting."""
    return 'Online Behavior Widgets'

@app.errorhandler(404)
def page_not_found(e):
    """Return a custom 404 error."""
    return 'Sorry, nothing at this URL.', 404

Create a file called appengine_config.py and add the following code.

"""'appengine_config' gets loaded when starting a new application instance."""
import sys
import os.path

# add 'lib' subdirectory to 'sys.path', so our 'main' module can load third-party libraries.

sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'lib'))

Create a folder called lib in the main folder.

Download the file called google-api-python-client-gae-.zip from this page.

Unzip the folder and add the 4 folders to the lib folder in your project.
Install the other required libs for Flask by creating a file called requirements.txt and add the following text.

# This requirements file lists all third-party dependencies for this project.
# Run 'pip install -r requirements.txt -t lib/' to install these dependencies in 'lib/' subdirectory.
# Note: The 'lib' directory is added to 'sys.path' by 'appengine_config.py'.
Flask>=0.10

Run pip install -r requirements.txt -t lib/ in the terminal install these dependencies. You should now be ready to test locally. Using the Google App Engine Launcher add the application as described in this tutorial.

Then, select the app as shown in the screenshot below and click run; this will run locally and open a new tab in your current open browser.

Run Widget Locally

If this works as expected you should be able to visit the site on your localhost at the port you set.

You are now ready to deploy this to the cloud. Click deploy and keep an eye on the logs to check that there are no errors.

if successful you can test the the app at yourbrandwidgets.appspot.com.

3. Enable the Google Analytics API

To use the Google Analytics API you will need to enable it for your project. Go to the API portal in the developer console under APIs & Auth and click on the Analytics API as shown in the screenshot below. Then, click on the Enable API button.

Enable Google Analytics API

Get the App Engine service account email, which will look something like yourbrandwidgets@appspot.gserviceaccount.com, under the Permissions tab following the steps shown in the screenshot below and add the email to your Google Analytics account with collaborate, read and analyze permission (learn more about User Permissions).

Google Analytics Permissions

4. Use Import.io To Scrape Extra Data

One issue we had while creating the widget in the sidebar of this site was that the author images and links are not stored in Google Analytics. We therefore have 2 options to overcome this.

Option 1

If you are using Google Tag Manager, create a variable to capture the author image and author urls on each pageview as custom dimensions.

Option 2 (the option we will use in this tutorial)

We used import.io to scrape the authors page and turn it into an API that we can use in app engine.

In order to see how this works, go to https://import.io and copy and paste this URL into the box and press try it out. You should see the page scraped into a structured format that you can use by clicking on the Get API button, as shown below.

import.io API

As you can see, the API has a record for each author in a neat JSON format including the 3 pieces of data we needed. The author’s name is under "value", the author’s page link is under "picture_link" and the author’s image is under "picture_image". That really is magic.

We can now create a function in our code that will call the import.io api, extract the 3 data points that we need, cache it for 24 hours, and the returns the result. We can test the result of this by creating an url for this. Update the main.py file with this code. You will notice we have now included some new modules at the top.

import json
import pickle
import httplib2

from google.appengine.api import memcache
from google.appengine.api import urlfetch
from apiclient.discovery import build
from oauth2client.appengine import OAuth2Decorator
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from oauth2client.appengine import AppAssertionCredentials
from flask import Flask
from flask import request
from flask import Response

app = Flask(__name__)
app.config['DEBUG'] = True

# Note: We don't need to call run() since our application is embedded within the App Engine WSGI application server.

@app.route('/')
def hello():
    """Return a friendly HTTP greeting."""
    return 'Hello World!'

@app.route('/importioauthors.json')
def importio():
    authors = importioOnlineBehaviorAuthors()

    return json.dumps(authors)

@app.errorhandler(404)
def page_not_found(e):
    """Return a custom 404 error."""
    return 'Sorry, nothing at this URL.', 404

def importioOnlineBehaviorAuthors():

    ob_authors_check = memcache.get('importioOnlineBehaviorsAuthors')
    if ob_authors_check:
        ob_authors_output = pickle.loads(memcache.get('importioOnlineBehaviorsAuthors'))
        ob_authors_output_method = 'memcache'
    else:
        importio_url = "https://api.import.io/store/data/6f4772f4-67ce-4f78-83f3-fa382e87c658/_query?input/webpage/url=http%3A%2F%2Fonline-behavior.com%2Fabout%2Fauthors&_user=ENTER-YOUR-USERID-HERE&_apikey=ENTER-YOUR-API-KEY-HERE"
        importio_url_result = urlfetch.fetch(importio_url)
        importio_result = json.loads(importio_url_result.content)
        importio_author_images = {}

        for row in importio_result['results']:
            name = row['value']
            importio_author_images[name] = {
                    'picture_image': row['picture_image'],
                    'picture_link': row['picture_link']
                    }

        ob_authors_output = importio_author_images

        memcache.set('importioOnlineBehaviorsAuthors', pickle.dumps(ob_authors_output), 86400)

    return ob_authors_output

You can run this locally or deploy to live and then go to yourbrandwidgets.appspot.com/importioauthors.json to test this is working.

5. Create the Top Authors API

The code shown below will authenticate and call the Google Analytics API using the App Engine service account email we added earlier. As you will see in the API request below, we are getting Unique Pageviews for the top 20 authors from the past 30 days. The code then stitches the import.io data to the Google Analytics data so that we have the author images and links ready to be used.

The results are cached for 24 hours so that the API is only called once a day for all users and returns the data in the callback function name we define when calling the URL.
Add the following code to your main.py file above the line of code @app.errorhandler(404)

@app.route('/topauthors.jsonp')
def topauthors():
    # Get the callback function name from the URL
    callback = request.args.get("callback")

    # Check if the data is stored in the cache (it resets after 24 hours)
    output_check = memcache.get('gaApiTopAuthors')

    # If yes then used the cached data in the response
    if output_check:
      output = pickle.loads(memcache.get('gaApiTopAuthors'))

      # If no then request the Google Analytics API
    else:

      # Authenticate and connect to the Google Analytics service
      credentials = AppAssertionCredentials(
      scope='https://www.googleapis.com/auth/analytics.readonly')
      http = credentials.authorize(httplib2.Http(memcache))
      analytics = build("analytics", "v3", http=http)

      # Set the Google Analytics View ID
      view_id = '32509579'

      # Set the report options
      result = analytics.data().ga().get(
        ids='ga:' + view_id,
        start_date='30daysAgo',
        end_date='yesterday',
        dimensions='ga:contentGroup2',
        metrics='ga:uniquePageviews',
        sort='-ga:uniquePageviews',
        filters='ga:contentGroup2!~Online Behavior|admin|(not set)|Miklos Matyas',
        max_results='20'
        ).execute()

      # Get the authors extra data
      authors = importioOnlineBehaviorAuthors()

      # Loop through the results from Google Analytics API and push into output only the data we want to share publicly
      output = []
      max_unique_pageviews = float(result['rows'][0][1])

      for row in result['rows']:
        author = row[0]
        unique_pageviews = float(row[1])
        perc_of_max = str(int(100*(unique_pageviews/max_unique_pageviews)))

        # Only push the author if their image and link exist in the import.io API
        if (author in authors):
            output.append({
              "author":author,
              "perc":perc_of_max,
              "image":authors[author]['picture_image'],
              "link":authors[author]['picture_link']
              })

      # Save the output in cache for 24 hours (60 seconds * 60 minutes * 24 hours)
      memcache.set('widgetTopTenAuthors', pickle.dumps(output), 86400)

    # Create the response in the JSONP format
    jsonp_callback = callback+'('+json.dumps(output)+')'

    resp = Response(jsonp_callback, status=200, mimetype='application/json')
    resp.headers['Access-Control-Allow-Origin'] = '*'

    # Return the response
    return resp

You will not be able to test this locally as it accesses the Google Analytics API so you will have to deploy to App Engine to see the output.

If it is all working as expecting you should see the result by directly accessing the URL in the browser. eg. http://yourbrandwidgets.appspot.com/topauthors.jsonp?callback=anyFunctionName

You can check for any errors in the developer console under Monitoring > Logs. Select App Engine and click the refresh icon on the right to see the latest logs for every time a URL is requested.

Developer Console Logs

6. Serve the Widget using Google Tag Manager

Using the API we just created, which returns the top authors data, we can add a custom HTML tag to Google Tag Manager that will loop through the results and (using a bit of HTML and CSS) output the results in nice looking widgets, complete with bar charts based on the percentage of the maximum Pageviews we calculated server-side.

You will want to design the widget first, and a tip is to try and reuse as much of the current CSS styles for the website.

a) Add the widget code as a tag

Add the following code to Google Tag Manager as a Custom HTML tag.

<script>
// create a function that will be called when the API is called
function topAuthorsCallback(data){
    // dos something with the data that is returned

    // append any new CSS styling to the head tag
    $ ('head').append(
    '<style>' +
    '.gawidget-author { float: left; width: 100%; }' +
    '.gawidget-author-img { width: 40px; float: left; }' +
    '.gawidget-author-chart { display: inline-block; vertical-align: top; width: 85%; height: 40px; margin-bottom: 5px; }' +
    '.gawidget-author-bar { height: 60%; background: #62B6BA; }' +
    '.gawidget-author-name { height: 40%; padding: 2px 5px; color: #666;}' +
    '</style>' )

    // Create a new div for where the widget will be inserted
    $ ( '#block-block-18' ).before(
     '<div id="block-top-authors-0" class="clear-block block"><h2>Top Authors</h2></div>' );

    // Create a header for Social links for consistency
    $ ( '#block-top-authors-0' ).after(
     '<div id="block-social-0" class="clear-block block"><h2>Social Links</h2></div>' );

    // loop through the first 5 results to create the widget
    for (var i = 0; i < 5; i++){

        var authorName = data[i]['author'];
        var authorUrl = data[i]['link'];
        var authorPerc = data[i]['perc'];
        var authorImg = data[i]['image'];
        var authorPosition = i + 1;

        var html_output = '<div class="gawidget-author">' +
        '<a href="' + authorUrl + '">' +
        '<div class="gawidget-author-img">' +
        '<img src="' + authorImg + '" style="width: 100%;">' +
        '</div>' +
        '<div class="gawidget-author-chart"><div class="gawidget-author-bar" style="width: '+ authorPerc +'%;"></div>' +
        '<div class="gawidget-author-name">' + authorName + '</div>' +
        '</div></a></div></div>'

        $ (html_output).hide().appendTo('#block-top-authors-0').fadeIn(2000)

    }

}

// The URL for the API on App Engine
var api_url = 'http://onlinebehaviorwidgets.appspot.com/topauthors.jsonp'
// The function created that will add the widget content to the site
var callback_function = 'topAuthorsCallback'
// Join the above to create the final URL
var url = api_url + '?callback=' + callback_function

// Call the jsonp API
$ .ajax({
    "url": url,
    "crossDomain":true,
    "dataType": "jsonp"
});
</script>

b) Create a variable and trigger

In this example, we will be adding the new widget right above the Google+ widget so first we create a Custom JS variable that returns true if the div element holding the Google+ exists and false if it does not, as shown below.

GTM Variable Trigger

c) Custom JS Variable – Google Plus Widget Exists

function(){
  if ($ ( '#block-block-18' ).length > 0){
    return true
  } else {
    return false
  }
}

d) Preview and Publish the widget

Set the tag to trigger on all pages where the div we are appending the widget to exists, as shown below.

Publish Widget

Save the tag and before you publish, go into preview mode to test that the tag is triggering as expected and the widget is appearing as you have designed. If you are happy it is all working you can publish the tag and launch the widget to all your users.

Your Turn To Create A Widget

This is just one simple example of what is possible and we would love to see what you create. How about sharing your top 10 products based on sales or top performing brands or categories. The possibilities are endless!

image 
Google Cloud Project
Run Widget Locally
Enable Google Analytics API
Google Analytics Permissions
import.io API
Developer Console Logs
GTM Variable Trigger
Publish Widget
Online Behavior
Online Behavior


Online Behavior – Marketing Measurement & Optimization

FacebookTwitterGoogle+LinkedInEmailPinterest

Pizza Hut: The Video Projector Pizza Box

Now this is cool. A Video Projector Pizza Box! With a slightly new shape and size, the box transforms from holding your delicious pizza, by removing the middle rester (the thing that stops the pizza hitting the top of the box) which now holds a makeshift projector lense, that plugs into the front of the […]


Digital Buzz Blog

FacebookTwitterGoogle+LinkedInEmailPinterest

Installing ‘Glastonbury: Land and Legend’ – Day 3

The third day of install saw the Jaroslav Fragner Gallery completely transformed!

The distinctive blue chairs, the iconic image of PQ2015, greeted us from the gallery entrance. They have been suspended from a bridge which links the gallery to the medieval Bethlehem chapel on the opposite side of the courtyard.

Prague Quadrennial chairs outside the Jaroslav Fragner Gallery

Prague Quadrennial chairs outside the Jaroslav Fragner Gallery

The graphics for the installation, designed by Marc Jennings, went up in the gallery foyer first thing. This included an enormous infographic, measuring 3m x 5m. Drawing inspiration from a site map used by the infrastructure department at the Glastonbury Festival, the infographic firmly grounds the installation in the topography of Worthy Farm and reflects how the festival emerges from and works with the Somerset countryside. The layers of precise detail and information visible on the map suggest the depth of organisation and infrastructure that support the largest green field festival in the world! Adding to these layers, the site map is overlaid with facts and stats about the festival and its history. The map was shortly followed by the title of the installation and a quotation from William Blake’s poem Jerusalem, which further emphasise the significance of the sense of place on the festival site through time, as well as its legendary associations with early Christianity, Arthurian Legend, Pagan rites and leylines.

Technicians in the Jaroslav Fragner Gallery installing the infographic map

Technicians in the Jaroslav Fragner Gallery installing the infographic map

Meanwhile, in the main gallery space, work was underway marrying the sound and visual elements together to bring the installation to life. Gareth Fry, sound designer, and Luke Halls, video designer, spent the day together in the space with the installation team to synch sound and sight, with exiting results!

Oli from Hawthorn adjusting screens and projectors!

Oli from Hawthorn adjusting screens and projectors!

A sneaky peek!

A sneaky peek!

 

 

Blog

FacebookTwitterGoogle+LinkedInEmailPinterest

Get In Touch!

Or save my details for later...