diff --git a/docs/advanced_topics/amp.rst b/docs/advanced_topics/amp.rst
new file mode 100644
index 000000000..ee7c4dae9
--- /dev/null
+++ b/docs/advanced_topics/amp.rst
@@ -0,0 +1,340 @@
+Building a site with AMP support
+================================
+
+This recipe document describes a method for creating an
+`AMP `_ version of a Wagtail site and hosting it separately
+to the rest of the site on a URL prefix. It also describes how to make Wagtail
+render images with the ```` tag when a user is visiting a page on the
+AMP version of the site.
+
+Overview
+--------
+
+In the next section, we will add a new URL entry that points at Wagtail's
+internal ``serve()`` view which will have the effect of rendering the whole
+site again under the ``/amp`` prefix.
+
+Then, we will add some utilities that will allow us to track whether the
+current request is in the ``/amp`` prefixed version of the site without needing
+a request object.
+
+After that, we will add a template context processor to allow us to check from
+within templates which version of the site is being rendered.
+
+Then, finally, we will modify the behaviour of the ``{% image %}`` tag to make it
+render ```` tags when rendering the AMP version of the site.
+
+Creating the second page tree
+-----------------------------
+
+We can render the whole site at a different prefix by duplicating the Wagtail
+URL in the project ``urls.py`` file and giving it a prefix. This must be before
+the default URL from Wagtail, or it will try to find ``/amp`` as a page:
+
+.. code-block:: python
+
+ # /urls.py
+
+ urlpatterns += [
+ # Add this line just before the default ``include(wagtail_urls)`` line
+ url(r'amp/', include(wagtail_urls)),
+
+ url(r'', include(wagtail_urls)),
+ ]
+
+If you now open ``http://localhost:8000/amp/`` in your browser, you should see
+the homepage.
+
+Making pages aware of "AMP mode"
+--------------------------------
+
+All the pages will now render under the ``/amp`` prefix, but right now there
+isn't any difference between the AMP version and the normal version.
+
+To make changes, we need to add a way to detect which URL was used to render
+the page. To do this, we will have to wrap Wagtail's ``serve()`` view and
+set a thread-local to indicate to all downstream code that AMP mode is active.
+
+.. note:: Why a thread-local?
+
+ (feel free to skip this part if you're not interested)
+
+ Modifying the ``request`` object would be the most common way to do this.
+ However, the image tag rendering is performed in a part of Wagtail that
+ does not have access to the request.
+
+ Thread-locals are global variables that can have a different value for each
+ running thread. As each thread only handles one request at a time, we can
+ use it as a way to pass around data that is specific to that request
+ without having to pass the request object everywhere.
+
+ Django uses thread-locals internally to track the currently active language
+ for the request.
+
+ Please be aware though: In Django 3.x and above, you will need to use an
+ ``asgiref.Local`` instead.
+ This is because Django 3.x handles multiple requests in a single thread
+ so thread-locals will no longer be unique to a single request.
+
+Now let's create that thread-local and some utility functions to interact with it,
+save this module as ``amp_utils.py`` in an app in your project:
+
+.. code-block:: python
+
+ # /amp_utils.py
+
+ from contextlib import contextmanager
+ from threading import local
+
+ # FIXME: For Django 3.0 support, replace this with asgiref.Local
+ _amp_mode_active = local()
+
+ @contextmanager
+ def activate_amp_mode():
+ """
+ A context manager used to activate AMP mode
+ """
+ _amp_mode_active.value = True
+ try:
+ yield
+ finally:
+ del _amp_mode_active.value
+
+ def amp_mode_active():
+ """
+ Returns True if AMP mode is currently active
+ """
+ return hasattr(_amp_mode_active, 'value')
+
+This module defines two functions:
+
+ - ``activate_amp_mode`` is a context manager which can be invoked using Python's
+ ``with`` syntax. In the body of the ``with`` statement, AMP mode would be active.
+
+ - ``amp_mode_active`` is a function that returns ``True`` when AMP mode is active.
+
+Next, we need to define a view that wraps Wagtail's builtin ``serve`` view and
+invokes the ``activate_amp_mode`` context manager:
+
+.. code-block:: python
+
+ # /amp_views.py
+
+ from django.template.response import SimpleTemplateResponse
+ from wagtail.core.views import serve as wagtail_serve
+
+ from .amp_utils import activate_amp_mode
+
+ def serve(request, path):
+ with activate_amp_mode():
+ response = wagtail_serve(request, path)
+
+ # Render template responses now while AMP mode is still active
+ if isinstance(response, SimpleTemplateResponse):
+ response.render()
+
+ return response
+
+Then we need to create a ``amp_urls.py`` file in the same app:
+
+.. code-block:: python
+
+ # /amp_urls.py
+
+ from django.conf.urls import url
+ from wagtail.core.urls import serve_pattern
+
+ from . import amp_views
+
+ urlpatterns = [
+ url(serve_pattern, amp_views.serve, name='wagtail_amp_serve')
+ ]
+
+Finally, we need to update the project's main ``urls.py`` to use this new URLs
+file for the ``/amp`` prefix:
+
+.. code-block:: python
+
+ # /urls.py
+
+ from myapp import amp_urls as wagtail_amp_urls
+
+ urlpatterns += [
+ # Change this line to point at your amp_urls instead of Wagtail's urls
+ url(r'amp/', include(wagtail_amp_urls)),
+
+ url(r'', include(wagtail_urls)),
+ ]
+
+After this, there shouldn't be any noticeable difference to the AMP version of
+the site.
+
+Write a template context processor so that AMP state can be checked in templates
+--------------------------------------------------------------------------------
+
+This is optional, but worth doing so we can confirm that everything is working
+so far.
+
+Add a ``amp_context_processors.py`` file into your app that contains the
+following:
+
+.. code-block:: python
+
+ # /amp_context_processors.py
+
+ from .amp_utils import amp_mode_active
+
+ def amp(request):
+ return {
+ 'amp_mode_active': amp_mode_active(),
+ }
+
+Now add the path to this context processor to the
+``['OPTIONS']['context_processors']`` key of the ``TEMPLATES`` setting:
+
+.. code-block:: python
+
+ # Either /settings.py or /settings/base.py
+
+ TEMPLATES = [
+ {
+ ...
+
+ 'OPTIONS': {
+ 'context_processors': [
+ ...
+ # Add this after other context processors
+ 'myapp.amp_context_processors.amp',
+ ],
+ },
+ },
+ ]
+
+You should now be able to use the ``amp_mode_active`` variable in templates.
+For example:
+
+.. code-block:: html+Django
+
+ {% if amp_mode_active %}
+ AMP MODE IS ACTIVE!
+ {% endif %}
+
+Using a different page template when AMP mode is active
+-------------------------------------------------------
+
+You're probably not going to want to use the same templates on the AMP site as
+you do on the regular web site. Let's add some logic in to make Wagtail use a
+separate template whenever a page is served with AMP enabled.
+
+We can use a mixin, which allows us to re-use the logic on different page types.
+Add the following to the bottom of the amp_utils.py file that you created earlier:
+
+.. code-block:: python
+
+ # /amp_utils.py
+
+ import os.path
+
+ ...
+
+ class PageAMPTemplateMixin:
+
+ @property
+ def amp_template(self):
+ # Get the default template name and insert `_amp` before the extension
+ name, ext = os.path.splitext(self.template)
+ return name + '_amp' + ext
+
+ def get_template(self, request):
+ if amp_mode_active():
+ return self.amp_template
+
+ return super().get_template(request)
+
+Now add this mixin to any page model, for example:
+
+.. code-block:: python
+
+ # /models.py
+
+ from .amp_utils import PageAMPTemplateMixin
+
+ class MyPageModel(PageAMPTemplateMixin, Page):
+ ...
+
+When AMP mode is active, the template at ``app_label/mypagemodel_amp.html``
+will be used instead of the default one.
+
+If you have a different naming convention, you can override the
+``amp_template`` attribute on the model. For example:
+
+.. code-block:: python
+
+ # /models.py
+
+ from .amp_utils import PageAMPTemplateMixin
+
+ class MyPageModel(PageAMPTemplateMixin, Page):
+ amp_template = 'my_custom_amp_template.html'
+
+Overriding the ``{% image %}`` tag to output ```` tags
+---------------------------------------------------------------
+
+Finally, let's change Wagtail's ``{% image %}`` tag, so it renders an ````
+tags when rendering pages with AMP enabled. We'll make the change on the
+`Rendition` model itself so it applies to both images rendered with the
+``{% image %}`` tag and images rendered in rich text fields as well.
+
+Doing this with a :ref:`Custom image model ` is easier, as
+you can override the ``img_tag`` method on your custom ``Rendition`` model to
+return a different tag.
+
+For example:
+
+.. code-block:: python
+
+ from django.forms.utils import flatatt
+ from django.utils.safestring import mark_safe
+
+ from wagtail.images.models import AbstractRendition
+
+ ...
+
+ class CustomRendition(AbstractRendition):
+ def img_tag(self, extra_attributes):
+ attrs = self.attrs_dict.copy()
+ attrs.update(extra_attributes)
+
+ if amp_mode_active():
+ return mark_safe(''.format(flatatt(attrs)))
+ else:
+ return mark_safe('
'.format(flatatt(attrs)))
+
+ ...
+
+Without a custom image model, you will have to monkey-patch the builtin
+``Rendition`` model.
+Add this anywhere in your project where it would be imported on start:
+
+.. code-block:: python
+
+ from django.forms.utils import flatatt
+ from django.utils.safestring import mark_safe
+
+ from wagtail.images.models import Rendition
+
+ def img_tag(rendition, extra_attributes={}):
+ """
+ Replacement implementation for Rendition.img_tag
+
+ When AMP mode is on, this returns an tag instead of an
tag
+ """
+ attrs = rendition.attrs_dict.copy()
+ attrs.update(extra_attributes)
+
+ if amp_mode_active():
+ return mark_safe(''.format(flatatt(attrs)))
+ else:
+ return mark_safe('
'.format(flatatt(attrs)))
+
+ Rendition.img_tag = img_tag
diff --git a/docs/advanced_topics/index.rst b/docs/advanced_topics/index.rst
index e9b581b5a..27dbb00cf 100644
--- a/docs/advanced_topics/index.rst
+++ b/docs/advanced_topics/index.rst
@@ -18,3 +18,4 @@ Advanced topics
jinja2
testing
api/index
+ amp