This codelab is a continuation of the concepts introduced in Accelerated Mobile Pages Foundations. You should already have completed the previous code lab before starting this lab or at least have a basic understanding AMP's core concepts already.

In this codelab, you'll learn how AMP handles advertising, analytics, video embedding, social media integration, image carousels and more. To achieve this you will build upon the example from the Foundations codelab by adding these features via the various AMP components.

What you'll learn

What you'll need

You can either download all the sample code to your computer:

Download Zip

...or clone the GitHub repository from the command line:

$ git clone https://github.com/googlecodelabs/accelerated-mobile-pages-advanced.git

You will download a ZIP file containing several example resources files and the starting article.html page.

Unzip the folder and navigate to the directory via the command line on your computer.

In order to test our sample page we need to access the files from a web server. There are several ways to create a temporary local web server for the purposes of testing. For this code lab we will provide instructions for 3 options available:

Option #1: Web Server for Chrome

You can find the "Web Server for Chrome" app at this link on the Chrome Web Store.

After installing the Chrome App you must point the app at a particular folder via the "Choose Folder" button. For this code lab you should select the folder where you unzipped the code lab example files.

Additionally you should tick the "Automatically show index.html" option and set the port to "8000". You will need to restart the the web server for these changes to take effect.

Access this URL via:

http://localhost:8000/article.amp.html

If the above URL loads successfully you can continue to the next section.

Option #2: Firebase Hosting

If you are interested in exploring our new Firebase static web hosting you can follow the instructions available here to deploy your AMP site to a Firebase hosting URL.

Firebase Hosting is a static hosting provider that you can use to quickly deploy and host a static website and its assets; including HTML, CSS, and JavaScript files. Users benefit from reduced latency because static content is cached in a content delivery network (CDN) with points of presence (PoPs) located around the world.

Lastly, Firebase Hosting is always served via SSL so it's great for AMP and the web in general. If you're more interested in purely focusing on AMP then simply ignore this option.

Option #3: HTTP Python Server

If you don't use Chrome or you are struggling to install the Chrome extension you can also use Python from the command-line to fire up a local web server.

To run Python's built-in HTTP server from the command line simply execute the following:

python -m SimpleHTTPServer

And access this URL:

http://localhost:8000/article.amp.html

AMP's component system allows us to quickly build efficient and responsive features into our articles with minimal effort. The core AMP JavaScript library in the <head> tag includes several core components:

All of the above core components can be used immediately in an AMP document. Our example code already utilises amp-img in our page and we explored how it relates to the AMP layout system in the AMP Foundations code lab, so let's explore amp-ad in the next chapter!

Your sample article.amp.html page should be as follows:

<!doctype html>
<html ⚡ lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">

    <link rel="canonical" href="/article.html">
    <link rel="shortcut icon" href="amp_favicon.png">

    <title>News Article</title>

    <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
    <style amp-custom>
      body {
        width: auto;
        margin: 0;
        padding: 0;
      }

      header {
        background: Tomato;
        color: white;
        font-size: 2em;
        text-align: center;
      }

      h1 {
        margin: 0;
        padding: 0.5em;
        background: white;
        box-shadow: 0px 3px 5px grey;
      }

      p {
        padding: 0.5em;
        margin: 0.5em;
      }
    </style>
    <script async src="https://cdn.ampproject.org/v0.js"></script>
    <script type="application/ld+json">
    {
     "@context": "http://schema.org",
     "@type": "NewsArticle",
     "mainEntityOfPage":{
       "@type":"WebPage",
       "@id":"https://example.com/my-article.html"
     },
     "headline": "My First AMP Article",
     "image": {
       "@type": "ImageObject",
       "url": "https://example.com/article_thumbnail1.jpg",
       "height": 800,
       "width": 800
     },
     "datePublished": "2015-02-05T08:00:00+08:00",
     "dateModified": "2015-02-05T09:20:00+08:00",
     "author": {
       "@type": "Person",
       "name": "John Doe"
     },
     "publisher": {
       "@type": "Organization",
       "name": "⚡ AMP Times",
       "logo": {
         "@type": "ImageObject",
         "url": "https://example.com/amptimes_logo.jpg",
         "width": 600,
         "height": 60
       }
     },
     "description": "My first experience in an AMPlified world"
    }
    </script>
  </head>
  <body>
    <header>
      News Site
    </header>
    <article>
      <h1>Article Name</h1>

      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam egestas tortor sapien, non tristique ligula accumsan eu.</p>

      <amp-img src="mountains.jpg" layout="responsive" width="266" height="150"></amp-img>
    </article>
  </body>
