<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Pikzor</title>
    <description>The latest articles on DEV Community by Pikzor (@pikzor).</description>
    <link>https://dev.to/pikzor</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3870754%2F362f619e-4673-4812-b781-c7a071f3f6df.png</url>
      <title>DEV Community: Pikzor</title>
      <link>https://dev.to/pikzor</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pikzor"/>
    <language>en</language>
    <item>
      <title>Why Your Link Preview Looks Ugly on Twitter (And How to Fix It)</title>
      <dc:creator>Pikzor</dc:creator>
      <pubDate>Fri, 10 Apr 2026 01:57:47 +0000</pubDate>
      <link>https://dev.to/pikzor/why-your-link-preview-looks-ugly-on-twitter-and-how-to-fix-it-50p</link>
      <guid>https://dev.to/pikzor/why-your-link-preview-looks-ugly-on-twitter-and-how-to-fix-it-50p</guid>
      <description>&lt;p&gt;You just published a blog post you're proud of. You share it on Twitter. And then you see it — a tiny logo, no description, or worse, a completely blank card with just the URL. Meanwhile, every other link in your feed has a clean, full-width preview image with a title and description.&lt;/p&gt;

&lt;p&gt;What went wrong?&lt;/p&gt;

&lt;p&gt;The answer is almost always one of five things. Let's go through each one and fix it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Twitter link previews actually work
&lt;/h2&gt;

&lt;p&gt;When you paste a URL into a tweet, Twitter sends a bot (called "Twitterbot") to crawl your page. This bot reads your HTML and looks for specific meta tags called Open Graph tags and Twitter Card tags. These tags tell Twitter: "Here's the title to display, here's the description, and here's the image."&lt;/p&gt;

&lt;p&gt;If the bot can't find these tags, or finds them but something is wrong, your link preview either looks broken or doesn't show up at all.&lt;/p&gt;

&lt;p&gt;Here's what a properly configured set of tags looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Open Graph tags (used by LinkedIn, Facebook, Slack, Discord) --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Your Page Title"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"A short description of what this page is about."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yoursite.com/images/og-card.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image:width"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"1200"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image:height"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"630"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:url"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yoursite.com/your-page"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- Twitter-specific tags --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:card"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"summary_large_image"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Your Page Title"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"A short description of what this page is about."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yoursite.com/images/og-card.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If any of these are missing or misconfigured, things break. Here are the five most common reasons.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 1: You have no og:image tag at all
&lt;/h2&gt;

&lt;p&gt;This is the most common issue. You wrote a blog post, hit publish, and never added an OG image meta tag. Twitter has nothing to show, so you get either a blank card or a tiny link with just text.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add an og:image meta tag pointing to an image URL. At minimum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yoursite.com/images/my-image.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yoursite.com/images/my-image.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're using WordPress, install the Yoast SEO plugin or RankMath — both let you set OG images through the editor without touching code.&lt;/p&gt;

&lt;p&gt;If you're using a static site generator like Next.js, Astro, or Hugo, you'll need to add these tags to your page template or layout file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 2: Your image is too small
&lt;/h2&gt;

&lt;p&gt;Twitter has minimum size requirements for the large card preview. If your image is smaller than 300x157 pixels, Twitter may not show it at all. If it's between 300px and 600px wide, Twitter will show a small thumbnail instead of the full-width card.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use an image that is exactly &lt;strong&gt;1200 x 630 pixels&lt;/strong&gt;. This is the standard OG image size that works across all platforms — Twitter, LinkedIn, Facebook, Discord, Slack, and WhatsApp.&lt;/p&gt;

&lt;p&gt;Also include the width and height meta tags — some platforms use these to pre-allocate space for the image before it loads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yoursite.com/images/og-card.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image:width"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"1200"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image:height"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"630"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Problem 3: You're missing the twitter:card tag
&lt;/h2&gt;

&lt;p&gt;This is the sneaky one. You might have og:image set up perfectly, but your Twitter preview still shows a tiny square thumbnail instead of a big full-width card.&lt;/p&gt;

&lt;p&gt;The reason: Twitter defaults to &lt;code&gt;summary&lt;/code&gt; card type, which shows a small square image on the left with text on the right. To get the big, beautiful full-width preview, you need to explicitly set the card type to &lt;code&gt;summary_large_image&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:card"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"summary_large_image"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That single line is the difference between this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[tiny square] Title
              Description
              yoursite.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────┐
