<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ open graph - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ open graph - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 25 Aug 2026 10:12:17 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/open-graph/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Gatsby Starter Blog: How to Add Header Images to Posts with Support for Twitter Cards ]]>
                </title>
                <description>
                    <![CDATA[ By David Good If you're like me, you used Gatsby Starter Blog to kickstart your personal blog, made a few customizations, and then just rolled with it.  Adding new posts in the form of markdown is great. But it also means you rarely have a reason to ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/gatsby-blog-header-image-twitter-card/</link>
                <guid isPermaLink="false">66d45e01680e33282da25e4d</guid>
                
                    <category>
                        <![CDATA[ blog ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Gatsby ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GraphQL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ open graph ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Twitter ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 29 Dec 2020 00:33:15 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/12/freeCodeCamp-GatsbyBlogImageTwitterCard-5.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By David Good</p>
<p>If you're like me, you used <a target="_blank" href="https://www.gatsbyjs.com/starters/gatsbyjs/gatsby-starter-blog">Gatsby Starter Blog</a> to kickstart your personal blog, made a few customizations, and then just rolled with it. </p>
<p>Adding new posts in the form of markdown is great. But it also means you rarely have a reason to look at the code. So when I decided to add header images to my posts with support for <a target="_blank" href="https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/abouts-cards">Twitter Cards</a>, I felt lost.</p>
<p>My requirements were to be able to add a large header image with a caption to a post as you can see here:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://davidagood.com/dynamodb-enhanced-client-java-heterogeneous-item-collections/">https://davidagood.com/dynamodb-enhanced-client-java-heterogeneous-item-collections/</a></div>
<p>Furthermore, a tweet which contains a link to the post should "expand" into <a target="_blank" href="https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/summary-card-with-large-image">Twitter's Summary Card with Large Image</a>, like this:</p>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/helloworldless/status/1336323721254948864"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<p>And finally, for posts which do not specify an image, a default image should be shown using <a target="_blank" href="https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/summary">Twitter's Summary Card</a>. Here's what that looks like where I've used my website logo as the default image:</p>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/helloworldless/status/1338482084445347844"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<p><strong>Note:</strong> Twitter's docs state that a website logo should not be used for a card image (see <code>twitter:image</code> section <a target="_blank" href="https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/summary#reference">here</a>). I'll leave it to you to decide whether it makes sense to use a fixed image as a fallback like I have here.</p>
<h2 id="heading-getting-started">Getting Started</h2>
<p>Here are the five high-level steps which I will be guiding you through. I'll attempt to explain everything in depth and provide links to other resources along the way. That way you will build up your knowledge of Gatsby which you can draw from to tackle the later, more complicated steps.</p>
<ol>
<li>Add Document Metadata Tags</li>
<li>Source Default Image using GraphQL</li>
<li>Source Post-Specific Image Properties using GraphQL</li>
<li>Add Header Image to Blog Post Template</li>
<li>Add New Properties to Post's Frontmatter</li>
</ol>
<p>The tools which we'll be using to accomplish this all come out of the box with <a target="_blank" href="https://www.gatsbyjs.com/starters/gatsbyjs/gatsby-starter-blog">Gatsby Starter Blog</a>!</p>
<ul>
<li><a target="_blank" href="https://github.com/nfl/react-helmet">React Helmet</a> - Used in the <code>SEO</code> component to add meta tags to the document head to support Twitter Cards and other <a target="_blank" href="https://ogp.me/">Open Graph</a> tags</li>
<li><a target="_blank" href="https://www.gatsbyjs.com/plugins/gatsby-source-filesystem/">Gatsby Source Filesystem</a> - A "plugin for sourcing data into your Gatsby application from your local filesystem", images in our case</li>
<li><a target="_blank" href="https://www.gatsbyjs.com/plugins/gatsby-image/">Gatsby Image</a> - "a React component specially designed to work seamlessly with Gatsby’s GraphQL queries. It combines <a target="_blank" href="https://image-processing.gatsbyjs.org/">Gatsby’s native image processing</a> capabilities with advanced image loading techniques to easily and completely optimize image loading for your sites. <code>gatsby-image</code> uses <a target="_blank" href="https://www.gatsbyjs.com/packages/gatsby-plugin-sharp/">gatsby-plugin-sharp</a> to power its image transformations."</li>
<li><a target="_blank" href="https://www.gatsbyjs.com/plugins/gatsby-plugin-sharp/">Gatsby Plugin Sharp</a> - "Exposes several image processing functions built on the <a target="_blank" href="https://github.com/lovell/sharp">Sharp image processing library</a>". We use this for resizing images.</li>
</ul>
<h2 id="heading-how-to-add-document-metadata-tags">How to Add Document Metadata Tags</h2>
<p>First, we will wire up the HTML metadata tags which can be read by Twitter and any other platform or tool which understands <a target="_blank" href="https://ogp.me/">Open Graph</a> such as Google, Facebook, and WhatsApp. </p>
<p>Learn more about document metadata here: <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML">What’s in the head? Metadata in HTML</a>.</p>
<p>Open the <code>SEO</code> component in <code>src/components/seo.js</code>. The first thing to notice is that this is using <a target="_blank" href="https://github.com/nfl/react-helmet">React Helmet</a>, and it already has many Open Graph and Twitter meta tags like <code>og:title</code>, <code>twitter:description</code>. It even has a <code>twitter:card</code> tag with a value of "summary" which enables a basic Twitter Summary Card with no image:</p>
<pre><code class="lang-js"><span class="hljs-comment">// src/components/seo.js</span>
<span class="hljs-keyword">const</span> SEO = <span class="hljs-function">(<span class="hljs-params">{ description, lang, meta, title }</span>) =&gt;</span> { 
<span class="hljs-comment">// Details omitted for brevity </span>
<span class="hljs-keyword">return</span> ( 
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Helmet</span> 
        <span class="hljs-attr">htmlAttributes</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">lang</span> }} 
        <span class="hljs-attr">title</span>=<span class="hljs-string">{title}</span> 
        <span class="hljs-attr">titleTemplate</span>=<span class="hljs-string">{</span>`%<span class="hljs-attr">s</span> | ${<span class="hljs-attr">site.siteMetadata.title</span>}`} 
        <span class="hljs-attr">meta</span>=<span class="hljs-string">{[</span> 
            { <span class="hljs-attr">name:</span> `<span class="hljs-attr">description</span>`, <span class="hljs-attr">content:</span> <span class="hljs-attr">metaDescription</span>, }, 
            { <span class="hljs-attr">property:</span> `<span class="hljs-attr">og:title</span>`, <span class="hljs-attr">content:</span> <span class="hljs-attr">title</span>, }, 
            { <span class="hljs-attr">property:</span> `<span class="hljs-attr">og:description</span>`, <span class="hljs-attr">content:</span> <span class="hljs-attr">metaDescription</span>, }, 
            { <span class="hljs-attr">property:</span> `<span class="hljs-attr">og:type</span>`, <span class="hljs-attr">content:</span> `<span class="hljs-attr">website</span>`, }, 
            { <span class="hljs-attr">property:</span> `<span class="hljs-attr">twitter:card</span>`, <span class="hljs-attr">content:</span> `<span class="hljs-attr">summary</span>`, }, 
            { <span class="hljs-attr">property:</span> `<span class="hljs-attr">twitter:creator</span>`, 
              <span class="hljs-attr">content:</span> <span class="hljs-attr">site.siteMetadata.social.twitter</span>, }, 
            // <span class="hljs-attr">...</span></span></span>
</code></pre>
<p>Let's update this component:</p>
<ol>
<li>Add <code>imageUrl</code> and <code>imageAlt</code> parameters. These will be passed as props by the <code>BlogPostTemplate</code> component as we will see later. Note that that I've used "URL" in the prop name to convey the fact that this must be a fully-qualified URL. Relative paths are not supported for the OG image!</li>
<li>Construct the default image URL, <code>defaultImageUrl</code>. I've written a tiny utility function, <code>constructUrl</code>, to concatenate a base URL with a relative path. We will see where <code>data.ogImageDefault</code> comes from in the next section.</li>
<li>Add an <code>ogImageUrl</code> variable which takes the <code>imageSrcUrl</code> prop or, if that's not provided, defaults to <code>defaultImageUrl</code>.</li>
<li>Add objects to the <code>meta</code> array passed to the <code>Helmet</code> component: <code>og:image</code>, <code>twitter:card</code>, and <code>twitter:image:alt</code></li>
</ol>
<p>A few things to note here:</p>
<ol>
<li>Twitter does have its own <code>twitter:image</code> meta tag, but per the <a target="_blank" href="https://developer.twitter.com/en/docs/twitter-for-websites/cards/guides/getting-started#twitter-cards-and-open-graph">docs</a>, we don't need to add both the <code>og:image</code> and the <code>twitter:image</code> tag since Twitter's parser will fall back to the Open Graph tags.</li>
<li>Open Graph specifies the <code>meta</code> attributes <code>property</code> and <code>content</code> whereas Twitter specifies <code>name</code> and <code>content</code>, respectively. But again, the Twitter docs state that their parser will fall back to the Open Graph attributes. This is nice because we can maintain consistency and don't need a bunch of repetitive properties with the same values which we have to keep in sync.</li>
<li>Notable exceptions to using the <code>property</code> attribute on <code>meta</code> tags are any non-Open Graph tags like <code>description</code> which must use the <code>name</code> attribute. I encourage you to use <a target="_blank" href="https://developers.google.com/web/tools/lighthouse">Lighthouse</a> which will identify basic issues with your SEO.</li>
</ol>
<pre><code class="lang-js"><span class="hljs-comment">// util.js</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> constructUrl = <span class="hljs-function">(<span class="hljs-params">baseUrl, path</span>) =&gt;</span>
  (!baseUrl || !path) ? <span class="hljs-literal">null</span> : <span class="hljs-string">`<span class="hljs-subst">${baseUrl}</span><span class="hljs-subst">${path}</span>`</span>;

<span class="hljs-comment">// src/components/seo.js</span>
<span class="hljs-comment">// Step 1: Add props</span>
<span class="hljs-keyword">const</span> SEO = <span class="hljs-function">(<span class="hljs-params">{ description, lang, meta, title, imageUrl, imageAlt }</span>) =&gt;</span> { 

    <span class="hljs-keyword">const</span> data = useStaticQuery(
        <span class="hljs-comment">// This is explained next</span>
    );

    <span class="hljs-comment">// Step 2: Construct default image URL</span>
    <span class="hljs-comment">// ogImageDefault is explained next</span>
    <span class="hljs-keyword">const</span> defaultImageUrl = constructUrl(data.site.siteMetadata.siteUrl, data.ogImageDefault?.childImageSharp?.fixed?.src)

    <span class="hljs-comment">// Step 3: Add this</span>
    <span class="hljs-keyword">const</span> ogImageUrl = imageUrl || defaultImageUrl; 

    <span class="hljs-keyword">return</span> ( 
        <span class="hljs-comment">// Step 4: Add new meta objects</span>
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Helmet</span> 
            <span class="hljs-attr">htmlAttributes</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">lang</span> }} 
            <span class="hljs-attr">title</span>=<span class="hljs-string">{title}</span> 
            <span class="hljs-attr">titleTemplate</span>=<span class="hljs-string">{</span>`%<span class="hljs-attr">s</span> | ${<span class="hljs-attr">site.siteMetadata.title</span>}`} 
            <span class="hljs-attr">meta</span>=<span class="hljs-string">{[</span>
                { <span class="hljs-attr">property:</span> `<span class="hljs-attr">og:image</span>`, <span class="hljs-attr">content:</span> <span class="hljs-attr">ogImageUrl</span>, }, 

                // <span class="hljs-attr">If</span> <span class="hljs-attr">a</span> <span class="hljs-attr">post</span> <span class="hljs-attr">has</span> <span class="hljs-attr">an</span> <span class="hljs-attr">image</span>, <span class="hljs-attr">use</span> <span class="hljs-attr">the</span> <span class="hljs-attr">larger</span> <span class="hljs-attr">card.</span> 
                // <span class="hljs-attr">Otherwise</span> <span class="hljs-attr">the</span> <span class="hljs-attr">default</span> <span class="hljs-attr">image</span> <span class="hljs-attr">is</span> <span class="hljs-attr">just</span> 
                // <span class="hljs-attr">a</span> <span class="hljs-attr">small</span> <span class="hljs-attr">logo</span>, <span class="hljs-attr">so</span> <span class="hljs-attr">use</span> <span class="hljs-attr">the</span> <span class="hljs-attr">smaller</span> <span class="hljs-attr">card.</span>
                { <span class="hljs-attr">property:</span> `<span class="hljs-attr">twitter:card</span>`, <span class="hljs-attr">content:</span> <span class="hljs-attr">imageUrl</span> ? `<span class="hljs-attr">summary_large_image</span>` <span class="hljs-attr">:</span> `<span class="hljs-attr">summary</span>`, }, 

                // <span class="hljs-attr">Add</span> <span class="hljs-attr">image</span> <span class="hljs-attr">alt</span> <span class="hljs-attr">text</span>
                // <span class="hljs-attr">Falls</span> <span class="hljs-attr">back</span> <span class="hljs-attr">to</span> <span class="hljs-attr">default</span> <span class="hljs-attr">which</span> <span class="hljs-attr">describes</span> <span class="hljs-attr">the</span> <span class="hljs-attr">site</span> <span class="hljs-attr">logo</span>
                { <span class="hljs-attr">property:</span> `<span class="hljs-attr">twitter:image:alt</span>`, <span class="hljs-attr">content:</span> <span class="hljs-attr">imageAlt</span> || "<span class="hljs-attr">davidagood.com</span> <span class="hljs-attr">logo</span>", }, 
                // <span class="hljs-attr">...</span></span></span>
</code></pre>
<h2 id="heading-how-to-source-default-image-using-graphql">How to Source Default Image using GraphQL</h2>
<p>This is where Gatsby's filesystem and image processing capabilities come into play. Below is the <code>useStaticQuery</code> call GraphQL query from the <code>SEO</code> component. I've added the <code>ogImageDefault</code> portion and the <code>siteUrl</code> which is needed for the <code>constructUrl</code> call shown above.</p>
<pre><code class="lang-js"><span class="hljs-comment">// src/components/seo.js</span>
<span class="hljs-keyword">const</span> data = useStaticQuery(
    graphql<span class="hljs-string">`
      query {
        site {
          siteMetadata {
            title
            description
            social {
              twitter
            }
            # Add this
            siteUrl
          }
        }
        # Add this
        ogImageDefault: file(relativePath: {eq: "icon.png"}) { 
          childImageSharp {
            fixed(height: 260, width: 260) {
              src
            }
          }
        }
      }
    `</span>,
);
</code></pre>
<h3 id="heading-graphql-file-and-image-processing-query-explained">GraphQL File and Image Processing Query Explained</h3>
<p>The top level node is <code>ogImageDefault</code>. This is a <a target="_blank" href="https://graphql.org/learn/queries/#aliases">GraphQL alias</a> for the <code>file</code> query which is applying a filter to find a file with relative path equal to <code>icon.png</code>. The name I've chosen, <code>ogImageDefault</code>, is completely arbitrary.</p>
<p>One key thing to understand here is what the <code>relativePath</code> is relative to. In other words, where is this file, <code>icon.png</code>? </p>
<p>Let me start by telling you the location of the file relative to the project root: <code>./content/assets/icon.png</code>. In the query, I haven't specified any relative path, just the filename. So how does Gatsby know where to find it? </p>
<p>Enter <code>[gatsby-source-filesystem](https://www.gatsbyjs.com/plugins/gatsby-source-filesystem/)</code>. If you look in <code>gatsby-config.js</code> you will see some config like this:</p>
<pre><code class="lang-js"><span class="hljs-comment">// gatsby-config.js </span>
<span class="hljs-built_in">module</span>.exports = { 
    <span class="hljs-comment">// siteMetadata: {...}, </span>
    <span class="hljs-attr">plugins</span>: [ 
        <span class="hljs-comment">// Other plugins omitted </span>
        { 
            <span class="hljs-attr">resolve</span>: <span class="hljs-string">`gatsby-source-filesystem`</span>, 
            <span class="hljs-attr">options</span>: { 
                <span class="hljs-attr">path</span>: <span class="hljs-string">`<span class="hljs-subst">${__dirname}</span>/content/blog`</span>, 
                <span class="hljs-attr">name</span>: <span class="hljs-string">`blog`</span>, 
            }, 
        }, 
        { 
            <span class="hljs-attr">resolve</span>: <span class="hljs-string">`gatsby-source-filesystem`</span>, 
            <span class="hljs-attr">options</span>: { 
                <span class="hljs-attr">path</span>: <span class="hljs-string">`<span class="hljs-subst">${__dirname}</span>/content/assets`</span>, 
                <span class="hljs-attr">name</span>: <span class="hljs-string">`assets`</span>, 
            }, 
        }, 
        <span class="hljs-comment">// ...</span>
</code></pre>
<p>What this is doing is registering these paths as "content roots" and giving them a name. So the name <code>blog</code> refers to <code>./content/blog</code> relative to the project root. And the name <code>assets</code> refers to <code>./content/assets</code> relative to the project root. You can use these names in queries by filtering on <code>sourceInstanceName</code>:</p>
<pre><code class="lang-graphql"><span class="hljs-comment"># http://localhost:8000/___graphql </span>
{ 
    allFile(<span class="hljs-symbol">filter:</span> {<span class="hljs-symbol">sourceInstanceName:</span> {<span class="hljs-symbol">eq:</span> <span class="hljs-string">"blog"</span>}}) { 
        edges { 
            node { 
                absolutePath 
                publicURL 
                sourceInstanceName 
            } 
        } 
    } 
}
</code></pre>
<p>The result of this query:</p>
<pre><code class="lang-js"><span class="hljs-comment">// Result of allFiles query with sourceInstanceName filter </span>
{ 
    <span class="hljs-string">"data"</span>: { 
        <span class="hljs-string">"allFile"</span>: { 
            <span class="hljs-string">"edges"</span>: [{ 
                <span class="hljs-string">"node"</span>: { 
                    <span class="hljs-string">"absolutePath"</span>: <span class="hljs-string">"/home/dgood/IdeaProjects/davidagood.com/content/blog/clean-code-and-architecture/index.md"</span>, 
                    <span class="hljs-string">"publicURL"</span>: <span class="hljs-string">"/static/40bb02d938c4faf7f977dd66c1a399d2/index.md"</span>, 
                    <span class="hljs-string">"sourceInstanceName"</span>: <span class="hljs-string">"blog"</span> 
                } 
            }, 
            <span class="hljs-comment">// additional results...</span>
</code></pre>
<p>So back to <code>ogImageDefault</code>: the <code>relativePath</code> we provided was just <code>icon.png</code>, but the file is actually located at <code>./content/assets/icon.png</code>. </p>
<p>Gatsby was able to resolve to the file because we configured a "content root" at <code>./content/assets</code>. We could have specified the <code>sourceInstanceName</code> to remove any ambiguity as to which "content root" this file is located in. </p>
<p>In fact, I'm not sure how Gatsby would behave if the same relative path existed in multiple "content roots". </p>
<p>This would be a good opportunity to dig into the Gatsby's source code to understand how this all works, but I'll leave that to you!</p>
<p>Next up: what is <code>childImageSharp</code>? "Child" refers to this being a child node of a <code>File</code> node. "Image" is just like it sounds. "Sharp" is referring to the <a target="_blank" href="https://github.com/lovell/sharp">Sharp</a> image processing tool and corresponding Gatsby plugin, <a target="_blank" href="https://www.gatsbyjs.com/plugins/gatsby-plugin-sharp/">gatsby-plugin-sharp</a>, which enables these image processing features.</p>
<p><code>fixed</code> means we want transform the image into an image of a fixed size. We specify the dimensions by passing parameters like this: <code>fixed(height: 260, width: 260)</code>. There are a few alternatives to <code>fixed</code> which we could use, one of which we will see below.</p>
<p>Finally, we only need the <code>src</code> property for the purposes of the Open Graph image meta tag.</p>
<h2 id="heading-how-to-source-post-specific-image-properties-using-graphql">How to Source Post-Specific Image Properties using GraphQL</h2>
<p>Following from above, we must update the <code>BlogPostTemplate</code> component to pass the <code>imageUrl</code> and <code>imageAlt</code> props to the <code>SEO</code> component. Again, we use the <code>constructUrl</code> utility to convert the relative path, <code>src</code>, into a URL. I explain the origin of these props' values below.</p>
<pre><code class="lang-js"><span class="hljs-comment">// util.js</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> constructUrl = <span class="hljs-function">(<span class="hljs-params">baseUrl, path</span>) =&gt;</span>
  (!baseUrl || !path) ? <span class="hljs-literal">null</span> : <span class="hljs-string">`<span class="hljs-subst">${baseUrl}</span><span class="hljs-subst">${path}</span>`</span>;

<span class="hljs-comment">// src/templates/blog-post.js</span>
<span class="hljs-keyword">const</span> BlogPostTemplate = <span class="hljs-function">(<span class="hljs-params">{ data, pageContext, location }</span>) =&gt;</span> { 
    <span class="hljs-comment">// Details omitted for brevity</span>
    <span class="hljs-keyword">return</span> ( 
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span> <span class="hljs-attr">location</span>=<span class="hljs-string">{location}</span> <span class="hljs-attr">title</span>=<span class="hljs-string">{data.site.siteMetadata.title}</span>&gt;</span> 
            <span class="hljs-tag">&lt;<span class="hljs-name">SEO</span> 
                <span class="hljs-attr">title</span>=<span class="hljs-string">{data.markdownRemark.frontmatter.title}</span> 
                <span class="hljs-attr">description</span>=<span class="hljs-string">{data.markdownRemark.frontmatter.description</span> || <span class="hljs-attr">data.markdownRemark.excerpt</span>} 
                <span class="hljs-attr">imageUrl</span>=<span class="hljs-string">{</span>
                    <span class="hljs-attr">constructUrl</span>(
                        <span class="hljs-attr">data.site.siteMetadata.siteUrl</span>, <span class="hljs-attr">data.markdownRemark.frontmatter.image</span>?<span class="hljs-attr">.childImageSharp</span>?<span class="hljs-attr">.fixed</span>?<span class="hljs-attr">.src</span>
                )} 
                <span class="hljs-attr">imageAlt</span>=<span class="hljs-string">{data.markdownRemark.frontmatter.imageAlt}</span> /&gt;</span>
        // ...</span>
</code></pre>
<p>Sourcing the image alt text is straightforward: we add <code>imageAlt</code> as a property to the <code>frontmatter</code> portion of our <code>BlogPostTemplate</code> component's GraphQL query. This query is exported as a GraphQL tagged template. </p>
<p>The name of the exported constant is arbitrary. In my case it's <code>const pageQuery</code>. </p>
<p>This query gets executed for us by Gatsby, and the results are passed to the <code>BlogPostTemplate</code> component in the <code>data</code> prop. </p>
<p>This is explained in the Gatsby docs here: <a target="_blank" href="https://www.gatsbyjs.com/docs/how-to/querying-data/page-query/">Querying Data in Pages with GraphQL</a>.</p>
<p>In order to source the actual image, we use <code>childImageSharp</code> again but in a slightly different way than we saw above:</p>
<pre><code class="lang-js"><span class="hljs-comment">// src/templates/blog-post.js</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> pageQuery = graphql<span class="hljs-string">`
    query BlogPostBySlug($slug: String!) {
      site {
        siteMetadata {
          title
          siteUrl
        }
      }
      markdownRemark(fields: {slug: {eq: $slug}}) {
        id
        excerpt(pruneLength: 160)
        html
        frontmatter {
          title
          date(formatString: "MMMM DD, YYYY")
          description
          # Add this
          image {
            childImageSharp {
              fixed(height: 600, width: 1200) {
                src
              }
              fluid(maxWidth: 700, maxHeight: 500) {
                ...GatsbyImageSharpFluid
              }
            }
          }
          # Add these
          imageAlt
          imageTitleHtml
        }
      }
    }
`</span>;
</code></pre>
<p>Here, <code>image</code> must match the name of the property we intend to set in the post's frontmatter. And the value of this property must be a path to a file <strong>relative to the post markdown file</strong>. </p>
<p>This is similar to what we did above using a GraphQL alias and the <code>file</code> query, but here it's implicit and being handled behind the scenes by Gatsby.</p>
<p>We specify the dimensions in the parameters to the <code>fixed</code> field. When choosing the dimensions, make sure any image you use is at least as big as the dimensions you specify here, and use these guideline from the <a target="_blank" href="https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/summary-card-with-large-image#reference">docs</a>:</p>
<blockquote>
<p>Images for this Card support an aspect ratio of 2:1 with minimum dimensions of 300x157 or maximum of 4096x4096 pixels</p>
</blockquote>
<p>We have also added the <code>fluid</code> property and a <a target="_blank" href="https://graphql.org/learn/queries/#fragments">GraphQL fragment</a>, <code>...GatsbyImageSharpFluid</code>, which retrieves all of the properties available on this node without having to enumerate them one by one. </p>
<p>The Gatsby Image component is <a target="_blank" href="https://www.gatsbyjs.com/docs/reference/built-in-components/gatsby-image/#images-that-stretch-across-a-fluid-container">designed to be used this way</a> in order to provide a responsive image experience using <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">HTML's native responsive image capabilities</a>.</p>
<h2 id="heading-how-to-add-a-header-image-to-your-blog-post-template">How to Add a Header Image to your Blog Post Template</h2>
<p>With the GraphQL query updated and the results being passed to our component by Gatsby, we're ready to add the Gatsby Image import and the JSX for the header image and caption:</p>
<pre><code class="lang-js"><span class="hljs-comment">// src/templates/blog-post.js</span>
<span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">"gatsby-image"</span>;

<span class="hljs-comment">// Details omitted for brevity</span>

{data.markdownRemark.frontmatter.image?.childImageSharp?.fluid &amp;&amp;
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Image</span>
            <span class="hljs-attr">fluid</span>=<span class="hljs-string">{data.markdownRemark.frontmatter.image.childImageSharp.fluid}</span>
            <span class="hljs-attr">alt</span>=<span class="hljs-string">{data.markdownRemark.frontmatter.imageAlt}</span> 
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
                <span class="hljs-attr">textAlign:</span> "<span class="hljs-attr">center</span>",
                <span class="hljs-attr">fontSize:</span> "<span class="hljs-attr">14px</span>",
                <span class="hljs-attr">lineHeight:</span> "<span class="hljs-attr">28px</span>",
            }}
            <span class="hljs-attr">dangerouslySetInnerHTML</span>=<span class="hljs-string">{{</span> 
                <span class="hljs-attr">__html:</span> <span class="hljs-attr">data.markdownRemark.frontmatter.imageTitleHtml</span> 
            }} 
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span>/&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span>/&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
}
</code></pre>
<p>If the <code>image</code> or <code>imageAlt</code> properties are not set in a post's frontmatter, it won't cause any issues. Those properties will just be <code>null</code> in the post's <code>data</code> prop, for example <code>data.markdownRemark.frontmatter.image</code> and <code>data.markdownRemark.frontmatter.imageAlt</code>. </p>
<p>For that reason, I've used <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining">optional chaining</a> when passing the <code>imageUrl</code> prop to the <code>SEO</code> component: <code>data.markdownRemark.frontmatter.image?.childImageSharp?.fixed?.src</code> and when optionally adding the header image component tree: <code>data.markdownRemark.frontmatter.image?.childImageSharp?.fluid</code>.</p>
<h2 id="heading-how-to-add-new-properties-to-a-posts-frontmatter">How to Add New Properties to a Post's Frontmatter</h2>
<p>Now all that's left is to add the actual image file, typically in the same directory as the markdown where we want to use it. Then we add the <code>image</code>, <code>imageAlt</code>, and <code>imageTitleHtml</code> properties to the post's frontmatter. </p>
<p>I've taken the suggested attribution HTML directly from <a target="_blank" href="https://unsplash.com/">Unsplash</a> and used it for the <code>imageTitleHtml</code>.</p>
<p>Remember: in this case, the image path is relative to the post markdown file.</p>
<pre><code class="lang-md">--- 
title: "Working with Heterogeneous Item Collections in the DynamoDB Enhanced Client for Java" 
date: "2020-12-07T01:51:34.815Z"
description: "Working with heterogeneous item collections with the Java SDKs can be tricky. Here we see how to handle 
them with the AWS SDK v2 for Java's Enhanced Client."
image: "./kevin-mueller-gGUiw8GNIFE-unsplash.jpg"
imageAlt: "Water droplets on black background"
imageTitleHtml: '<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span></span>Photo by <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://unsplash.com/@kevinmueller?utm_source=unsplash<span class="hljs-symbol">&amp;amp;</span>utm_medium=referral<span class="hljs-symbol">&amp;amp;</span>utm_content=creditCopyText"</span>&gt;</span></span>Kevin Mueller<span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span></span> on <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://unsplash.com/?utm_source=unsplash<span class="hljs-symbol">&amp;amp;</span>utm_medium=referral<span class="hljs-symbol">&amp;amp;</span>utm_content=creditCopyText"</span>&gt;</span></span>Unsplash<span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span></span><span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span></span>'

--- 

// Markdown here...
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>That's it – you did it! We covered quite a few concepts in this article. You should now be able to add header images to your blog posts and get nice Open Graph-based preview experiences on Twitter, Facebook, Google, WhatsApp, and more.</p>
<p>You can find the completed code on GitHub here:</p>
<ul>
<li><a target="_blank" href="https://github.com/helloworldless/davidagood.com/blob/55164811e2265de754940c8432c58c2bceec8e43/src/components/seo.js">SEO</a></li>
<li><a target="_blank" href="https://github.com/helloworldless/davidagood.com/blob/55164811e2265de754940c8432c58c2bceec8e43/src/templates/blog-post.js">BlogPostTemplate</a></li>
<li><a target="_blank" href="https://github.com/helloworldless/davidagood.com/blob/55164811e2265de754940c8432c58c2bceec8e43/content/blog/dynamodb-enhanced-client-java-heterogeneous-item-collections/index.md">Example post markdown</a></li>
</ul>
<p>Once you've implemented this and deployed it, you can use the <a target="_blank" href="https://cards-dev.twitter.com/validator">Twitter Card Validator</a> to test the behavior before actually tweeting a link.</p>
<p>Coincidentally, I did experience some issues with cards not being displayed in tweets even though the Validator showed that they were working. </p>
<p>In one case, I tweeted a link in a reply, and there was no card at all—just the raw link. The next day, I tweeted the same link, and this time the card worked fine! </p>
<p>In another case, I was looking at my Twitter Profile page, and several of my tweets had the cards but the image was not being displayed. So I opened a Chrome Incognito window, and in that window the images were displayed as expected.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is Open Graph and how can I use it for my website? ]]>
                </title>
                <description>
                    <![CDATA[ It can take a lot of time to build content and maintain a website. How can we make sure our content stands out when getting shared on social feeds around the internet? What is Open Graph? Why do I need it? What happens if I don’t have it? Starting w... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-open-graph-and-how-can-i-use-it-for-my-website/</link>
                <guid isPermaLink="false">66b8e39ac9bc6d235bb126b4</guid>
                
                    <category>
                        <![CDATA[ #content marketing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Digital Marketing  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                    <category>
                        <![CDATA[ marketing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ open graph ]]>
                    </category>
                
                    <category>
                        <![CDATA[ social media ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Colby Fayock ]]>
                </dc:creator>
                <pubDate>Thu, 26 Mar 2020 14:51:33 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/03/open-graph.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>It can take a lot of time to build content and maintain a website. How can we make sure our content stands out when getting shared on social feeds around the internet?</p>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-open-graph">What is Open Graph?</a></li>
<li><a class="post-section-overview" href="#heading-why-do-i-need-it">Why do I need it?</a></li>
<li><a class="post-section-overview" href="#heading-what-happens-if-i-dont-have-it">What happens if I don’t have it?</a></li>
<li><a class="post-section-overview" href="#heading-starting-with-the-basics-of-open-graph">Starting with the basics of open graph</a></li>
<li><a class="post-section-overview" href="#heading-website-open-graph-type">Website open graph type</a></li>
<li><a class="post-section-overview" href="#heading-some-other-open-graph-tags-that-are-worth-adding">Some other open graph tags that are worth adding</a></li>
<li><a class="post-section-overview" href="#heading-twitter-and-other-social-media-networks-using-open-graph">Twitter and other social media networks using open graph</a></li>
<li><a class="post-section-overview" href="#heading-images-in-open-graph">Images in open graph</a></li>
<li><a class="post-section-overview" href="#heading-testing-your-open-graph-tags">Testing your open graph tags</a></li>
<li><a class="post-section-overview" href="#heading-can-i-get-an-example">Can I get an example?</a></li>
</ul>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/QwEQKM4YRnU" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-what-is-open-graph">What is Open Graph?</h2>
<p><a target="_blank" href="https://ogp.me/">Open Graph</a> is an internet protocol that was originally created by <a target="_blank" href="http://fbdevwiki.com/wiki/Open_Graph_protocol">Facebook</a> to standardize the use of metadata within a webpage to represent the content of a page.</p>
<p>Within it, you can provide details as simple as the title of a page or as specific as the duration of a video. These pieces all fit together to form a representation of each individual page of the internet.</p>
<h2 id="heading-why-do-i-need-it">Why do I need it?</h2>
<p>Content on the internet is typically created with at least one goal in mind -- to share it with others. This might not necessarily matter if you’re just sending it to one friend, but if you want to share it or want it to be shared on any social network or app that utilizes rich previews, you’ll want that preview to be as effective as possible.</p>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/colbyfayock/status/1237455806230077441"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<p>This will help encourage people to check out your content and inevitably click through to your content.</p>
<h2 id="heading-what-happens-if-i-dont-have-it">What happens if I don’t have it?</h2>
<p>Most social networks by default will try to make their best effort in creating a preview of your content. This more often than not doesn’t go so well.</p>
<p>Take for instance my website <a target="_blank" href="https://colbyfayock.com">colbyfayock.com</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/simple-twitter-card.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Example of a simple Twitter Card</em></p>
<p>It correctly grabs the title of my page and the description, but it's not the most enticing looking tweet in a feed.</p>
<p>Contrast that to the preview of a single post and we see a different story.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/large-image-twitter-card.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Example of a Twitter Card with a large image</em></p>
<p>So what happens if you don’t have open graph tags? Nothing bad will happen, but you won’t be taking advantage of some of the features that help make your content stand out next to the loads of other content getting posted on the internet.</p>
<h2 id="heading-starting-with-the-basics-of-open-graph">Starting with the basics of open graph</h2>
<p>The four basic open graph tags that are required for each page are <code>og:title</code>, <code>og:type</code>, <code>og:image</code>, and <code>og:url</code>. These tags should be unique for each page you serve, meaning your homepage’s tags should all be different from your blog post article’s page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/open-graph-twitter-card.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Anatomy of a Twitter Card using Open Graph tags</em></p>
<p>While it should be pretty straightforward, here’s a breakdown of what each of the tags mean:</p>
<ul>
<li><code>og:title</code>: The title of your page. This is typically the same as your webpage's <code>&lt;title&gt;</code> tag unless you’d like to present it differently.</li>
<li><code>og:type</code>: The “type” of website you have. I’ll explain more in the next section, though a generic “type” is “website”.</li>
<li><code>og:image</code>: This should be a link to an image that you’d like to represent your content. It should be a high resolution image that the social networks will use in their feeds.</li>
<li><code>og:url</code>: This should be the URL of the current page.</li>
</ul>
<p>When placing a tag on your website, you should place it in the <code>&lt;head&gt;</code> along with any other metadata. The tag used will be a <code>&lt;meta&gt;</code> tag and should look like this pattern:</p>
<pre><code>&lt;meta property=“[NAME]” content=“[VALUE]” /&gt;
</code></pre><p>So if I were to create a set four basic open graph tags for my website, <a target="_blank" href="https://colbyfayock.com">colbyfayock.com</a>, it might look like:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:title"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Colby Fayock - A UX Designer <span class="hljs-symbol">&amp;amp;</span> Front-end Developer Blog"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:type"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"website"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:image"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"/static/website-social-card-44070c4a901df708aa1563ac4bbe595a.jpg"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:url"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"https://www.colbyfayock.com"</span> /&gt;</span>
</code></pre>
<h2 id="heading-website-open-graph-type">Website open graph type</h2>
<p>The open graph protocol has a few variations of the “type” of website it supports. This includes types like website, article, or video.</p>
<p>When setting up your open graph tags, you’ll want to have an idea of which type will make more sense for your website. If your page is focused on a single video, it probably makes sense to use the type “video”. If it’s a general website with no specific vertical, you would probably just want to use the type “website”.</p>
<p>Similar to the others, this is unique for each page. So if your homepage is "website,” you could always have another page of type “video”.</p>
<p>So if I were to create an open graph type for my website, it might look like the following on my homepage:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- colbyfayock.com --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">“og:type”</span> <span class="hljs-attr">content</span>=<span class="hljs-string">“profile”</span> /&gt;</span>
</code></pre>
<p>When navigating to a blog post, it would look like:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- https://www.colbyfayock.com/2020/03/anyone-can-map-inspiration-and-an-introduction-to-the-world-of-mapping/ --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">“og:type”</span> <span class="hljs-attr">content</span>=<span class="hljs-string">“article”</span> /&gt;</span>
</code></pre>
<p>You can find the most common open graph website types on the open graph webpage: <a target="_blank" href="https://ogp.me/#types">https://ogp.me/#types</a></p>
<h2 id="heading-some-other-open-graph-tags-that-are-worth-adding">Some other open graph tags that are worth adding</h2>
<p>Though you’ll generally be okay with the basics, here are a few more that would be worth adding:</p>
<ul>
<li><code>og:description</code>: A description of your page. Similarly to <code>og:title</code>, this may be the same as your website’s <code>&lt;meta type=“description”&gt;</code> tag, unless you’d like to present it differently.</li>
<li><code>og:locale</code>: If you want to localize your tags, it would probably make sense to include locale. The format is <code>language_TERRITORY</code>, where the default is <code>en_US</code>.</li>
<li><code>og:site_name</code>: The name of the overall website your content is on. If you're on a blog post page, you might have a <code>title</code> using that blog post’s title, where the <code>site_name</code> would be the name of your blog.</li>
<li><code>og:video</code>: Have a video that supports your content? Here’s a chance to include it. Add a link to your video using this tag.</li>
</ul>
<p>These tags will be added in the same pattern as before:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">“[NAME]”</span> <span class="hljs-attr">content</span>=<span class="hljs-string">“[VALUE]”</span> /&gt;</span>
</code></pre>
<h2 id="heading-twitter-and-other-social-media-networks-using-open-graph">Twitter and other social media networks using open graph</h2>
<p>Most of the social networks adhere to the basics of open graph standards, but a few of them also include their own extension to help customize the look and feel within their ecosystem.</p>
<p>Twitter for instance, allows you to specify <code>twitter:card</code>, which is the type of “card” you can use when they show your website. At this time, their card types include:</p>
<ul>
<li>summary</li>
<li>summary_large_image</li>
<li>app</li>
<li>player</li>
</ul>
<p>This will help you choose how your links are used in their feed. If you choose <code>summary_large_image</code> for instance, Twitter will show your links with big high resolution images as long as you’re providing it in the in the <code>og:image</code> tag.</p>
<p>Here are some quick references to the documentation of how to use open graph tags with some of the social media sites:</p>
<ul>
<li>Twitter: <a target="_blank" href="https://developer.twitter.com/en/docs/tweets/optimize-with-cards/guides/getting-started">https://developer.twitter.com/en/docs/tweets/optimize-with-cards/guides/getting-started</a></li>
<li>Facebook: <a target="_blank" href="https://developers.facebook.com/docs/sharing/webmasters/">https://developers.facebook.com/docs/sharing/webmasters/</a></li>
<li>Pinterest: <a target="_blank" href="https://developers.pinterest.com/docs/rich-pins/overview/">https://developers.pinterest.com/docs/rich-pins/overview/</a>?</li>
<li>LinkedIn: <a target="_blank" href="https://www.linkedin.com/help/linkedin/answer/46687/making-your-website-shareable-on-linkedin?lang=en">https://www.linkedin.com/help/linkedin/answer/46687/making-your-website-shareable-on-linkedin?lang=en</a></li>
</ul>
<h2 id="heading-images-in-open-graph">Images in open graph</h2>
<p>While adding your image as <code>og:image</code> should often be enough, sometimes it can be challenging to get your image to show up correctly. If you seem to be running into trouble, the open graph standard includes a few image tags such as <code>og:image:url</code> vs <code>og:image:secure_url</code> as well as the <code>og:image:width</code> and <code>og:image:height</code>.</p>
<p>Try to make sure you’re following all of the <a target="_blank" href="https://ogp.me/#structured">notes and examples in the open graph documentation</a>. Additionally, some of the social networks have image requirements. <a target="_blank" href="https://developer.twitter.com/en/docs/tweets/optimize-with-cards/overview/summary-card-with-large-image">Twitter for instance requires</a> a ratio of 2:1 with a minimum size of 300x157 and a maximum size of 4096x4096 that’s under 5MB and of JPG, PNG, WEBP or GIF format.</p>
<p>If you’re stuck, test your tags using the social media network’s tools to see if you can find the issue.</p>
<h2 id="heading-testing-your-open-graph-tags">Testing your open graph tags</h2>
<p>Luckily, our favorite social networks also provide tools to help us debug our tags. Once you make sure that your tags are actually showing up in the source code of your website, you’ll be able to preview how your website will look in the feed.</p>
<ul>
<li>Twitter: <a target="_blank" href="https://cards-dev.twitter.com/validator">https://cards-dev.twitter.com/validator</a></li>
<li>Facebook: <a target="_blank" href="https://developers.facebook.com/tools/debug/">https://developers.facebook.com/tools/debug/</a></li>
<li>Pinterest: <a target="_blank" href="https://developers.pinterest.com/tools/url-debugger/">https://developers.pinterest.com/tools/url-debugger/</a></li>
</ul>
<h2 id="heading-digging-further-into-open-graph-tags">Digging further into open graph tags</h2>
<p>While most of these should cover a basic website, there are a few more tags that might help you and your business’s discoverability throughout social networks. </p>
<p>If you’re interested in diving in more, <a target="_blank" href="https://ogp.me/">the documentation</a> does a great job at providing a list of all of the available tags for you to use.</p>
<p><a target="_blank" href="https://ogp.me/">https://ogp.me/</a></p>
<h2 id="heading-can-i-get-an-example">Can I get an example?</h2>
<p>If you’re simply looking for an example to get started, here’s what you should end up with when setting up your tags for <a target="_blank" href="https://www.colbyfayock.com/2020/03/anyone-can-map-inspiration-and-an-introduction-to-the-world-of-mapping/">a blog post</a>:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:site_name"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Colby Fayock"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">“og:title”</span> <span class="hljs-attr">content</span>=<span class="hljs-string">“Anyone</span> <span class="hljs-attr">Can</span> <span class="hljs-attr">Map</span>! <span class="hljs-attr">Inspiration</span> <span class="hljs-attr">and</span> <span class="hljs-attr">an</span> <span class="hljs-attr">introduction</span> <span class="hljs-attr">to</span> <span class="hljs-attr">the</span> <span class="hljs-attr">world</span> <span class="hljs-attr">of</span> <span class="hljs-attr">mapping</span> <span class="hljs-attr">-</span> <span class="hljs-attr">Colby</span> <span class="hljs-attr">Fayock</span>" /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Chef Gusteau was a visionary who created food experiences for the world to enjoy. How can we take his lessons and apply them to the world of…"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:url"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"https://www.colbyfayock.com/2020/03/anyone-can-map-inspiration-and-an-introduction-to-the-world-of-mapping/"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:type"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"article"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"article:publisher"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"https://www.colbyfayock.com"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"article:section"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Coding"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"article:tag"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Coding"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:image"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"https://res.cloudinary.com/fay/image/upload/w_1280,h_640,c_fill,q_auto,f_auto/w_860,c_fit,co_rgb:232129,g_west,x_80,y_-60,l_text:Source%20Sans%20Pro_70_line_spacing_-10_semibold:Anyone%20Can%20Map!%20Inspiration%20and%20an%20introduction%20to%20the%20world%20of%20mapping/blog-social-card-1.1"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:image:secure_url"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"https://res.cloudinary.com/fay/image/upload/w_1280,h_640,c_fill,q_auto,f_auto/w_860,c_fit,co_rgb:232129,g_west,x_80,y_-60,l_text:Source%20Sans%20Pro_70_line_spacing_-10_semibold:Anyone%20Can%20Map!%20Inspiration%20and%20an%20introduction%20to%20the%20world%20of%20mapping/blog-social-card-1.1"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:image:width"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"1280"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:image:height"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"640"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"twitter:card"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"summary_large_image"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"twitter:image"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"https://res.cloudinary.com/fay/image/upload/w_1280,h_640,c_fill,q_auto,f_auto/w_860,c_fit,co_rgb:232129,g_west,x_80,y_-60,l_text:Source%20Sans%20Pro_70_line_spacing_-10_semibold:Anyone%20Can%20Map!%20Inspiration%20and%20an%20introduction%20to%20the%20world%20of%20mapping/blog-social-card-1.1"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"twitter:site"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"@colbyfayock"</span> /&gt;</span>
</code></pre>
<h2 id="heading-looking-for-other-ways-to-optimize-and-analyze-your-content">Looking for other ways to optimize and analyze your content?</h2>
<ul>
<li><a target="_blank" href="https://www.freecodecamp.org/news/how-to-add-a-social-media-image-to-your-github-project/">How to Add a Social Media Image to Your Github Project Repository</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/making-sense-of-google-analytics-and-the-traffic-to-your-website/">How to Make Sense of Google Analytics and the Traffic to Your Website</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/how-to-set-up-and-track-youtube-channel-performance-with-google-analytics/">How to set up and track YouTube Channel performance with Google Analytics</a></li>
</ul>
<div id="colbyfayock-author-card">
  <p>
    <a href="https://twitter.com/colbyfayock">
      <img src="https://res.cloudinary.com/fay/image/upload/w_2000,h_400,c_fill,q_auto,f_auto/w_1020,c_fit,co_rgb:007079,g_north_west,x_635,y_70,l_text:Source%20Sans%20Pro_64_line_spacing_-10_bold:Colby%20Fayock/w_1020,c_fit,co_rgb:383f43,g_west,x_635,y_6,l_text:Source%20Sans%20Pro_44_line_spacing_0_normal:Follow%20me%20for%20more%20JavaScript%252c%20UX%252c%20and%20other%20interesting%20things!/w_1020,c_fit,co_rgb:007079,g_south_west,x_635,y_70,l_text:Source%20Sans%20Pro_40_line_spacing_-10_semibold:colbyfayock.com/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_68,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_145,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_222,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_295,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/v1/social-footer-card" alt="Follow me for more Javascript, UX, and other interesting things!" width="2000" height="400" loading="lazy">
    </a>
  </p>
  <ul>
    <li>
      <a href="https://twitter.com/colbyfayock">? Follow Me On Twitter</a>
    </li>
    <li>
      <a href="https://youtube.com/colbyfayock">?️ Subscribe To My Youtube</a>
    </li>
    <li>
      <a href="https://www.colbyfayock.com/newsletter/">✉️ Sign Up For My Newsletter</a>
    </li>
  </ul>
</div>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