</html>

The above is a simple page, the most interesting fact of this page is that it passes both AMP validation and the Schema.org search engine meta data validation. If this page were deployed on a news website it would be eligible for inclusion in the new Google search carousel dedicated to AMP content so it's a great starting point for our work.

Before we alter the page let's open up the Chrome Developer Tools. When working on a website (especially a mobile focused website) it is usually a good idea to simulate a mobile experience when testing in the browser. Start by opening the Developer Console in Chrome via Menu > More Tools > Developer Tools:

Now inspect the JavaScript output in the developer console. Make sure you have the Console tab selected:

Now click the device simulation button in the developer console. It is represented by a phone and tablet sitting next one another:

In the menu that appears, set the device to "Nexus 5X":

Now we can start working on the page itself. Let's try adding an ad to our AMP article!

All ads in AMP are constructed using the amp-ad component. Using this component we can configure our ads in several ways such as the width, height and layout mode. However, many ad platforms will require additional configuration such as the account ID for the ad network, which ad should be served or options for targeting the advertising. For amp-ad we simply fill in the various options required as HTML attributes.

Take a look at this example of a Double Click ad:

<amp-ad
  width="300"
  height="250"
  type="doubleclick"
  data-slot="/35096353/amptesting/image/static">
</amp-ad>

As you can see this is a very simple configuration. Take note of the type attribute, this attribute informs the amp-ad component of which ad platform you want to use. In this case we wanted Double Click's platform and therefore the type value was doubleclick.

The data-slot attribute is more unique. Any attributes starting with data- in amp-ad are vendor specific attributes. This means that not all vendors will necessarily require this particular attribute nor will they necessarily react if it is supplied. For example, compare the above Double Click example with a test advertisement from the A9 platform:

<amp-ad
  width="300"
  height="250"
  type="a9"
  data-aax_size="300x250"
  data-aax_pubname="test123"
  data-aax_src="302">
</amp-ad>

Try adding both of the above examples into your article just after the <header> tag. Refresh the page and you should see two testing ads have appeared:

Let's explore some more options available to use with Double Click. Try adding these two geotargeting ad configurations to your page:

<amp-ad
  width="300"
  height="250"
  type="doubleclick"
  data-slot="/35096353/amptesting/geo/uk">
  <div fallback>No ad appeared because you're not browsing from the UK!</div>
</amp-ad>

<amp-ad
  width="300"
  height="250"
  type="doubleclick"
  data-slot="/35096353/amptesting/geo/us">
  <div fallback>No ad appeared because you're not browsing from the US!</div>
</amp-ad>

Unfortunately the geotargeting cannot be controlled from the code of the page itself. However, these test adverts have already been configured in the Double Click dashboard to only show in particular countries, specifically the United Kingdom and the United States of America.

Refresh the page and take a look. The following screenshot was captured from Australia, so neither advert is loading:

The above geotargeting example demonstrates how amp-ad is flexible enough for all sorts of ad platform features.

The following are the currently supported ad networks:

Be sure to check out the documentation page for the AMP Ad component for information on the latest supported ad platforms.

In the next chapter we'll explore more advanced AMP components and how to include them in our AMP documents.

By now you have a basic AMP document with text, an image and even an advertisement embedded on the page -- all key ingredients to telling a story and monetising your content. However, modern websites often include more functionality than simply pictures and text.

So let's take our AMP document to the next level and explore what components are available beyond the core components mentioned earlier.

In this chapter we'll try adding more advanced web functionality that is commonly found on news articles:

Embed a YouTube video

Let's try embedding a YouTube video into the document. The following code will embed a video, add it to your page:

<amp-youtube
  data-videoid="mGENRKrdoGY"
  layout="responsive"
  width="480"
  height="270">
  <div fallback>
    <p>The video could not be loaded.</p>
  </div>
</amp-youtube>

Refresh the page and look at the page. You should see this text instead of a video: "The video could not be loaded."

Even if your browser can show YouTube videos without issue you will still receive this error. Why? The video hasn't actually failed to load, rather the component itself failed.

Remember, not all components are included in the core AMP library JavaScript file. We need to include an additional JavaScript request for the YouTube component in particular. All components except for a core set will require these additional JavaScript references.

Add the following request to the <head> tag:

<script async custom-element="amp-youtube" src="https://cdn.ampproject.org/v0/amp-youtube-0.1.js"></script>

Refresh the page and you should see the YouTube video:

Once again we have specified the width and height of the video in order for the aspect ratio to be calculated by the AMP layout system. Furthermore the layout type has been set to responsive meaning this video will fill the width of its parent element.

Learn more about the YouTube component.

Display a Tweet

Embedding preformatted tweets from Twitter is a common feature of news articles. The AMP Twitter component can provide this functionality with ease.

Start by adding the following JavaScript request to the <head> tag of your document:

<script async custom-element="amp-twitter" src="https://cdn.ampproject.org/v0/amp-twitter-0.1.js"></script>

Now in your article add this code to embed the tweet itself:

<amp-twitter
  width="486"
  height="657"
  layout="responsive"
  data-tweetid="638793490521001985">
</amp-twitter>

The data-tweetid attribute is another example of a custom attribute being required by a particular platform vendor. In this case Twitter recognises the data-tweetid attribute as corresponding to a particular tweet to be embedded in the page.

Refresh your browser and take a look at the page. You should see the tweet appear:

Learn more about the Twitter component.

Highlight an article quote

A common element in news articles is to highlight particularly engaging snippets of text from the article. For example, a quotation from a particular source or an important fact might be repeated in a larger font to attract attention from the reader.

However, since not all quotations or snippets of text are necessarily the same length of string characters it can be difficult to balance the larger font size with the amount of space the particular text will consume on the page.

AMP includes another component specifically for this type of situation called amp-fit-text. It allows you to define a fixed width and fixed height element and a maximum font size. The component intelligently scales the font size to fit the quotation's text within the width and height available.

Let's give it a try. Firstly, add the component's library to the <head> tag:

<script async custom-element="amp-fit-text" src="https://cdn.ampproject.org/v0/amp-fit-text-0.1.js"></script>

Add the following to your page:

<amp-fit-text width="400" height="75" layout="responsive" max-font-size="42">
  Big, bold article quote goes here.
</amp-fit-text>

Refresh the page and look at the result!

Now experiment further. What happens if the quotation is much shorter?

<amp-fit-text width="400" height="75" layout="responsive" max-font-size="42">
  #YOLO
</amp-fit-text>

Or how about a longer quotation?

<amp-fit-text width="400" height="75" layout="responsive" max-font-size="42">
   And the Raven, never flitting, still is sitting, still is sitting. On the pallid bust of Pallas just above my chamber door; And his eyes have all the seeming of a demon's that is dreaming, And the lamp-light o'er him streaming throws his shadow on the floor; And my soul from out that shadow that lies floating on the floor. Shall be lifted—nevermore!
</amp-fit-text>

As a last experiment with amp-fit-text, try creating a short piece of text such as #YOLO with a much larger height -- for example, a value of 400 -- and maintaining the max-font-size attribute value of 42. What would the resulting page look like? Does the text center vertically or does the height of the amp-fit-text tag shrink to fit the max font size? Knowing what you know about AMP's layout system try to answer the question before editing the document!

Another common feature in web development is a carousel. AMP includes a generic component designed to fulfil this need. Let's start with a simple example such as a carousel of images.

Remember to include the carousel component library by adding the following JavaScript request to the <head> tag of your document:

<script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>

Next we'll embed a simple carousel of images with a responsive layout and a pre-defined width and height. Add the following to your page:

<amp-carousel layout="fixed-height" height="168" type="carousel" >
  <amp-img src="mountains-1.jpg" width="300" height="168"></amp-img>
  <amp-img src="mountains-2.jpg" width="300" height="168"></amp-img>
  <amp-img src="mountains-3.jpg" width="300" height="168"></amp-img>
</amp-carousel>

Refresh your page and you should see a carousel in your page:

The carousel component can be configured in a variety of ways. Try changing the type to slides instead and look at the result. Be sure to change the layout attribute of the amp-carousel and the images inside it to be responsive as well.

Now instead of a scrolling list of elements you'll see one element at a time. Try swiping horizontally to move through the elements. If you swipe to the third element you won't be able to swipe any further.

Next, add the loop attribute. Refresh the page and try swiping to the left immediately. The carousel loops endlessly.

Lastly, let's make this carousel autoplay at a rate of every 2 seconds. Add the autoplay attribute to the page and the delay attribute with a value of 2000 like so: delay="2000".

Your final result should look something like this:

<amp-carousel layout="responsive" width="300" height="168" 
         type="slides" autoplay delay="2000" loop>
  <amp-img src="mountains-1.jpg" width="300" height="168" layout="responsive"></amp-img>
  <amp-img src="mountains-2.jpg" width="300" height="168" layout="responsive"></amp-img>
  <amp-img src="mountains-3.jpg" width="300" height="168" layout="responsive"></amp-img>
</amp-carousel>

Refresh the page and give it a spin!

Image carousels are great but what if we want more complex content to appear in our carousel? Let's try mixing things up a bit by placing an advert, some text and an image altogether in a single carousel. Can amp-carousel really handle such a mixture all at once? You bet.

First let's add this styling to the page to ensure the amp-fit-text and amp-carousel components work together safely:

amp-fit-text {
    white-space: normal;
}

Now try putting the following carousel code into your page:

<amp-carousel layout="fixed-height" height="250" type="carousel" >
    <amp-img src="blocky-mountains-1.jpg" width="300" height="250"></amp-img>

    <amp-ad width="300" height="250"
      type="doubleclick"
      data-slot="/35096353/amptesting/image/static">
        <div placeholder>This advert is still loading.</div>
    </amp-ad>

    <amp-fit-text width="300" height="250" layout="fixed">
        Big, bold article quote goes here.
    </amp-fit-text>
</amp-carousel>

Refresh the page and you should see something like this:

Learn more about the Carousel component.

Analytics platforms are commonly integrated into websites via inline JavaScript snippets and function calls which trigger events that are sent back to the analytics system. AMP provides a flexible JSON configuration syntax to replicate this process for several analytics partners.

The following is an example of traditional JavaScript driven Google Analytics tracking which we will rewrite in amp-analytic's JSON format. Firstly the traditional JavaScript approach:

