The AMP Camp build process


What’s AMP Camp?

It’s one thing to work as a Developer Advocate and talk about how AMP can be used to create quick, interactive sites. It’s quite another to actually build one! So a few of us decided to create a simple but fully functional e-commerce website, covering everything until the checkout. We hoped to learn the subtleties involved in creating these interactions, to create guidance for others, and to make some nice feature requests.

And, thus, the AMP CAMP demo site was born!

We learned a whole lot making this site, and we want to share this with you. In this series of articles, we’ll explain how we built the site and created its interactions. You can also watch the talk at the end of this post.

First things first: let’s start with an article about the AMP Camp build process.

Why did we use a build process?

It’s common to compile software from a set of source files into the files that are used in production. This is called a build process. Sometimes it’s convenient to do this with HTML – to create resources in a more convenient form, then automatically compile that down to the HTML that gets served to browsers.

A build process is especially convenient with AMP. After all, the information required to render an AMP webpage lives in a single file. Its CSS is included inside the HTML in <style> tags. And if you’re not using <amp-script>, you won’t even be providing separate JavaScript resources. In contrast, almost all non-AMP webpages refer to many other CSS and JS files. AMP is simpler!

Nonetheless, while you’re creating your AMP pages, you probably won’t want to create each page within a single file unless your site is very simple. At the very least, unless you’re using you’re combining CSS and HTML intentionally in JSX or web components, it’s messy to work with source files that contain both CSS and HTML. You’ll likely at least want to create CSS and HTML in separate files, then use a build process to combine them.

Thinking about this further, your webpages will usually share much of the same HTML. For example, they may have the same navigation menu, or similar footers. It’s simply not a best practice to copy identical HTML from page to page. What if you want to change that menu? You’d have to copy and paste the new HTML across your site! That menu should live in its own file instead. More generally, you want to build pages from HTML partials. Since AMP is an HTML framework, in which HTML describes user interactions and can even contain logic, this holds doubly true.

Similarly, it’s rarely best to write all your CSS in one jumbo-size file and make every page load it. You might argue that, once this large file loads, it will likely be cached, so as the user progresses through your site, they won’t experience that 200K render-blocking hit on each page. But if that first page loads slowly, the user may never get to that second page! You really want each page to load a smaller CSS file, containing mostly only the styles used on that page.

You can’t use more than 75K of CSS if you want your AMP page to pass validation. Plus, that CSS must be contained inside the HTML to save a render-blocking network call! Hence, it’s best to only add the CSS to a page that is needed. All this is much easier if you use a build process to assemble your CSS from partials, then merge that into each HTML file.

So, just as it’s often easier and more convenient to assemble webpages from smaller parts with a build process, it’s easier and more convenient for AMP web pages. As a bonus, plenty of build tools have been created specifically for AMP, either to make AMP pages easier to create, or to make them faster for users! To learn more, let’s take a look at the build process used in the AMP Camp demo site.

The AMP Camp site is built with node.js and gulp. Throughout this article, we’ll refer to the code on github, especially the gulpfile. We’ll also refer to ways in which you can make your build process better than ours!

Building our HTML

const fileinclude = require('gulp-file-include');

AMP Camp builds its HTML from partials, in much the way discussed above. Since our site is relatively simple, we used fileinclude. That said, if we expand the project just a little, we’ll probably want to migrate to a more powerful tool.

To see this in action, check out the start of index.html, which includes separate partials for the <head>, the page header, the navigation menu, and some other things:

