diff --git a/senat_campaign/migrations/0006_auto_20200601_1819.py b/senat_campaign/migrations/0006_auto_20200601_1819.py
new file mode 100644
index 0000000000000000000000000000000000000000..2f28277e69678e9ce4d59a1bed865f3042586e8d
--- /dev/null
+++ b/senat_campaign/migrations/0006_auto_20200601_1819.py
@@ -0,0 +1,63 @@
+# Generated by Django 3.0.6 on 2020-06-01 16:19
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("wagtailimages", "0022_uploadedimage"),
+        ("senat_campaign", "0005_delete_senatcampaignwebsettings"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="senatcampaigncookiespage",
+            name="search_image",
+            field=models.ForeignKey(
+                blank=True,
+                null=True,
+                on_delete=django.db.models.deletion.SET_NULL,
+                related_name="+",
+                to="wagtailimages.Image",
+                verbose_name="Search image",
+            ),
+        ),
+        migrations.AddField(
+            model_name="senatcampaignhomepage",
+            name="search_image",
+            field=models.ForeignKey(
+                blank=True,
+                null=True,
+                on_delete=django.db.models.deletion.SET_NULL,
+                related_name="+",
+                to="wagtailimages.Image",
+                verbose_name="Search image",
+            ),
+        ),
+        migrations.AddField(
+            model_name="senatcampaignnewsindexpage",
+            name="search_image",
+            field=models.ForeignKey(
+                blank=True,
+                null=True,
+                on_delete=django.db.models.deletion.SET_NULL,
+                related_name="+",
+                to="wagtailimages.Image",
+                verbose_name="Search image",
+            ),
+        ),
+        migrations.AddField(
+            model_name="senatcampaignprogrampage",
+            name="search_image",
+            field=models.ForeignKey(
+                blank=True,
+                null=True,
+                on_delete=django.db.models.deletion.SET_NULL,
+                related_name="+",
+                to="wagtailimages.Image",
+                verbose_name="Search image",
+            ),
+        ),
+    ]
diff --git a/senat_campaign/models.py b/senat_campaign/models.py
index 73855641ea1001b41218fb7f9d34c495f0ef89f9..2500019a57f8cd1353bf40d7559017070d0e0702 100644
--- a/senat_campaign/models.py
+++ b/senat_campaign/models.py
@@ -12,8 +12,33 @@ from wagtail.core.models import Page
 from wagtail.documents.blocks import DocumentChooserBlock
 from wagtail.images.blocks import ImageChooserBlock
 from wagtail.images.edit_handlers import ImageChooserPanel
+from wagtailmetadata.models import MetadataPageMixin
 
 from calendar_utils.models import CalendarMixin
+from tuning import help
+
+HELP_COMBINED_TITLE = (
+    "Pokud není zadán <strong>Titulek stránky</strong>, použije se "
+    "<strong>Název</strong> (tab obsah) doplněný o jméno kandidáta."
+)
+
+
+class SubpageMixin:
+    """Must be used in class definition before MetadataPageMixin!"""
+
+    @property
+    def root_page(self):
+        if not hasattr(self, "_root_page"):
+            self._root_page = self.get_parent().specific
+        return self._root_page
+
+    def get_meta_image(self):
+        return self.search_image or self.root_page.get_meta_image()
+
+    def get_meta_title(self):
+        if self.seo_title:
+            return self.seo_title
+        return f"{self.title} | {self.root_page.full_name}"
 
 
 class ContactBlock(blocks.StructBlock):
@@ -28,7 +53,7 @@ class ContactBlock(blocks.StructBlock):
         label = "kontaktní osoba"
 
 
