Mike Coutermarsh
Posted on March 10, 2019
Ever wonder how trendy websites like Product Hunt or Medium generate those fancy Twitter screenshots?
Wonder no more!
Essentially, they render the HTML/CSS in a headless Chrome instance and take a screenshot. Sound complicated? Yes, it is. Especially "at scale."
Good thing there are API's for this.
I will show you how to do this with an API I built specifically for this purpose: HTML/CSS to Image API.
require "httparty"
auth = { username: 'user_id', password: 'api_key' }
html = "<div class=\"box\"><h3>Hello, world 😍</h3></div>"
css = ".box {
border: 4px solid #8FB3E7;
padding: 20px;
color: white;
font-size: 100px;
width: 800px;
height: 400px;
font-family: 'Roboto';
background-color: #8BC6EC;
background-image: linear-gradient(135deg, #8BC6EC 0%, #9599E2 100%);
}"
image = HTTParty.post("https://hcti.io/v1/image",
body: { html: html, css: css },
basic_auth: auth)
# { url: https://hcti.io/v1/image/bfae7d68-86cc-4934-83ac-af3ba75a0d34 }
Done. We have an image ✨.
Rails + Caching
If you're creating these from Rails and already use memcached, here's a nice trick for ensuring you only create them once.
cache_key = "image/#{html}/#{css}"
image = Rails.cache.fetch(cache_key) do
HTTParty.post("https://hcti.io/v1/image",
body: { html: html, css: css },
basic_auth: auth)
end
We use the html/css to generate the cache key. Don't worry about it being too long. Rails/Dalli automatically hashes the key for you, guaranteeing it will be unique and the correct length.
This way, if you send the exact same payload again, Rails will pull the URL from cache rather than regenerating it.
Another Rails tip
If you're generating these for all of your content, it may be temping to stick the API call into an after_create
. I advise against that. It's always best to keep I/O to an absolute minimum when "in request". Even though the request may only take 30ms, that can add up if the endpoint is already doing a lot.
The solution, is using a background job.
So instead of making the call directly in an after_create
. You can instead enqueue the background job using after_create
. Then the image will be generated in the background. Keeping your Rails response times super quick.
Build something cool?
If you build something cool this, let me know so I can tweet it!!
Posted on March 10, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.