00%
blog.info()
← Back to Home
SEQUENCE // Building The Blog

I Built a Selfie Engine for my Go Blog

Author Thorn Hall
0

I was thinking to myself, "I want more page views. How can I write backend code to potentially improve my article click rate?" That's when it occurred to me that the social preview image being the same for every article is kind of boring. What if the social preview was a preview of the web page itself? Is there a way to make this automated?

This sounded like a solid idea, but I needed to integrate it carefully to avoid slowing down the application. The key was in finding the right place in my architecture to handle the image generation.

The Solution

To understand the solution, we need to understand how my app works (don't worry, I won't go into too much detail. Let's keep it high level for now.)

My app has two phases:

  • The build phase: my Go application builds static HTML files for the Go server to use
  • The runtime phase: the Go server, also within the application code, starts and listens for requests on the internet, serving those files to you

To support automated social previews, I need to modify the build phase. Specifically, we need to modify the build phase to also generate the static preview images. How do we do this?

The Static Previews

I decided that the static preview would be a reflection of the actual page content. Therefore, taking a screenshot of the heading made sense. There are a couple of problems with this approach:

  • Social previews are required to be 1200 by 630 pixels. If I simply took a screenshot of the article page, the text would be too small to read when shared on Twitter or LinkedIn. Plus, the navigation bar and sidebar would clutter the image.
  • Doing this manually would be annoying. I'd have to take a screenshot and resize the image, manually saving them to the correct directory.

I needed an automated way to render a simplified version of the header that was optimized for social media cards.

To solve this, I created a hidden HTML template. This template is never shown to actual human visitors. It is a stripped-down version of my site design that uses my specific fonts and colors, but with massive text and a fixed aspect ratio.

The Photographer

This is where the Go script comes in. I wrote a small generator tool that runs during the build process. It performs a few clever steps:

  • It spins up a temporary local web server
  • It renders the hidden template for every article in my database
  • It uses a library called Chromedp to launch a headless browser
  • The browser visits the local server, takes a screenshot of the template, and saves it as a PNG file
  • Once the images are generated, the temporary server shuts down and the images are moved into the public assets folder.

The Result

I integrated this into my GitHub Actions pipeline. Now, whenever I push a new article to the repository, the automation kicks in. It builds the application binary and generates a fresh set of social preview images in parallel.

The result is that I get custom, perfectly branded social cards for every post without paying for an external image service or doing it manually. It effectively works as a selfie engine for my blog, ensuring it always looks good when shared.

View Abstract Syntax Tree (Build-Time Generated)
Document
Paragraph
Text "I was thinking to myself, "..."
Text " automated?"
Paragraph
Text "This sounded like a solid i..."
Text " generation."
Heading
Text "The"
Text " Solution"
Paragraph
Text "To understand the solution,..."
Text " now.)"
Paragraph
Text "My app has two"
Text " phases:"
List
ListItem
TextBlock
Text "The build phase: my Go appl..."
Text " use"
ListItem
TextBlock
Text "The runtime phase: the Go s..."
Text " you"
Paragraph
Text "To support automated social..."
Text " this?"
Heading
Text "The Static"
Text " Previews"
Paragraph
Text "I decided that the static p..."
Text " approach:"
List
ListItem
TextBlock
Text "Social previews are require..."
Text " image."
ListItem
TextBlock
Text "Doing this manually would b..."
Text " directory."
Paragraph
Text "I needed an automated way t..."
Text " cards."
Paragraph
Text "To solve this, I created a ..."
Text " ratio."
Heading
Text "The"
Text " Photographer"
Paragraph
Text "This is where the Go script..."
Text " steps:"
List
ListItem
TextBlock
Text "It spins up a temporary loc..."
Text " server"
ListItem
TextBlock
Text "It renders the hidden templ..."
Text " database"
ListItem
TextBlock
Text "It uses a library called Ch..."
Text " browser"
ListItem
TextBlock
Text "The browser visits the loca..."
Text " file"
ListItem
TextBlock
Text "Once the images are generat..."
Text " folder."
Heading
Text "The"
Text " Result"
Paragraph
Text "I integrated this into my G..."
Text " parallel."
Paragraph
Text "The result is that I get cu..."
Text " shared."