-class SenatCampaignHomePage(Page, CalendarMixin):
+class SenatCampaignHomePage(Page, MetadataPageMixin, CalendarMixin):
     # top section
     headline = models.CharField("podtitulek pod jménem", max_length=250, blank=True)
     top_photo = models.ForeignKey(
@@ -123,12 +148,15 @@ class SenatCampaignHomePage(Page, CalendarMixin):
     promote_panels = [
         MultiFieldPanel(
             [
-                HelpPanel(
-                    "Název stránky na předchozím tabu slouží k rozlišení stránek "
-                    "v Majáku. V prohlížeči se zobrazí tento titulek."
-                ),
                 FieldPanel("seo_title"),
                 FieldPanel("search_description"),
+                ImageChooserPanel("search_image"),
+                HelpPanel(
+                    help.build(
+                        help.IMPORTANT_TITLE,
+                        "Pokud není zadán <strong>Search image</strong>, použije se úvodní foto kandidáta.",
+                    )
+                ),
             ],
             gettext_lazy("Common page configuration"),
         ),
@@ -165,6 +193,9 @@ class SenatCampaignHomePage(Page, CalendarMixin):
     def root_page(self):
         return self
 
+    def get_meta_image(self):
+        return self.search_image or self.top_photo
+
     @property
     def full_name(self):
         return f"{self.first_name} {self.last_name}"
@@ -236,7 +267,7 @@ class SenatCampaignHomePage(Page, CalendarMixin):
         return context
 
 
-class SenatCampaignNewsIndexPage(Page):
+class SenatCampaignNewsIndexPage(Page, SubpageMixin, MetadataPageMixin):
     parent_page_types = ["senat_campaign.SenatCampaignHomePage"]
     subpage_types = ["senat_campaign.SenatCampaignNewsPage"]
 
@@ -246,6 +277,8 @@ class SenatCampaignNewsIndexPage(Page):
                 FieldPanel("slug"),
                 FieldPanel("seo_title"),
                 FieldPanel("search_description"),
+                ImageChooserPanel("search_image"),
+                HelpPanel(help.build(HELP_COMBINED_TITLE, help.NO_SEARCH_IMAGE)),
             ],
             gettext_lazy("Common page configuration"),
         ),
@@ -259,12 +292,6 @@ class SenatCampaignNewsIndexPage(Page):
     class Meta:
         verbose_name = "Aktuality"
 
-    @property
-    def root_page(self):
-        if not hasattr(self, "_root_page"):
-            self._root_page = self.get_parent().specific
-        return self._root_page
-
     def get_context(self, request):
         context = super().get_context(request)
         articles = self.get_children().live().order_by("-senatcampaignnewspage__date")
@@ -272,7 +299,7 @@ class SenatCampaignNewsIndexPage(Page):
         return context
 
 
-class SenatCampaignNewsPage(Page):
+class SenatCampaignNewsPage(Page, SubpageMixin, MetadataPageMixin):
     date = models.DateField("datum")
     perex = models.TextField("perex")
     body = RichTextField("článek", blank=True)
@@ -283,6 +310,8 @@ class SenatCampaignNewsPage(Page):
         null=True,
         blank=True,
     )
+    # we will use photo as search image
+    search_image = None
 
     content_panels = Page.content_panels + [
         FieldPanel("date"),
@@ -297,6 +326,12 @@ class SenatCampaignNewsPage(Page):
                 FieldPanel("slug"),
                 FieldPanel("seo_title"),
                 FieldPanel("search_description"),
+                HelpPanel(
+                    help.build(
+                        HELP_COMBINED_TITLE,
+                        "Pokud není zadán <strong>Popis vyhledávání</strong>, použije se prvních 150 znaků <strong>Perexu</strong> (tab obsah).",
+                    )
+                ),
             ],
             gettext_lazy("Common page configuration"),
         ),
@@ -311,14 +346,6 @@ class SenatCampaignNewsPage(Page):
     class Meta:
         verbose_name = "Aktualita"
 
-    @property
-    def root_page(self):
-        if not hasattr(self, "_root_page"):
-            self._root_page = (
-                self.get_ancestors().type(SenatCampaignHomePage).specific().get()
-            )
-        return self._root_page
-
     def get_context(self, request):
         context = super().get_context(request)
         context["related_articles"] = (
@@ -328,6 +355,24 @@ class SenatCampaignNewsPage(Page):
         )
         return context
 
+    @property
+    def root_page(self):
+        if not hasattr(self, "_root_page"):
+            self._root_page = (
+                self.get_ancestors().type(SenatCampaignHomePage).specific().get()
+            )
+        return self._root_page
+
+    def get_meta_image(self):
+        return self.photo
+
+    def get_meta_description(self):
+        if self.search_description:
+            return self.search_description
+        if len(self.perex) > 150:
+            return str(self.perex)[:150] + "..."
+        return self.perex
+
 
 class ProgramBlock(blocks.StructBlock):
     title = blocks.CharBlock(label="titulek")
@@ -340,7 +385,7 @@ class ProgramBlock(blocks.StructBlock):
         label = "programový bod"
 
 
