DEV Community

Jakub Švehla
Jakub Švehla

Posted on

Automated link preview images with Python & Flask

In this post, I will show you how to generate link preview images for your blog posts so that they look good when you share them on social media.

Below, you can see how it's gonna look like:

twitter-card-screenshot

We will create a simple Flask endpoint that will accept a URL and return a generated image based on the website's metadata.

So let's get to work.

Prepare a Jinja2 template for an HTML version of your card

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{{ title }}</title>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
    <style>
      @page {
        size: 1200px 628px;
        margin: 0;
        padding: 0;
      }

      html {
        font-size: 137.5%;
        -webkit-font-smoothing: antialiased;
      }

      body {
        padding: 3rem;
        font-family: 'Inter', sans-serif;
        color: #111111;
        background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='18' viewBox='0 0 100 18'%3E%3Cpath fill='%231c64f2' fill-opacity='0.05' d='M61.82 18c3.47-1.45 6.86-3.78 11.3-7.34C78 6.76 80.34 5.1 83.87 3.42 88.56 1.16 93.75 0 100 0v6.16C98.76 6.05 97.43 6 96 6c-9.59 0-14.23 2.23-23.13 9.34-1.28 1.03-2.39 1.9-3.4 2.66h-7.65zm-23.64 0H22.52c-1-.76-2.1-1.63-3.4-2.66C11.57 9.3 7.08 6.78 0 6.16V0c6.25 0 11.44 1.16 16.14 3.42 3.53 1.7 5.87 3.35 10.73 7.24 4.45 3.56 7.84 5.9 11.31 7.34zM61.82 0h7.66a39.57 39.57 0 0 1-7.34 4.58C57.44 6.84 52.25 8 46 8S34.56 6.84 29.86 4.58A39.57 39.57 0 0 1 22.52 0h15.66C41.65 1.44 45.21 2 50 2c4.8 0 8.35-.56 11.82-2z'%3E%3C/path%3E%3C/svg%3E");
      }

      h1 {
        font-size: 3.052rem;
        margin-top: 0;
      }

      p {
        font-size: 1.563rem;
        line-height: 1.5;
      }
    </style>
  </head>

  <body>
    <h1>{{ title }}</h1>
    <p>{{ excerpt }}</p>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Create a Flask endpoint that will generate the preview image

import io
import requests
from lxml import etree

@app.route('/preview.png')
def preview():
    # Fetch the URL
    page_html = requests.get(request.args['url']).text

    # Parse the HTML response
    parser = etree.HTMLParser()
    tree = etree.parse(io.StringIO(page_html), parser)

    # Get the website's title and description from its metadata
    head = tree.xpath('/html/head')[0]
    title = head.xpath('meta[@property="og:title"]/@content')[0]
    description = head.xpath('meta[@property="og:description"]/@content')[0]

    # Render the HTML version of the preview
    preview_html = render_template('card.html', title=title, excerpt=description)

    # Use weasyprint to convert the HTML preview to PNG
    preview_img = weasyprint.HTML(string=preview_html).write_png(resolution=2 * 96)

    return Response(preview_img, mimetype='image/png')
Enter fullscreen mode Exit fullscreen mode

Below are the steps one by one:

  1. fetch the URL,
  2. parse the HTML response,
  3. get the website's title and description from its metadata,
  4. render the HTML version of the preview,
  5. use weasyprint to convert the HTML preview to PNG,
  6. and return the generated image.

And that's it! Now you can use the endpoint in your website metadata so that it looks good when shared on social media:

<meta property="og:image" content="https://YOUR_DOMAIN/preview.png?url=YOUR_URL"/>
Enter fullscreen mode Exit fullscreen mode

Latest comments (2)

Collapse
 
antoniovmonge profile image
Antonio V Monge

Usign metatags.io/ (free tool) you generate the metatags you need to paste in the

of your website.
It is a 3 minuntes solution. Meta Tags — Preview, Edit and Generate

Collapse
 
ssakhavi profile image
Siavash Sakhavi

I was looking for this so badly. Thanks for the share