I Built a Selfie Engine for my Go Blog
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.