-class SenatCampaignProgramPage(Page):
+class SenatCampaignProgramPage(Page, SubpageMixin, MetadataPageMixin):
     committee_preference = StreamField(
         [("committee", blocks.CharBlock(label="výbor či komise"))],
         verbose_name="preferované výbory a komise",
@@ -361,6 +406,8 @@ class SenatCampaignProgramPage(Page):
                 FieldPanel("slug"),
                 FieldPanel("seo_title"),
                 FieldPanel("search_description"),
+                ImageChooserPanel("search_image"),
+                HelpPanel(help.build(HELP_COMBINED_TITLE, help.NO_SEARCH_IMAGE)),
             ],
             gettext_lazy("Common page configuration"),
         ),
@@ -377,14 +424,8 @@ class SenatCampaignProgramPage(Page):
     class Meta:
         verbose_name = "Program"
 
-    @property
-    def root_page(self):
-        if not hasattr(self, "_root_page"):
-            self._root_page = self.get_parent().specific
-        return self._root_page
-
 
-class SenatCampaignCookiesPage(Page):
+class SenatCampaignCookiesPage(Page, SubpageMixin, MetadataPageMixin):
     body = RichTextField("obsah", blank=True)
 
     content_panels = Page.content_panels + [
@@ -397,6 +438,8 @@ class SenatCampaignCookiesPage(Page):
                 FieldPanel("slug"),
                 FieldPanel("seo_title"),
                 FieldPanel("search_description"),
+                ImageChooserPanel("search_image"),
+                HelpPanel(help.build(HELP_COMBINED_TITLE, help.NO_SEARCH_IMAGE)),
             ],
             gettext_lazy("Common page configuration"),
         ),
@@ -412,9 +455,3 @@ class SenatCampaignCookiesPage(Page):
 
     class Meta:
         verbose_name = "Cookies"
-
-    @property
-    def root_page(self):
-        if not hasattr(self, "_root_page"):
-            self._root_page = self.get_parent().specific
-        return self._root_page
diff --git a/senat_campaign/templates/senat_campaign/base.html b/senat_campaign/templates/senat_campaign/base.html
index 091d15a07b807ced7b2f095db0cbd77be14e8785..2cf07267aa1d819c992d2aa4c486308251230f76 100644
--- a/senat_campaign/templates/senat_campaign/base.html
+++ b/senat_campaign/templates/senat_campaign/base.html
@@ -1,4 +1,4 @@
-{% load static wagtailuserbar wagtailcore_tags wagtailimages_tags %}
+{% load static wagtailuserbar wagtailcore_tags wagtailimages_tags wagtailmetadata_tags %}
 <!doctype html>
 <html lang="cs">
 <head>
@@ -21,29 +21,10 @@
   <!-- Meta -->
   <meta charset="utf-8">
   <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-  <meta name="description" content="{% firstof page.search_description page.perex|truncatechars:150 %}">
-  <meta name="author" content="Piráti">
-  {% if page.seo_title %}
-  <title>{{ page.seo_title }}</title>
-  {% else %}
-  <title>{{ page.title }} | {{ page.root_page.full_name }}</title>
-  {% endif %}
-
-  <!-- OpenGraph info -->
-  <meta property="og:title" content="{% firstof page.seo_title page.title page.root_page.full_name %}" />
-  <meta property="og:type" content="website" />
-  <meta property="og:locale" content="cs_CZ" />
-  <meta property="og:url" content="{{ page.full_url }}" />
-  {# TODO #}
-  <meta property="og:image" content="{% static "shared/img/og_image.jpg" %}" />
-  <meta property="og:description" content="{% firstof page.search_description page.perex %}" />
+  {% meta_tags %}
 
   <!-- Favicon -->
-  <link rel="icon" type="image/png" href="{% static "shared/favicon/favicon-196.png" %}" sizes="196x196">
-  <link rel="icon" type="image/png" href="{% static "shared/favicon/favicon-128.png" %}" sizes="128x128">
-  <link rel="icon" type="image/png" href="{% static "shared/favicon/favicon-96.png" %}" sizes="96x96">
-  <link rel="icon" type="image/png" href="{% static "shared/favicon/favicon-32.png" %}" sizes="32x32">
-  <link rel="icon" type="image/png" href="{% static "shared/favicon/favicon-16.png" %}" sizes="16x16">
+  {% include "shared/favicon_snippet.html" %}
 
   <!-- Bootstrap CSS -->
   <link rel="stylesheet" href="{% static "shared/vendor/bootstrap-4.4.1/css/bootstrap.min.css" %}">