│      [BIG FULL-WIDTH IMAGE]     │
├─────────────────────────────────┤
│ Title                           │
│ Description                     │
│ yoursite.com                    │
└─────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always use &lt;code&gt;summary_large_image&lt;/code&gt;. There's virtually no reason to use the small card format.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 4: You're using a relative URL instead of an absolute URL
&lt;/h2&gt;

&lt;p&gt;This one trips up a lot of developers. Your OG image tag looks fine in your code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- This DOES NOT work --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"/images/og-card.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But Twitter's bot sees &lt;code&gt;/images/og-card.png&lt;/code&gt; and has no idea what domain that belongs to. It can't resolve it, so no image shows up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Always use the full, absolute URL starting with &lt;code&gt;https://&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- This works --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yoursite.com/images/og-card.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're building the URL dynamically in JavaScript or a framework, make sure you're prepending your domain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Wrong&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ogImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`/images/og/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.png`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Right&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ogImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://yoursite.com/images/og/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.png`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is especially common in Next.js and Astro projects where developers forget to add the &lt;code&gt;NEXT_PUBLIC_SITE_URL&lt;/code&gt; or equivalent base URL to their image paths.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 5: Twitter is showing a cached old version
&lt;/h2&gt;

&lt;p&gt;You fixed all the tags, tested locally, everything looks perfect. But when you share the link on Twitter, it still shows the old broken preview.&lt;/p&gt;

&lt;p&gt;This happens because Twitter aggressively caches link previews. Once it crawls your page and stores the preview, it doesn't re-crawl for a while — sometimes hours, sometimes days.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Force Twitter to re-crawl your page using the Twitter Card Validator:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;cards-dev.twitter.com/validator&lt;/strong&gt; (or search "Twitter Card Validator")&lt;/li&gt;
&lt;li&gt;Paste your URL&lt;/li&gt;
&lt;li&gt;Click "Preview card"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This forces Twitter to fetch the page fresh and update its cache. You should see your new preview image appear immediately. If it still shows the old version, wait 5 minutes and try again.&lt;/p&gt;

&lt;p&gt;For Facebook and LinkedIn, they have their own cache-clearing tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Facebook&lt;/strong&gt;: developers.facebook.com/tools/debug — paste your URL, click "Scrape Again"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LinkedIn&lt;/strong&gt;: linkedin.com/post-inspector — paste your URL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pro tip: if you're actively developing and testing OG images, add a cache-busting query parameter to your image URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yoursite.com/images/og-card.png?v=2"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change &lt;code&gt;v=2&lt;/code&gt; to &lt;code&gt;v=3&lt;/code&gt; each time you update the image. This forces every platform to treat it as a new URL and fetch the fresh version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick debugging checklist
&lt;/h2&gt;

&lt;p&gt;Before you share any important link, run through this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Open your page in a browser and view the page source (Ctrl+U or Cmd+U). Search for &lt;code&gt;og:image&lt;/code&gt;. Is it there? Is it an absolute URL?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open the og:image URL directly in your browser. Does the image load? Is it the right image?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Is the image at least 1200x630? Check the dimensions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do you have &lt;code&gt;twitter:card&lt;/code&gt; set to &lt;code&gt;summary_large_image&lt;/code&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run the URL through a debugger tool. Try opengraph.xyz — it shows all your OG tags in one place and flags issues.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can also check from the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://yoursite.com/your-page | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"og:image&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;twitter:image&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;twitter:card"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shows you exactly what the crawlers will see.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lazy way to fix all of this
&lt;/h2&gt;

&lt;p&gt;If you have a site with dozens or hundreds of pages and you don't want to manually create and maintain OG images for each one, tools like &lt;a href="https://pikzor.com" rel="noopener noreferrer"&gt;Pikzor&lt;/a&gt; generate dynamic OG images automatically — you pick a template, drop one URL into your meta tag, and every page gets a unique preview card.&lt;/p&gt;

&lt;p&gt;Whatever you do, don't leave your links looking broken. Every time someone shares your content with a missing or ugly preview, you're losing clicks. It takes 5 minutes to fix, and once it's set up, you never have to think about it again.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>twitter</category>
      <category>seo</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to Add Dynamic OG Images to Any Website in 5 Minutes</title>
      <dc:creator>Pikzor</dc:creator>
      <pubDate>Fri, 10 Apr 2026 01:55:36 +0000</pubDate>
      <link>https://dev.to/pikzor/how-to-add-dynamic-og-images-to-any-website-in-5-minutes-1oih</link>
      <guid>https://dev.to/pikzor/how-to-add-dynamic-og-images-to-any-website-in-5-minutes-1oih</guid>
      <description>&lt;p&gt;Ever shared a link on Twitter and watched it show up as a sad little URL with no preview? Or worse — a tiny stretched logo that makes your site look like it was built in 2004?&lt;/p&gt;

