diff --git a/config/_default/params.yaml b/config/_default/params.yaml
index c5e2cd9..c17d7df 100644
--- a/config/_default/params.yaml
+++ b/config/_default/params.yaml
@@ -8,3 +8,8 @@ cta:
# Footer
footer_logo: "/images/colored-logo.png"
copyright_text: "© Neurodata Without Borders - All Rights Reserved"
+
+# Search results and link previews, for pages that have no description or
+# image of their own
+description: "Neurodata Without Borders (NWB) is a data standard and software ecosystem for neurophysiology and behavioral data."
+shareImage: "/images/share-card.jpg"
diff --git a/layouts/partials/essentials/head.html b/layouts/partials/essentials/head.html
index a2fcfcc..d8e7dc7 100644
--- a/layouts/partials/essentials/head.html
+++ b/layouts/partials/essentials/head.html
@@ -2,6 +2,7 @@
+{{ partial "essentials/metadata.html" . }}
{{/* Title */}}
{{ if not .IsHome }}{{ .Title | plainify }} -{{ end }}{{ .Site.Title }}
diff --git a/layouts/partials/essentials/metadata.html b/layouts/partials/essentials/metadata.html
new file mode 100644
index 0000000..1058d13
--- /dev/null
+++ b/layouts/partials/essentials/metadata.html
@@ -0,0 +1,54 @@
+{{/*
+ Description and link preview tags.
+
+ The description is the first of these that is set: `description`, `summary`
+ (events) or `subtitle` (news) in the front matter, the start of the page
+ body, then `description` in config/_default/params.yaml.
+
+ The preview image is the page's `image` when it is a PNG or JPEG no wider
+ than 3.3:1. Wider logo strips lose most of their width when a preview crops
+ them, so those pages, like pages with a GIF or with no image, use
+ `shareImage` from the same file.
+*/}}
+{{ $title := site.Title }}
+{{ if and .Title (not .IsHome) }}
+ {{ $title = .Title | plainify | htmlUnescape | replaceRE `\s+` " " }}
+{{ end }}
+
+{{ $description := .Params.description | default .Params.summary | default .Params.subtitle | default .Summary | default site.Params.description }}
+{{ $description = $description | plainify | htmlUnescape | replaceRE `\s+` " " | truncate 200 }}
+{{ $description = trim $description " " }}
+
+{{ $image := site.Params.shareImage | absURL }}
+{{ $largeImage := true }}
+{{ with .Params.image }}
+ {{ if hasPrefix . "http" }}
+ {{ $image = . }}
+ {{ else }}
+ {{ $path := index (split . "#") 0 }}
+ {{ $file := printf "static%s" $path }}
+ {{ if and (findRE `(?i)\.(png|jpe?g)$` $path) (fileExists $file) }}
+ {{ $config := imageConfig $file }}
+ {{ $ratio := div (float $config.Width) $config.Height }}
+ {{ if le $ratio 3.3 }}
+ {{ $image = $path | absURL }}
+ {{ $largeImage = and (ge $ratio 1.5) (ge $config.Width 600) }}
+ {{ end }}
+ {{ end }}
+ {{ end }}
+{{ end }}
+
+
+
+
+
+
+
+{{ if and .IsPage (eq .Section "news") }}
+
+ {{ with .Date }}{{ end }}
+{{ else }}
+
+{{ end }}
+{{/* X reads the Open Graph tags above for everything except the card type. */}}
+
diff --git a/static/images/share-card.jpg b/static/images/share-card.jpg
new file mode 100644
index 0000000..401a877
Binary files /dev/null and b/static/images/share-card.jpg differ