Paweł Kowalski
Posted on April 23, 2020
Promoting content on social media is an important part of marketing. If you want to make sure your posts/tweets/stories are eye-catching or at least visible on the user's wall, you probably want to leverage OpenGraph tags to provide additional metadata to your content that will not only inform search engines about your content but also improve the appearence of social media cards.
Problem
When we started posting content on social media we noticed that our social media cards were missing images, descriptions. We decided to fix that on our documentation website and it proved to be pretty easy to do.
To check if your site is already optimized, use the following official tools:
- Twitter: https://cards-dev.twitter.com/validator
- Facebook: https://developers.facebook.com/tools/debug
- LinkedIn: https://www.linkedin.com/post-inspector
Ideally what you want to see is a title, a description and an image showing up.
Solution
Most of the metadata we used are standard OpenGraph.
OpenGraph (Facebook, LinkedIn)
If you need more information about any of the properties used, read the OpenGraph official documentation.
<meta property="og:locale" content="en_US" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="platformOS Documentation" />
<meta property="article:section" content="Uncategorized" />
<meta property="og:title" content="{{ title }}" />
<meta property="og:description" content="{{ description }}" />
<meta property="og:url" content="{{ context.location.url }}" />
<meta property="article:published_time" content="{{ dates.created_at }}" />
<meta property="article:modified_time" content="{{ dates.content_updated_at }}" />
<meta property="og:updated_time" content="{{ dates.content_updated_at }}" />
<meta property="og:image" content="{{ 'images/pos-logo.png' | asset_url }}" />
<meta property="og:image:width" content="730" />
<meta property="og:image:height" content="412" />
We hardcoded some of the metadata because we did not see the need to make it dynamic. You might want to also add author
- consult the documentation to choose the best tags for your use case.
Here's an explanation for the dynamic parts:
-
title
: a variable that we calculate based on what is in the current page metadata. We reused our title tag content here. -
description
: same as above, we reused our usual meta data description content here -
image
: absolute URL to the image. The image we used is 713x412px, but you can experiment with dimensions that fit your content/logo better. -
url
: absolute URL to the page (with query params if essential) -
published_time
: date when the content was first published - see below how we got thedates
object -
modified_time
: datetime when the content was last modified - see below how we got thedates
object -
updated_time
: datetime when the content was last modified - see below how we got thedates
object
Dates
We did not use dates before, so we needed to pull those from the database using GraphQL. We used the admin_pages
endpoint, filtered one page with the slug of the current page and pulled the date of file creation and the date of the last edit of the page body (not including metadata like title).
{% graphql page_dates, slug: context.page.slug %}
query get_dates($slug: String!) {
admin_pages(
per_page: 1
filter: { slug: { value: $slug } }
) {
results {
content_updated_at
created_at
}
}
}
{% endgraphql %}
{% assign dates = page_dates | fetch: 'admin_pages' | fetch: 'results' | first %}
Twitter uses its own set of metadata to extract for its cards preview.
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:description" content="{{ description }}" />
<meta name="twitter:title" content="{{ title }}" />
<meta name="twitter:image" content="{{ 'images/pos-logo-2to1.png' | asset_url }}" />
Here's an explanation of new elements:
-
card
: there are a couple of different card types that Twitter supports, we chosesummary_large_image
because it shows the image in a prolific way -
image
: Twitter requires the image to be in 2:1 aspect ratio forsummary_large_image
or it will not show, so we prepared another image for that reason
Results
The difference in visibility is pretty big but what's more important, users are able to instantly tell what the link is about before they click it.
Before:
After:
Structured data
After you have prepared your OpenGraph metadata, it is also a good idea to add so called structured data into your website.
Structured data helps search engines find and understand your content and website. It is organized and tagged with specific groups of text that help search engines understand the context of that information and can return accurate results to searchers.
This metadata is sometimes used by websites to generate rich snippets instead of OpenGraph. Additionally, this data is used by search engines to populate their rich snippets. Using structured data you can describe your content in detail. Because of that, it is more flexible. It is possible to describe the relation between entities (author, image, website). The more details you provide (within reason), the better.
Example
<script type='application/ld+json'>
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "WebSite",
"@id": "https://documentation.platformos.com",
"url": "https://documentation.platformos.com",
"name": "platformOS Documentation",
"inLanguage": "en-US",
"description": "Examples, tutorials, references, APIs, and best practices—everything you need to build future-proof applications on platformOS"
},
{
"@type": "ImageObject",
"inLanguage": "en-US",
"url": "{{ 'images/pos-logo.png' | asset_url }}",
"width": 730,
"height": 412,
"caption": "platformOS Documentation"
},
{
"@type": "WebPage",
"url": "{{ context.location.url }}",
"name": "{{ title }}",
"description": "{{ description }}",
"isPartOf": {
"@id": "https://documentation.platformos.com"
},
"inLanguage": "en-US",
"primaryImageOfPage": {
"@id": "{{ 'images/pos-logo.png' | asset_url }}"
},
"datePublished": "{{ dates.created_at }}",
"dateModified": "{{ dates.content_updated_at }}",
"potentialAction": [
{
"@type": "ReadAction",
"target": [
"{{ context.location.url }}"
]
}
]
}
]
}
</script>
We basically recycled data we used in OpenGraph, and added very simple relations.
Resources
When you develop your own structured data, validate it on https://search.google.com/structured-data/testing-tool/u/0/ - it will show you warnings and errors should you encounter them.
Read the standard specification on: https://schema.org/docs/documents.html
Read these articles to get more practical information than from the official documentation:
- https://developers.google.com/search/docs/guides/intro-structured-data
- https://www.lullabot.com/articles/create-seo-juice-by-adding-json-ld-structured-data-to-drupal-8
- https://neilpatel.com/blog/structured-data/
- https://medium.com/slack-developer-blog/everything-you-ever-wanted-to-know-about-unfurling-but-were-afraid-to-ask-or-how-to-make-your-e64b4bb9254
Posted on April 23, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.