<!doctype html>
<html ="" lang="en">
    %%include('../partials/head.html', {
        "pageType": "index"
    %%include('../partials/header.html', {
        "pageType": "index"  

Some of these partials contain other partials. Notably, we decided to put our analytics in its own partial, analytics.html, which header.html then imports.

Building our CSS

AMP Camp’s head.html partial is built from subpartials as well. These subpartials are not HTML files, but CSS files. head.html includes CSS files that are common to each page:

<style amp-custom>

as well as CSS that’s specific to each page:

%%if (context.pageType == 'index') {

To build more efficient CSS, you can divide your HTML into smaller partials and subpartials and associate the appropriate CSS with each. This way, each page of the site truly only contains the CSS it needs. For example, organizes its CSS with atomic design, a system in which larger UI design elements contain progressively smaller ones, all the way down to “atoms”. Check it out here! Another option is to use a framework like Next.js, which lets you do a React-style CSS/HTML association. (We encourage you to learn about Next.js’ AMP support here – or try this tutorial.)

const sass = require('gulp-sass');

AMP Camp builds its CSS from SASS, a popular higher-level language that compiles down to CSS. This works with AMP pages just as it does with non-AMP pages!

However, if your SASS happens to contain extended characters, the SASS processor will automatically output a rule to specify the character encoding:

@charset "UTF-8";

Unfortunately, such rules aren’t standard for CSS that lives inside a <style> tag. Thus this rule inspires the AMP validator (see below) to throw an error!

Our solution isn’t pretty, but it’s simple and robust: after SASS does its work, we postprocess the resulting CSS to remove any such rules:

gulp.task('styles', function buildStyles() {
    const cssEncodingDirective = '@charset "UTF-8";';

    return gulp.src(paths.css.src)
        .pipe(sass(options.env === 'dist' ? { outputStyle: 'compressed' } : {}))
        .pipe(options.env === 'dev' ? replace(cssEncodingDirective, '') : noop())
        .pipe(autoprefixer('last 10 versions'))
        .pipe(mergeMediaQuery({log: true}))

AMP-specific tools

const gulpAmpValidator = require('gulp-amphtml-validator');

Speaking of AMP validation, we want to ensure that our pages are always meeting AMP’s standards, so that they’ll be eligible for AMP caches, and so we’ll avoid errors, but also because we want to serve fast, accessible pages. Consequently, our build process includes the AMP Validator. We’ve set it up so that when any page isn’t valid AMP, the build breaks.

gulp.task('validate', function validate() {
    return gulp.src(paths.html.dest + '/**/*.html')

If we didn’t want any invalid page to break the build, we could omit the failAfterError() step above.

Note that some of AMP Camp’s pages are rendered from templates on the server. We don’t want to run the validator in the server! Fortunately, since what we substitute into those templates is simple and highly predictable, we feel confident running the validation on these templates. In a larger project, it would be safer to render some sample pages during the build process and test those for validity.

const ampOptimizer = require('@ampproject/toolbox-optimizer');

Finally, we use the AMP Optimizer for a number of purposes!

  • Many AMP components require their own small script to function. The developer needs to keep track of these for each page and ensure each is included in the <head>. That’s why, for this project, we developed the amphtml-autoscript gulp module, which detects which components a page uses and automatically inserts the necessary scripts! This functionality has now been incorporated into the AMP Optimizer.
  • AMP pages contain boilerplate that hides the page until the AMP runtime loads, gets parsed, and executes. When it starts up, the AMP runtime performs various transformations on the DOM, then unhides the page. AMP caches perform these transformations in advance, serving the modified HTML right to your browser and speeding things up substantially. The AMP Optimizer does this right on your origin! This can make AMP pages twice as fast on your origin, so we think it’s invaluable.
  • Finally, it automatically inserts mandatory AMP tags so we don’t have to.

AMP Camp runs the AMP Optimizer during the build process on our compiled templates. This means our template delimiters can’t contain angle brackets, like <% and %>, because the Optimizer would parse these as HTML. We use square brackets ([% and %]) instead.

AMP Optimizer can be used in your server as well, at runtime. If you do this, you should cache optimized pages to avoid excess server load.

And there you have it

We’re hoping the build process we used for AMP Camp helps make your own AMP project easier! Again, to see a build process for a larger site, check out the way is built. Or, to see an interesting React-based approach, check out the Concert sample or Article sample.

Stay tuned for the next article in the AMP CAMP series – how we used templates on the client and on the server.

Happy building!

Written by Ben Morss, Developer Advocate

How to Combine AMP with Dynamic, Personalized Content


Note: the following guest post was written by Madison Miner, CEO and founder, WompMobile

AMP is well known as a comprehensive solution for speed. A common misconception, however, is that because AMP pages may be served from a cache, AMP is best suited for static content like news articles and blog pages, and not ideal for dynamic, personalized experiences. As an open-source initiative, AMP has steadily evolved and matured. Today, AMP delivers rich, dynamic content with guaranteed speed – making the framework perfect for e-commerce, retail and other industries that rely on delivering targeted, personalized experiences. 

This post describes how dynamic data – commonly required for e-commerce websites – can be used within the AMP framework.

Three Types of Dynamic Data

1. Time-sensitive data: Data that’s the same for all users and changes frequently, such as product pricing and availability. Example AMP pages that exhibit time-sensitive data:

2. User profile or personal data: Data that changes based on what you know – or can guess – about a user. This is often used to display relevant products based on a user’s browsing history and their location, or to serve highly targeted, personalized experiences. Examples:

3. User-account data: Data that’s tied to a specific-user account, which often includes authentication, currency, number of items in the cart, or a wish list. Examples:

  • George remembers your Cookie settings, and only prompts new users to select cookies on AMP 

A Deeper Dive into How AMP Works

AMP requires the adoption of performance guardrails and best practices while ensuring content can be consumed from a cache. To implement each of the dynamic features outlined above, two things are required: the <amp-list> component and an AMP-compatible API. Let’s see how each of these features work.

Time-sensitive data is the simplest type of dynamic data, only requiring an amp-list and an API that returns pure JSON with the correct CORS headers.  Since the price and availability data is the same for all users, the API doesn’t need to concern itself with cookies or credentials. 

To return meaningful user account data, an API will typically use cookies to identify users. To include cookies in requests made by <amp-list>, the credentials=”include” attribute is required. This requires a more sophisticated API that accepts cookies, identifies users, potentially sets cookies, responds with personalized content, and also responds with an access-control-allow-credentials header. 

When using AMP pages on your own domain, there are no unusual cookie restrictions. However, when pages are served from the AMP cache, it’s important to remember that your domain is recognized as a third party. Some browsers, like Safari, may block third-party cookies. It is recommended to understand Safari cookie management before committing to a final strategy.

There are several workarounds for this problem, such as using the AMP client ID to recognize users instead of cookies. When AMP pages are served from your own domain, cookies work as expected, allowing AMP to deliver user-specific data for all browsers.

Creating a personalized experience based on a user profile or persona can be done in several ways. 

  • Deliver an experience based on location
    • IP-geolocation can be used on the server to approximate a user’s location. A database of IP addresses, like those offered by MaxMind, is required. IP-geolocation won’t provide GPS-like accuracy; however, it returns accurate city-level results. Once the user’s approximate location is determined, the server returns localized results via an API response. This can be used to display nearby stores sales, the closest services available location, or the local currency and language., Providence Health Services and are examples of brands that utilize IP-geolocation to approximate location and return personalized results. 
  • Deliver an experience based on user history
    • Show related products or services based on the customer’s previous browsing history on your site. 
  • Deliver an experience based on persona 
    • Use data and algorithms to guess which of your products the customer will be most likely to buy. This technique may require working with third-party data and creating AMP-specific APIs.

A key component of this type of customization is tracking user behavior. The amp-analytics component can be used in several ways to report user journey steps, such as product views and user interactions. The AMP Client ID is the most straightforward and consistent way to unify session management.  The Linker feature of amp-analytics can also be used to link amp sessions between 3rd party amp caches and your own domain. 

Final Thoughts

The AMP framework is unapologetic about the importance of speed, and sets rules and best practices to guarantee a fast experience.  But achieving speed can’t come at the expense of functionality. You need both. As you’ve learned, AMP provides a framework to do just that.

By using components and APIs, AMP eliminates bloated JavaScript and historic bad practices, while retaining all the features and logic that are critical to any business. AMP is a great way to build for the web that provides a balanced approach, promotes speed and helps your customers. 

More room for more style


Increasing the AMP CSS limit

Whether your style is a professional journalist website or bohemian ecommerce emails, AMP now gives you more room to show it. The AMP maximum allowable CSS limit has been raised to 75kB – a 50% increase! This is the biggest, and, well, only change to the CSS cap in the near half-decade lifespan on the AMP project, and affects both AMP powered websites and AMP for Email.


AMP had the 50kB limit with the best intentions – a forcing function to encourage strong CSS hygiene. Over the years, we’ve received a lot of feedback on the CSS allotment, and we hear you! Fitting experiences that meet higher-than-ever user expectations within a maintainable 50kB limit is difficult. 

This was no hasty change – we investigated many different possibilities, including automatic AMP cache level minification, migrating to a percentage-of-used-selector based limit, or even a dynamic limit based on document complexity. Ultimately, raising the limit was the option that best fit AMP developer’s needs.

What’s next

So the good news is that you now have 75kB of CSS available on each AMP powered webpage and AMP email. Even better news: you don’t have to change a thing on your existing AMP experiences! Since the AMP library is evergreen, this limit will automatically roll out to any and every AMP powered site soon. 

The AMP team is thrilled to see what new possibilities this change will open up for all developers, and can’t wait to see what’s dreamed up. You can join the community to share what you make, or just follow along with all AMP updates, on the Slack channel, twitter, or by sign up for our newsletter.

Crystal Lambert, Technically a Writer, Google, AMP Project

Patrick Kettner, Developer Cheerleader, Google, AMP Project

Easier AMP development with the new AMP Optimizer


Creating AMP pages has just gotten a lot simpler with the new AMP Optimizer 2.0. 

The primary goal of AMP Optimizer is to make AMP pages load even faster by applying additional server-side optimizations. With this release, AMP Optimizer also makes it a lot simpler to integrate AMP into frameworks and CMSs! For example, we’ve just released an AMP plugin for the wonderful static site generator Eleventy that makes use of all these new features. 

But first let’s take a quick look at what’s new in AMP Optimizer 2.0:

  1. Auto AMP component script import. 
  2. Auto add any missing mandatory AMP tags.
  3. New Markdown support via <img> tag to <amp-img> conversion.
  4. CSP tag generation for inline amp-scripts.
  5. Built-in HTML minification removing unneeded whitespace (this includes AMP specific optimizations such as removing whitespace from inline JSON and minifying inline amp-scripts using terser).
  6. AMP server-side-rendering now supports the intrinsic layout. This means AMP Optimizer can remove the AMP boilerplate for pages using the intrinsic layout resulting in much faster load times.
  7. Transformations run 40% faster by switching from parse5 to htmlparser2!

Now, let’s talk about the first three features and how they simplify building AMP pages and integrating AMP into Frameworks and CMSs.

Auto AMP component extension import

Auto AMP component import means that AMP Optimizer will analyze the DOM for any used AMP components and will automatically inject all needed scripts imports into the head.

For example, if it encounters the following tag:

<amp-video src="video.mp4" width="300" height="200"></amp-video>

It will automatically add the amp-video script extension import:

<script async custom-element="amp-video"   src=""></script>

This works also for AMP components which don’t require a specific tag:

<div amp-fx="fade-in">I will fade in</div>

In this case, the presence of the amp-fx attribute will trigger the import of the amp-fx-collection script:

<script async custom-element="amp-fx-collection" src=""></script>

This is pretty awesome, because many AMP features are now super straightforward to use and no longer require you to go to the AMP docs and copy/paste the script import. We’re expecting to see a significant drop in traffic once this feature has been widely adopted!

Auto add any missing mandatory AMP tags.

The other piece of the puzzle for how AMP Optimizer improves developer experience is the ability to add any missing mandatory AMP tags. For example, given the following HTML fragment:

  <title>My Page</title>
  <link rel="canonical" href="/mypage.html" />
  <h1>Hello World!</h1>

AMP Optimizer will automatically add all the mandatory tags and attributes needed to turn this into a valid AMP page:

<!doctype html>
<html >
  <meta charset="utf-8">
  <title>My Page</title>
  <link rel="canonical" href="/mypage.html" />
  <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
  <style amp-boilerplate>...</noscript>
  <script async src=""></script>
  <h1>Hello World!</h1>

This means, you don’t need to include any AMP specific markup in your layout templates when using AMP Optimizer. Together with auto component import, creating AMP pages becomes as easy as using built in HTML tags.

Working towards improved AMP support for Frameworks and CMSs 

This AMP Optimizer release is the first stepping stone in offering better AMP support in frameworks and CMS platforms. 

Next.js already offers great AMP support and has AMP Optimizer already built in. This means that with this AMP Optimizer release (available in Next.js v9.2.2), creating AMP pages in Next.js has become even easier. You can now directly use AMP components (in this case amp-fx-collection):

export const config = {amp: true};

export default () => (
 <div amp-fx='fade-in'>I will fade-in</div>

Without having to explicitly import the amp-fx-collection-.0.1.js component script via the <Head>:

import Head from 'next/head'
export const config = {amp: true};

export default () => (
   <div amp-fx='fade-in'>I will fade-in</div>

Markdown Support

This AMP Optimizer release adds a new markdown mode, which will convert <img> tags into <amp-img> or <amp-anim> tags (all other Markdown features are already supported by AMP).

This enables the following conversion flow: => HTML => AMP Optimizer => valid AMP

Combined with automatically AMP component script import and automatically adding missing mandatory AMP tags it’s now possible to directly convert markdown into valid AMP:

const AmpOptimizer = require('@ampproject/toolbox-optimizer');
const md = require('markdown-it')({
  // don't sanitize html if you want to support AMP components in Markdown
  html: true,

// enable markdown mode
const ampOptimizer = AmpOptimizer.create({
  markdown: true,

const markdown = `
# Markdown 

Here is an image declared in Markdown syntax: 

![A random image](

You can directly declare AMP components:

<amp-twitter width="375" 

Any missing extensions will be automatically imported.

const html = md.render(markdown);

// valid AMP!
const amphtml = await ampOptimizer.transformHtml(html, {
  canonical: filePath,


Every website publishing AMP pages should use AMP Optimizer to benefit from the performance improvements of up to 50% faster rendering times. The best part: performance will automatically get better over time with every new server-side optimization that is released. 
The new features introduced with this release greatly improve the AMP developer experience. Using AMP components becomes as straightforward as using any other HTML tag. But this is only the first step and we plan to build upon this in the future and bring AMP support to more frameworks and CMS Stay tuned to the AMP Blog and follow @AMPhtml on Twitter for any future news on the AMP Optimizer.

Written by Sebastian Benz, Developer Programs Engineer, AMP Project, Google

An update on AMP Conf

AMP Conf

Thanks for your interest in AMP Conf 2020. With event registration approaching quickly and growing concern around the coronavirus (COVID-19), and in alignment with the best practices laid out by the CDC, WHO, and other relevant entities, we wanted to share an important update. Based on our most up-to-date assessment, the potential difficulties around travel, and in consideration of general public health and safety, we have decided to postpone the event. 

If you have any questions, feel free to email the AMP Conf planning team at: 

We’re very sorry to delay the opportunity to connect in person, but we feel strongly that the safety and health of all attendees, especially those who are traveling, is the priority at this time.

We will aim to share an updated date for the event in the future when we have a better sense of a time that will work for everyone. 

Stay tuned!

Posted by Alex Durán, AMP Project Marketing Lead at Google on behalf of the AMP Conf planning team

Learn how to use the Search Console AMP status report


The following guest post was written by Daniel Waisberg, Search Advocate, Google

Search Console is a free tool provided by Google to webmasters and developers to help optimize sites for search. In addition to data about search performance, index coverage and structured data markup, the tool can also help improve your AMP implementation. It shows AMP issues Google discovered in your website, provides information on how to fix them, and allows you to ask Google to validate your fixes. 

We’ve released a new episode of our Search Console Training YouTube series that shows you how to use the AMP status report in the tool.

In a nutshell, the AMP status report top level view shows crawled AMP pages with any issues found by Google. You’ll find a table with all issues sorted by a combination of severity, validation state, and number of pages affected. Click a specific issue to see more details and   a link to learn more about how to fix it and a process to notify Google about your fixes. You’ll also find a list of example URLs affected by this issue – you can click a specific URL to find the HTML and exact location of the offending code. 

It might also be a good idea to use the AMP Test tool, where in addition to testing a specific page, you can also upload a piece of code to check for issues – this can be helpful to debug issues for new pages. This tool will check your general AMP implementation, without specific information about Google indexing, so there is no need to verify your website to use it.

We hope you enjoy the videos and it helps you improve your AMP implementation! If you’re not using Search Console, check out the options available to verify your site ownership. For questions or comments, reach out via the Webmasters Help Community or our Twitter account

How RebelMouse Makes Rich AMP Simple And Powerful And Why It Matters So Much


Editor’s note: the following guest post was written by Andrea Breanna, Founder/CEO of RebelMouse

RebelMouse is a next-generation CMS for media companies and brands that are genuine about their content. The RebelCMS is a developer-friendly, cloud-based solution that is obsessed with maximizing content distribution across the web. This obsession is built on the foundational tenet that to create continuous organic growth from content, the distribution of that content must be automatic and optimized for new channels. We enable smart developers to be hyper-efficient and give their companies more, anywhere, and at any time. Whether you’re on mobile or desktop, you get the same streamlined functionality, key insights, and content distribution to grow your business.

Why We’ve Invested Heavily in AMP Features

AMP pages are built to be fast and load almost instantly when clicked from Google Search, increasing user engagement and dropping bounce rates. Our team at RebelMouse has  found that these increases in organic traffic happen regardless of the traffic source — because readers really do like faster, cleaner pages.

AMP is a rich environment and implementing it properly can be time-consuming. AMP pages, in order to be fast, are highly structured, and companies need efficient tools to take full advantage of the opportunities that AMP provides. When implemented correctly, the impact for a digital business is remarkable:

RebelMouse AMP features helped these sites to quickly adopt AMP and see huge traffic increases in Q4 2019, showing improvement even with non-AMP traffic.

We’ve seen that time and time again, as AMP traffic increases, so does non-AMP traffic. Because of this correlation, we dedicate significant development resources to integrating AMP technology into our CMS. Every RebelMouse-powered site is continuously updated for performance and features that keep our clients hypermodern, while allowing total creative freedom. AMP is no exception.

Below are some of the ways we’re pushing the envelope with AMP to make it a seamless part of the publishing workflow, decrease the friction of implementation, and maximize the traffic benefits.

Structured Data for High Performance on Search

AMP pages should have the same structured data that open web pages do. RebelMouse makes this simple to implement and the results can be game-changing.

The RebelCMS is built to maximize performance on search by adding structured data to AMP pages, which helps position your content within rich search results. Structured data gives platforms like Google the ability to better display information about your page, making it easier for users to understand what your site is about.

Rapid Development of Rich AMP Environments
RebelMouse’s Entry Editor allows content creators to easily enable AMP, AMP stories, and choose to enable AMP on mobile and/or desktop.

Quickly design AMP pages that outperform industry standards with an average of five pages per user. With the RebelCMS, you can choose to enable AMP by default, or implement it across articles individually with one click in our Entry Editor. Because rich functionality is supported out of the box, developer implementations and customizations take a fraction of the time compared to industry standards.

Simplified AMP Layout Creation and Management

Our Layout & Design tool allows you to easily implement dynamic AMP layouts, either through the default canonical usage, or when forcing AMP on mobile and/or desktop. Using this tool, it’s possible to create complex, multi-column layouts with ease that will be served as lightning-fast AMP pages to your visitors.

The RebelCMS intelligently serves the proper layout depending on the device that a visitor is using to view your site’s content. You might have different layout templates for news articles, sponsored content, recipes, etc.

These templates can be enabled directly from the editing interface so that every article will be presented in the best possible way for optimal user engagement.

AMP-First Experiences for Mobile and Desktop

To maximize the speed benefits of AMP, RebelMouse also provides a way to enable AMP for mobile and desktop traffic on a per-article basis. Developers can easily configure sites to run all articles as AMP first. When enabled, traffic for the article will be redirected to the AMP version of the page for better performance.

AMP-first experiences lead to faster load times which may enable clients to be ranked higher. Readers really do like faster, cleaner pages, and the positive impact on stats is overwhelmingly clear.

What makes RebelMouse’s implementation of native AMP options so powerful is that they can be controlled on a per-article basis, so that posts which may need an embed that’s not supported by AMP can exist as exceptions.

Add Conversion Units to Maximize Audience Retention

Interstitial conversion units can be placed within your content so you can build a mailing list, get leads, or just highlight a new feature to your audience.

Integrate Ad Blocks for AMP Monetization

Got ads? With the RebelCMS, you can easily add your ad blocks to your AMP pages for maximum monetization of your audience.

Next-Gen Content Authoring for AMP

All of the best features of the RebelCMS’s Entry Editor have been included for AMP, so you can rest assured that you will not be missing anything critical by expanding your usage of AMP within your organization.

Full Support for the RebelMouse Particle Assembler

When using AMP on the RebelCMS, the benefits of our Particle Assembler are maintained in full. Every particle is still sharable and the same pageview methodology is active by default. Particle Assembler is a core feature of our platform that makes it incredibly easy to author rich content for your site, including listicles, slideshows, and more. Now you can bring the power of our creation tools to your AMP pages as well.

Native Stats and Data Integrations

RebelMouse tracks AMP performance directly from within the CMS and offers connections to all major analytics platforms so you can get the data you need to make the best decisions for your business.

Multivariate Testing With Rich Data Insights

Try multiple AMP layouts and compare them to determine the best performing layout for your content.

Stay on Top of Data With AMP Linkers

RebelMouse fully supports AMP Linker functionality, allowing you to remember your users’ settings and preferences by appending relevant parameters to your URLs. This ensures that their sessions remain in sync when they move between your domain and AMP’s cache domain, maintaining the integrity of the user journey so you don’t lose important analytical insights.

Learn More About RebelMouse

AMP Conf 2020: Return to NYC

AMP Conf

UPDATE: Given the recent events surrounding COVID-19 (coronavirus), AMP Conf has been postponed. Please read our latest update regarding AMP Conf.

AMP Conf 2019 in Tokyo

Last year over 500 of us gathered in Tokyo to share the latest AMP news and learn from some of the thousands of developers engaged with the open source project. A lot has happened in the world of AMP since then, including AMP joining the OpenJS Foundation, our release for general availability of <amp-script>, Adobe Campaign launching support for AMP For Email, and many other exciting developments. We’ve seen amazing growth in the AMP community as developers around the world continue to build beautiful, performant sites, all while using AMP as a way to stay productive and innovative.

AMP Conf returns to NYC!

We are thrilled to invite you to join us at the next AMP Conf, being held in New York City on June 16 and 17. We are so excited to be returning to the city where AMP Conf got its start, and can’t wait to see you there. Come to learn about the latest ways the AMP community is working to make the web better for everyone – publishers, platforms, advertisers, creators, and of course, users. You’ll hear from those working on contributing to AMP, those using the format, and the committees who manage AMP’s governance. 

We also want to continue the tradition of including broader community voices by inviting you to submit ideas for talks. We want to hear about the most interesting things you’ve done with AMP, how AMP has increased your team’s productivity, how you’ve approached building AMP pages, or how you’ve innovated with AMP Stories, AMP For Email, and AMP Ads. Stay tuned for more information and a form to submit ideas for talks.

We will be releasing applications for spots at AMP Conf in the coming month, but in the meantime click here to save the date on your calendar. We’ll also share more details soon regarding a limited number of travel scholarships for those who may need travel support, especially those from underrepresented communities.

If you’re unable to attend in person, we’ll be recording and live streaming all of the talks, so subscribe to the AMP YouTube channel to catch those videos in the meantime.

Stay tuned for details on registration and the talk agenda as we get closer to the event! We look forward to seeing many of you in New York City later this year! 

Posted by Alex Durán, AMP Project Marketing Lead at Google 

In search of the search


Editor’s Note: the following guest post was written by Thorsten Harders and Sebil Satici, Developers at Jung von Matt. offers a lot of resources that make it easier to get started and build with AMP: case studies, details on how each component works, guides with best practices, step-by-step tutorials and plenty of executable code examples. In fact, it offers so many resources that we needed a way for developers to quickly discover and reach all that existing content. We wanted to do so by making all of our content searchable directly on the site. This article walks through the steps we took to implement search on

TL;DR: The new search is built using <amp-lightbox>, <amp-list>, <amp-autocomplete>, <amp-mustache> and of course <amp-bind> to glue them all together. It uses a custom API that is backed by Google custom search and it uses Service Worker functionalities to cache the latest search query and results.

Built with AMP components

We had three goals when building the search functionality:

  1. The search should be accessible in its own layer from all pages.
  2. The search should be optimized for finding AMP components, as these are core to the AMP developer experience.
  3. The search should be implemented using valid AMP functionalities.

Hide and show the search layer (with amp-lightbox)

Looking around the web you’ll see many different types of search functions. Some are just plain input fields while others expand and collapse with fancy animations. Some trigger a page-load to paginated result pages, others asynchronously display results. Some auto-suggest search terms, others don’t. For we wanted to combine the best of those approaches to come up with a solution that manages to stay out of the user’s way as much as possible while at the same time being quickly accessible. Therefore, we decided to encapsulate the whole search in a fullscreen layer to:

  • suggest interesting articles to users (e.g new guides or components that have been published) no matter what page the user is on
  • avoid distracting the user with other elements on the page
  • quickly display the search results inline without having to load an extra results page

To accomplish our needs we have decided to continue with <amp-lightbox>. It makes it easy for us to hide and show the search layer while offering us helpful actions and events we could use for the integration in our AMP frontend.

Adding seamless interaction

From a user experience perspective, it was particularly important to us that the user achieves a seamless transition between entering the search query and seeing the result. When the user opens the search layer, the input field is automatically focused and the user can start typing right away. When the search layer is closed, we focus the search toggle again, so that keyboard users can continue in the same position as before.

We implemented this feature using the <amp-lightbox> open and close events in combination with the global focus action:

<amp-lightbox layout="nodisplay"

Listing the search results (with amp-list and amp-mustache)

For displaying the search results on the page, we use the <amp-list> component as it has paging and infinite scroll already built-in – exactly what you need when listing search results.  The actual search is implemented server-side and can be accessed via an API endpoint /search/do which returns a JSON object similar to this:

  "result": {
    "pageCount": 10,
    "pages": [
        "title": "Some title",
        "description": "Description",
        "url": ""
  "nextUrl": "/search/do?q=amp&page=2"

We use amp-bind to update the full search URL in our  <amp-list>, by binding the [src] attribute to the input query. To enable infinite scrolling, we set the load-more attribute and for a cleaner reload experience when triggering subsequent searches, we set the reset-on-refresh attribute. In the <amp-mustache> template we use the data from the result object to render the list dynamically. Here is the code:

<amp-list id="searchList"
          [src]="query ? '/search/initial-items : '/search/do?q=' + 
  <template type="amp-mustache">
    <div class="search-result-list">
      <a href="{{url}}">

Suggest what matters (with amp-autocomplete)

According to our analytics data, developers most often visit to access AMP component documentation and samples. That’s why we wanted to make these as easy to discover as possible. With <amp-autocomplete>, AMP offers an out-of-the-box solution for implementing auto-suggestions. The goal is to auto-suggest all available AMP components. The static datasource is provided by the /search/autosuggest endpoint and the autocomplete generates suggestions client-side using the filter="substring" designation.

<amp-autocomplete filter="substring"
                  on="select:AMP.setState({    query: event.value })"
    <input placeholder="What are you looking for?">

Executing the search (with amp-form)

Users can trigger the search by selecting one of the auto-suggested options or submitting the form. To execute the actual search request we are using the state query as a URL parameter.

<amp-list [src]="'/search/do?q=' + encodeURIComponent(query) + '&locale=en'">

Based on the on action in the amp-autocomplete, the query is updated (and amp-list rerenders) both when the form submits and when autocomplete emits a select event.

<form action-xhr="/search/echo"
          AMP.setState({ query: queryInput }),
      method="POST" target="_top">
  <amp-autocomplete filter="substring"
                    on="select:AMP.setState({ query: event.value })"
    <input id="searchInput"
           placeholder="What are you looking for?"
           on="input-throttled:AMP.setState({ queryInput: event.value })"
    <button disabled [disabled]="!queryInput">Search</button>

When the form is submitted we also focus the search result container to let the keyboard navigation start directly with the first entry. Additionally, we call changeToLayoutContainer of the <amp-list> to ensure the list’s height will change according to the content and can get smaller. Because in our case the result of the form submit event is not needed, we simply point to an echo action. Sidenote: this won’t be needed in the future as it’s soon going to be possible to use `amp-autocomplete` without  a form.

Caching previous search results via Service Worker

After we launched the first version of the search we received a related feature request fairly quickly: keep showing the results for the latest search query, even when the user navigates to another page.

To achieve this, we built upon AMP’s one-line Service Worker amp-sw which offers basic PWA functionalities like caching and offline pages. We extended it to store the latest search query and the corresponding search results.

When a search is started, we display the previous search query and its results. Otherwise, we will display a list of suggested articles. On page load, we initialize an amp-state object from a server endpoint /search/latest-query which populates the search input field and the search results:

// search.html
<amp-state id="query" src="/search/latest-query"></amp-state>

<amp-list src="/search/initial-items"
          [src]="query ? '/search/initial-items : '/search/do?q=' + encodeURIComponent(query)"

The trick is: this server-endpoint does not exist. The magic happens in the Service Worker which intercepts the route and creates a new response with the cached search query and search results from the user’s last search request and sends it back to the page instead of loading the original response from the network.

To save the latest search query, we grab the query parameter from the requested URL with a regular expression and store it in a newly created response object in our cache.

Then the route handler checks if there is an entry in the cache that matches the search request. If there is the results are returned from the cache immediately. Otherwise, the request falls through to the server and then gets cached for the following calls.

// serviceworker.js
async function searchDoRequestHandler(url, request) {
  const searchQuery = decodeURIComponent([^&]+)/)[1]);
  const cache = await;

  cache.put(SEARCH_LATEST_QUERY_PATH, new Response(`"${searchQuery}"`));

  let response = await cache.match(request);
  if (response) return response;

  response = await fetch(request);
  if (response.status == 200) {
    cache.delete(request, {
      ignoreSearch: true,
    cache.put(request, response.clone());

  return response;

This way when the user opens the search layer on another page, they automatically receive their previous search results back and can continue where they left off.

Here you can see how a handler function is registered:

// serviceworker.js
self.addEventListener('fetch', (event) => {
  const requestUrl = new URL(event.request.url);
  if (requestUrl.pathname === '/search/do') {
    event.respondWith(searchDoRequestHandler(requestUrl, event.request));

Intercepting and dynamically changing requests with the help of the Service Worker API is a neat way whenever you want to personalize data used by AMP components that load data from remote endpoints like <amp-state> or <amp-list> et al. Just like it helped us to enhance the user experience for the search by caching the user’s latest search query.


With the implementation of a search function within, we accomplished our goal of allowing users to precisely navigate the content of the site in an intuitive and efficient manner. For even better user experience, we are also caching previous search results with Service Worker functionalities.

The cool thing about this is that we integrated the search without a single line of JavaScript (except the Service Worker part). Just by making use of AMP’s existing components we could integrate useful features like auto-suggestion and infinite scrolling, which would be quite challenging to implement otherwise!

Written by Thorsten Harders and Sebil Satici, Developers at Jung von Matt

SEO for AMP Stories


Updated March 24, 2020 to clarify how AMP’s canonical-pairing is not supported by AMP Stories.

AMP Stories are a new, exciting medium for storytelling on the web. The format is based on the same concept as familiar Stories features in popular social networking apps but intended for more general purpose content from “how to apply lip gloss the right way” to a “travel guide through the Himalayas”. Importantly, AMP Stories are just web pages. They have a URL on your web server, they are linkable, and they can link out to other web pages. With that the biggest takeaway for SEO of Stories is:

Do all the SEO things you would do for any other page on your website. If it helps rank your non-Story pages, it’ll probably help the Stories as well.

In particular, just like other pages on your site, make sure your Stories are linked from within your website so that your users and bots can actually discover them. If you are using a sitemap, make sure to include your Stories in that sitemap. If you are posting your regular web pages to social media, post your Stories as well. We could go on here, but the gist really comes down to: Follow the best practices you’re already applying to the rest of your website.

Stories specific SEO tactics

Given the relative newness of this format on the web and its unique characteristics, there are SEO tactics specific to Stories. These tactics aren’t comprehensive and should be augmented with all the standard SEO work being done for your web pages that’s described above.


AMP Stories have a built-in mechanism to attach metadata to a Story. Make sure all your Stories follow these metadata guidelines. This ensures maximum compatibility with search engines and discovery features that take advantage of that metadata.

Additionally, make sure you include all the title, description,, OGP, Twitter card, etc. markup you would include in any other web page.

Linking to Stories

We recommend deeply integrating Stories into your website such as linking them from your homepage or category pages where applicable. E.g. if your Story is about a travel destination and you have a page that lists all your travel articles, then also link the Stories on that category page. An additional special landing page like (which would then be linked from key pages like your homepage) might also make sense.

Links from within your site and to other websites are a critical component of how the web works and optimizing for discoverability. As Stories are web pages themselves, this is also true for them.

URL format

There is no need to indicate in the URL of a Story that it is using the AMP Stories format. Ideally your Stories are integrated into a wider URL strategy. For example, if your “New York Travel” articles are using a format like “/new-york/travel/title-of-article.html” then consider using the exact same directory structure and URL format for your Stories.

Page attachments

Page attachments can be used to present additional information in “classic article form” alongside your Story. This can be useful to provide extra detail, deep dives, or onward journeys for the content presented in your Story.

Image descriptions

While this best practice technically applies to all web pages, we have seen folks omit “alt” text for images in Stories. We strongly recommend adding meaningful “alt” text where appropriate to optimize for accessibility and indexability of your content.

Video subtitles

Consider providing subtitles and/or captions for the videos in your Stories.

Video-only Stories

We recommend that you take full advantage of semantic HTML to build up your story. However, some tools designed for the social media use case may instead export a story such that each slide is represented as a video file that bakes in all the text into the video. In this case it is recommended to add the precise text displayed inside of the video as a “title” attribute on the amp-video element. Again, only do this if you absolutely cannot use semantic markup in your Stories generation.


While the Stories format is traditionally associated with mobile consumption, AMP Stories also work on desktop with optional support for landscape displays. This means that your Stories can also appear in desktop search results without any extra work.

AMP’s canonical-pairing is not supported

Although AMP Stories are created using the AMP framework, AMP Stories should be self-canonical. That is, the <link rel=”amphtml”..> pairing that is frequently used by AMP Pages is not available for Stories. A long form article (or standalone video) and an AMP Story about the same topic are different stand-alone web experiences; one should not be canonical for the other. However, if you have a separate story webpage with the same content as an AMP Story, you should consider making the AMP Story canonical. Make sure to AMP-validate your Web Stories.

The Secret of SEO

As a final reminder: Content is king! Like any web page, providing high quality content that is useful and interesting to your users is and will always be the most important “SEO tactic” that cannot be ignored and takes precedence above all else. Include a complete narrative and follow these best practices to take advantage of the unique characteristics of the format to keep the users engaged. 


SEO for Stories is like SEO for any other web page. Your SEO skills should translate 1:1 to Stories. A limited number of Stories-specific SEO best practices exist and they are documented in this blog post. Finally, remember to include high quality content and good luck optimizing your Stories!

Posted by Flavio Palandri Antonelli, Software Engineer at Google