&lt;p&gt;That preview card you see when someone shares a link — the one with the image, title, and description — is controlled by something called an Open Graph image (or OG image). And if you're not setting it up properly, you're leaving clicks on the table.&lt;/p&gt;

&lt;p&gt;Let's fix that in 5 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's an OG image, exactly?
&lt;/h2&gt;

&lt;p&gt;When you paste a URL into Twitter, LinkedIn, Slack, Discord, or pretty much any messaging app, the platform crawls your page and looks for specific HTML meta tags. These tags tell the platform: "Here's the title. Here's the description. And here's the image to show."&lt;/p&gt;

&lt;p&gt;That image is your OG image. It's the first thing people see before deciding whether to click your link.&lt;/p&gt;

&lt;p&gt;A good OG image can be the difference between someone scrolling past your link and actually clicking it. Think about your own behavior — when you see a link with a clean, branded preview card versus one with a gray box or a pixelated logo, which one are you more likely to click?&lt;/p&gt;

&lt;h2&gt;
  
  
  The meta tags you need
&lt;/h2&gt;

&lt;p&gt;Open Graph images work through HTML meta tags in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; section of your page. Here's the minimum set you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"How We Grew to 10K Users in 6 Months"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"The exact playbook we used to go from zero to 10,000 users without spending a dollar on ads."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yoursite.com/images/og-grow-10k.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image:width"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"1200"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image:height"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"630"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:url"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yoursite.com/blog/grow-to-10k"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:type"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"article"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Twitter specifically, you also want these:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:card"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"summary_large_image"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"How We Grew to 10K Users in 6 Months"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"The exact playbook we used..."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yoursite.com/images/og-grow-10k.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;summary_large_image&lt;/code&gt; card type is what gives you that big, full-width preview image on Twitter instead of a tiny square thumbnail.&lt;/p&gt;

&lt;h2&gt;
  
  
  What size should your OG image be?
&lt;/h2&gt;

&lt;p&gt;The recommended size is &lt;strong&gt;1200 x 630 pixels&lt;/strong&gt; with a 1.91:1 aspect ratio. This works well across all major platforms: Twitter, LinkedIn, Facebook, Discord, Slack, and WhatsApp.&lt;/p&gt;