<script>
(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','//www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');
</script>

The above is quite simple, it sends a notification for the pageview event to be tracked.

To replicate all of the above in the amp-analytics component, we first include the component library in our document's <head>:

<script async custom-element="amp-analytics" src="https://cdn.ampproject.org/v0/amp-analytics-0.1.js"></script>

And then we include the component as follows:

<amp-analytics type="googleanalytics">
<script type="application/json">
{
  "vars": {
    "account": "UA-YYYY-Y"
  },
  "triggers": {
    "default pageview": {
      "on": "visible",
      "request": "pageview",
      "vars": {
        "title": "Name of the Article"
      }
    }
  }
}
</script>
</amp-analytics>

It may seem more complicated but it's actually a very flexible format for describing several different types of events. Additionally, the JSON format does not include the blob of JavaScript code in the traditional example which could potentially lead to mistakes if accidentally altered.

In the JSON format the triggers key includes a set of keys which represent all event triggers we will track, the keys of those triggers are descriptions of the event, for example "default pageview" in the above. The title key value relates to the name of the page being viewed.

Expanding the above example we can add another trigger "click on #header trigger":

<amp-analytics type="googleanalytics">
<script type="application/json">
{
  "vars": {
    "account": "UA-YYYY-Y"
  },
  "triggers": {
    "default pageview": {
      "on": "visible",
      "request": "pageview",
      "vars": {
        "title": "Name of the Article"
      }
    },
    "click on #header trigger": {
      "on": "click",
      "selector": "#header",
      "request": "event",
      "vars": {
        "eventCategory": "examples",
        "eventAction": "clicked-header"
      }
    }
  }
}
</script>
</amp-analytics>

This trigger is exactly what it sounds like, by using the DOM selector "#header" we can query for a tag with the id "header" and on the event of it being "clicked" or tapped on the device we send an event action "clicked-header" to the analytics platform with the category label "examples".

If you have a custom tracking platform you wish to integrate with you can still use amp-analytics and define your own personalised URL endpoints for the tracking information. Read more about the amp-analytics component here!

A common requirement of mobile websites is the inclusion of a site navigation menu. These menus can take many different forms. Here are a few examples of how navigation can be presented on an AMP document:

  1. Link back to your home page -- the simplest option.
  2. A sub-heading menu via the carousel component.

Home Page Link

The simplest way to get your users to access your website's regular navigation options is to just funnel them back to your regular website interface!

Try adding this HTML link to the <header> tag:

<header>
  <a href="homepage.html">
    <amp-img class="home-button" src="icons/home.png" width="36" height="36"></amp-img>
  </a>

  News Site
</header>

And add this rule to your inline CSS:

.home-button {
  float: left;
}

Now refresh the page. You should see a link in the top-left corner of the page pointing to homepage.html - if you click this link you'll quickly discover it doesn't lead anywhere.

This link can be replaced with the URL of your website's homepage to enable your users to navigate to other parts of your site via your regular website's navigation.

As mentioned, this is the simplest approach available -- leveraging your existing website navigation. Next we'll explore two alternatives.

Sub Heading Menu

Another approach to this problem is to present your site's navigation menu inside the AMP document. To keep contained to a small section of your page we can use a carousel to present a scrollable menu beneath the site's header.

Since we need the carousel component, be sure to add the component's JavaScript to the <head> tag of your page:

<script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>

Try adding this HTML snippet just below your <header> tag:

...
</header>
<div class="sub-menu">
  <amp-carousel layout="fixed-height" height="38" type="carousel">
    <a href="#example1">Example 1</a>
    <a href="#example2">Example 2</a>
    <a href="#example3">Longer Named Example 3</a>
    <a href="#example4">Example 4</a>
    <a href="#example5">Example 5</a>
    <a href="#example6">Example 6</a>
  </amp-carousel>
</div>
<article>
...

And add these rules to your inline CSS:

.sub-menu {
  background: black;
}

.sub-menu a {
  display: block;
  background: tomato;
  margin: 5px;
  padding: 5px;
  color: white;
  text-decoration: none;
}

Now refresh the page. You should see a menu of links appearing below your article title. This menu can be scrolled horizontally to store many navigation links.

This sub-menu navigation is a great way to store lots of links without consuming too much space on your page.

As discussed earlier there are no external stylesheet requests allowed in AMP documents. However, there is one exception to this rule: fonts.

Fonts are an important part of the article reading experience for web users and since web browsers fetch font files via external stylesheet requests this exclusion in AMP is necessary.

Let's try adding a reference to the Raleway font to the document:

<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Raleway">

Now update your CSS to include a reference to Raleway:

body {
  width: auto;
  margin: 0;
  padding: 0;
  font-family: 'Raleway', sans-serif;
}

Refresh your page and check out your page's new look. Also inspect the validator's output and you will note that there are no complaints with regard to this external request.

You've finished the Advanced AMP code lab and successfully explored many key components of AMP!

Hopefully it's clear to you how amp-ad and amp-analytics can be used to support all sorts of different ad platforms and analytics vendors. Be sure to explore the full list of AMP components available.

The following are some additional topics and links you might want to explore to amplify your skills even further!