Scale Your Marketing

Using Bannerbear in a Batch Generation Process

Jon Yongfook · June 2020


Need to batch-generate lots of social media images for a website you run? Here's an example of using Bannerbear in a command-line script that you can run anytime.

A common use-case for Bannerbear is generating bespoke og:image and twitter card images for every page on your website. When automated, this is a simple and zero maintenance way to drive more traffic to your pages from social media.

There are various ways to implement this in your projects using Bannerbear. Since Bannerbear is a REST API, one popular method is employing an event-driven approach, pinging Bannerbear whenever your platform generates new content.

But another method would be a batch approach, where you auto generate images in large batches at once and save them to your own filesystem.

Advantages of Batch Generation

  • Zero brittleness as the images are pre-generated
  • Simple to manage expiry / regeneration; just delete the images and rerun the script
  • Keeps image generation code separate from your core

Disadvantages of Batch Generation

  • You have to "remember" to run the script*
  • Less suitable when there is new content being published constantly

*could easily be automated though!

Batch generation is ideal for sites that are built via a static site generator where you want static image assets and no code running on-the-fly.

The Bannerbear marketing site (this website) is run on a static site generator called Middleman and all the social media og:image files are generated by batch using a Rakefile. Whenever I add new content to the site I simply run:

rake bannerbear:generate

Which runs the following process:

  • Fetch a json feed of all pages of the site
  • Then, for each pageā€¦
  • Checks for a pre-existing og:image in a specified folder
  • If the image file already exists, move on
  • If the image file doesn't exist, send a request to Bannerbear
  • Wait for the image to get generated, then save it to the specified folder
  • Move to the next page in the json feed

And that's it! This is written in Ruby since that's what I know best, but you could write something similar to this in any programming language :)

View this Gist on Github

require 'httparty'
require 'open-uri'

namespace :bannerbear do
  task :generate do
    puts "Starting json request"
    response = HTTParty.get(ENV['LOCAL_BB_SITE_ALL_POSTS'])
      json = JSON.parse response.body
      puts "Number of pages: #{json.size}"
      json.each_with_index do |page,i|
        puts "#{i} ---------------------------------------"
        puts "Checking file exists for"
        path = './source/images/opengraph/' + page['filename']
        puts path
        if !File.file?(path)
          puts "File doesn't exist, lets create!"
          general_template_id = ENV['BB_SITE_GENERAL_OG_TEMPLATE']
          blog_template_id = ENV['BB_SITE_BLOG_OG_TEMPLATE']
          template = general_template_id
          mods = [
              :name => "title",
              :text => page['title']
          if page['blog_date']
            template = blog_template_id
            mods = [
                :name => "title",
                :text => page['title']
                :name => "date",
                :text => page['blog_date']
          payload = {
            :template => template,
            :modifications => mods,
          puts "Creating Bannerbear API request"
          puts payload
          response ="", {
            body: payload,
            headers: {"Authorization" => "Bearer #{ENV['BANNERBEAR_SOCIAL_MEDIA_PROJECT_API_KEY']}"}
          image_json = JSON.parse response.body
          counter = 1
          #poll for image to complete
          5.times do |attempt|
            puts "Attempt #{attempt}"
            counter = counter+1
            response = HTTParty.get(image_json['self'], {
              headers: {"Authorization" => "Bearer #{ENV['BANNERBEAR_SOCIAL_MEDIA_PROJECT_API_KEY']}"}
            image_json = JSON.parse response.body
            if image_json['image_url_png']
              puts "Image generated!"
              puts image_json['image_url_png']
              download = open(image_json['image_url_png'])
              IO.copy_stream(download, path)
            sleep 1
        puts "Moving to next page..."
    rescue => e
      puts "Rescued #{e.inspect}"

View this Gist on Github

Tags for this article

Jon Yongfook@yongfook

Jon is the founder of Bannerbear. He has worked as a designer and programmer for 20 years and is fascinated by the role of technology in design automation.

Follow the Journey

Hello I'm Jon, the founder of Bannerbear — every 2 weeks I send a newsletter with updates from the Product, Marketing and Business sides of my startup, subscribe below to receive it!