&lt;p&gt;A few things to keep in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use PNG or JPG format. PNG looks sharper, JPG has smaller file sizes.&lt;/li&gt;
&lt;li&gt;Keep important text and visuals away from the edges — some platforms crop slightly.&lt;/li&gt;
&lt;li&gt;Keep the file size under 1MB. Large images load slowly and some platforms will skip them entirely.&lt;/li&gt;
&lt;li&gt;Always use absolute URLs (starting with &lt;code&gt;https://&lt;/code&gt;) for the image path, not relative ones. Relative URLs are the number one reason OG images don't show up.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Three ways to add OG images to your site
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Approach 1: One static image for your entire site
&lt;/h3&gt;

&lt;p&gt;This is the simplest approach. You create one OG image — usually your logo on a branded background — and use it everywhere.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yoursite.com/images/default-og.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt; Takes 2 minutes. Better than having no image at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt; Every page on your site shares the same preview image. When someone shares your blog post about pricing strategies, it looks identical to someone sharing your about page. People can't tell what the link is about from the preview.&lt;/p&gt;

&lt;p&gt;This approach works for a personal portfolio or a simple landing page. For anything with multiple pages of content, you want something better.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach 2: Manually design an image for each page
&lt;/h3&gt;

&lt;p&gt;Open Canva or Figma, create a 1200x630 image with the blog post title, your branding, maybe an icon. Save it. Upload it. Reference it in the meta tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- blog/grow-to-10k.html --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yoursite.com/images/og/grow-to-10k.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- blog/pricing-strategy.html --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yoursite.com/images/og/pricing-strategy.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt; Each page gets a unique, polished preview image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt; It takes 10-15 minutes per image. If you have 50 blog posts, that's 8+ hours of design work. Nobody maintains this consistently. You'll do it for the first 5 posts and then stop.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach 3: Dynamic OG images via URL (the smart way)
&lt;/h3&gt;

&lt;p&gt;Instead of creating images manually, you use a service that generates them on-the-fly from a URL. You pass your title, author, and brand color as URL parameters, and the service returns a PNG image.&lt;/p&gt;

&lt;p&gt;The concept is simple. Instead of pointing your meta tag at a static file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yoursite.com/images/og/some-file.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You point it at a URL that generates the image dynamically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://pikzor.com/og?title=How+We+Grew+to+10K+Users&amp;amp;author=Sarah+Chen&amp;amp;theme=dark"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When Twitter or LinkedIn hits that URL, the service renders a beautiful card image with your title and branding, and returns the PNG. The image is cached, so subsequent requests are instant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt; Zero manual work per page. Every page gets a unique image. Add a new blog post and the OG image exists automatically. Change your branding once and all images update.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt; You depend on an external service (or need to host your own rendering engine).&lt;/p&gt;

&lt;h2&gt;
  
  
  How to implement dynamic OG images
&lt;/h2&gt;

&lt;h3&gt;
  
  
  In plain HTML
&lt;/h3&gt;

&lt;p&gt;If you have a static HTML site, you set the meta tag manually per page — but the image URL is dynamic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; 
    &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://pikzor.com/og?title=My+Blog+Post&amp;amp;author=John&amp;amp;color=3B82F6"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image:width"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"1200"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image:height"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"630"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:card"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"summary_large_image"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:image"&lt;/span&gt; 
    &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://pikzor.com/og?title=My+Blog+Post&amp;amp;author=John&amp;amp;color=3B82F6"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  In Next.js (App Router)
&lt;/h3&gt;

&lt;p&gt;With Next.js, you can set OG images dynamically using the metadata export in your page or layout files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/blog/[slug]/page.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateMetadata&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ogImageUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://pikzor.com/og?&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3B82F6&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;})}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;excerpt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;openGraph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;excerpt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ogImageUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;630&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;card&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;summary_large_image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;excerpt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ogImageUrl&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This generates a unique OG image URL for every blog post automatically. When you publish a new post, the OG image just works — no extra steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  In any JavaScript framework
&lt;/h3&gt;

&lt;p&gt;If you're using Astro, Nuxt, SvelteKit, or any other framework, the pattern is the same. Build the URL with your dynamic data and inject it into the head:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Generic approach — works anywhere&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getOGImageUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3B82F6&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`https://pikzor.com/og?&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Use it in your template/layout&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ogImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getOGImageUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Then inject into &amp;lt;meta property="og:image" content="${ogImage}" /&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to test your OG images
&lt;/h2&gt;

&lt;p&gt;After adding the meta tags, you need to verify they work. Social platforms cache aggressively, so if your old preview was broken, you need to force a refresh.&lt;/p&gt;

&lt;p&gt;Use these free debuggers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Twitter Card Validator&lt;/strong&gt;: cards-dev.twitter.com/validator — paste your URL, see the preview&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Facebook Sharing Debugger&lt;/strong&gt;: developers.facebook.com/tools/debug — paste your URL, click "Scrape Again" to refresh the cache&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LinkedIn Post Inspector&lt;/strong&gt;: linkedin.com/post-inspector — paste your URL, see the preview&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;opengraph.xyz&lt;/strong&gt;: paste any URL and see all OG tags at once&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Common issues to check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the og:image URL an absolute URL (starts with https://)?&lt;/li&gt;
&lt;li&gt;Is the image actually accessible? Try opening the URL directly in your browser.&lt;/li&gt;
&lt;li&gt;Is the image at least 1200x630? Smaller images may show as tiny thumbnails or not at all.&lt;/li&gt;
&lt;li&gt;Did you include &lt;code&gt;twitter:card&lt;/code&gt; set to &lt;code&gt;summary_large_image&lt;/code&gt;? Without this, Twitter shows a tiny square instead of a large card.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stop wasting time designing OG images
&lt;/h2&gt;

&lt;p&gt;If you don't want to deal with building your own rendering pipeline, tools like &lt;a href="https://pikzor.com" rel="noopener noreferrer"&gt;Pikzor&lt;/a&gt; let you generate dynamic OG images by just picking a template and dropping a URL into your meta tags — no design work, no API code, done in 2 minutes.&lt;/p&gt;

&lt;p&gt;Whatever approach you pick, just make sure every page on your site has an OG image. Your links will get more clicks, your content will look more professional, and you'll never have to stare at that ugly gray box again.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
      <category>tutorial</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
