Rails developers often need to take screenshots within their programs for a variety of reasons.
If you're a Rails developer, you may find yourself taking screenshots to:
- Show a bug that's occurring during automated testing
- Programmatically grab screenshots from a URL instead of asking your users to upload potentially inconsistent files
- Track changes on your competitor’s pricing and landing pages
- Ensure your i18n translations look great when accessed from their respective countries
- And more...
Fortunately, there are a few gems and tools to make this very easy in Rails applications.
In this blog post, we’ll show you 4 different ways to take website screenshots using Rails. So whether you're a beginner or an experienced developer looking to integrate screenshots into your next app, read on for some tips and tricks!
4 Ways to Take Screenshots Programmatically with Rails
In this article, we'll cover 4 of the most popular ways to take screenshots programmatically. In our examples, we'll create a simple app that lets a user fill out a text box with a URL of their choice and click a button to retrieve and view the screenshot.
We'll be using Rails 7 throughout this article. However, these examples should work for older versions of Rails as well. We'll cover the following options:
- Puppeteer & Grover
- Cloudinary + URL2png
- html2canvas
- Urlbox
First up, Puppeteer & Grover...
Puppeteer & Grover
Puppeteer is an API that allows a user to control Chrome or Chromium in either headless or full (non-headless) mode. It’s a versatile package with many features and is commonly used to take screenshots.
To best use Puppeteer with Rails, there’s a handy gem built on top of Puppeteer called Grover. Grover makes it easy to call a .to_pdf
type method to create a screenshot in the format of your choosing.
Basic set-up and configuration
Let’s set up the project by firing up a new Rails app and moving into our new app. In the terminal, we'll add the following command:
rails new puppeteer && cd puppeteer
Next, we’ll need to install Puppeteer and Grover to take screenshots. In your gemfile, add the following line:
gem grover
Then go ahead and run bundle install
.
We'll also want to get Puppeteer installed, so type yarn add puppeteer
into your terminal to set up your project with Puppeteer.
Adding a route and creating our view
That's it for the configuration work. Our next step is to create a basic view where we'll be able to see our text field and button. First up, we'll add a default route so we can see our form as soon as we fire up our server. In your routes.rb
file, add root "screenshot#show"
before the last end tag.
Before we load our page, we'll want to make sure that we have something to show our visitors. In the app/views/
folder, screen a folder called screenshot
and inside it, add a file called show.html.erb
.
Inside this show view, we'll add a form to capture a URL.
This form will submit to the show method in our soon to be created screenshot_controller file.
Then, if Puppeteer comes back with an image, we'll display it in an image tag.
Setting up the controller
Now that we have a show view, we'll need a controller action for it. In app/controllers/
create a file called screenshot_controller.rb
. Inside that file, drop the following code:
This code will take the URL the user entered in the form (if it exists) and convert it into a .png with Grover. @image
will give us a PNG data file that we'll then take and display in the view.
Go ahead and start your rails server
, enter in the URL of a site you want to screenshot, click the button, and watch as it appears in the view. Pretty cool, huh?
If you want to customize your configuration further, you can update an initializer file with the options you prefer.
To produce the image above, ours is set to the following:
Benefits and Drawbacks of Using Puppeteer for Screenshots
The advantage of Puppeteer is that it is well maintained and has plenty of options to customize your screenshots with - for example, color blindness simulation, PDF support, setting locations, and disabling javascript.
However, because it is so versatile, it’s easy to get lost in the amount of features and options you can choose from. Plus, If you’re going to be taking lots of screenshots, you may need to maintain your own cluster which can increase the number of systems you’ll need to spin up and maintain.
Cloudinary + URL2png
Cloudinary is a fantastic service for storing and serving media files. They also integrate with a screenshot service called URL2png to make taking screenshots easy.
For this example, we'll need to do a bit more setup than Puppeteer.
- You'll first need to sign up for a Cloudinary account.
- Once you have your account set up, you'll need to register for the URL2png add-on through their website.
One important thing to note is that URL2png does not offer free versions on their homepage, but with a Cloudinary account, you can get up to 50 free screenshots.
Basic set up and confirmation
Before we get into installing the gem, let's first get a fresh Rails app started by typing the following into the terminal:
rails new cloudinary && cd cloudinary
In your gemfile, add the following line:
gem cloudinary
Once it's in your gem file, run bundle install
.
In order to access Cloudinary through its API, you'll also need a way to send Cloudinary your API key and secret. When you're logged in to the Cloudinary application, you can download your cloudinary.yml file at https://cloudinary.com/console/cloudinary.yml & add it to your config folder. Beware! This file contains secrets so if you’re following these steps for a production app, please replace your keys with a reference to the credential file where you’ll keep them safe!
Views, controllers, and route
Similar to Puppeteer above, we'll now set up a basic route, view, and controller action. We'll create a root route in routes.rb
file by adding root "screenshot#show"
before the last end tag.
Then, in the app/views/
folder, screen a folder called screenshot
and inside it, add a file called show.html.erb
and add the following code to it:
That's it for the view. To be able to access that view with the route we've created, we'll need to go to app/controllers/
and create a file called screenshot_controller.rb
. Inside that file, drop the following code:
Start your Rails server with rails s
and you should be able to enter a url and get a screenshot of it.
Benefits and Drawbacks of Using Cloudinary & URL2png for Screenshots
We'd recommend the Cloudinary + URL2png option if you already use Cloudinary and need a handful of screenshots or want to take advantage of the many image transformations Cloudinary offers.
However, you'll need to manage multiple accounts and, if you want to take more than 50 screenshots, will need to sign up for a plan with URL2png and depending on your usage, potentially a plan with Cloudinary as well.
html2canvas
While not a gem, html2canvas is easy to integrate into a Rails app with a little sprinkling of javascript with help from StimulusJS.
However, html2canvas only lets you take screenshots of your own app. So we'll modify our screenshot button app a little here.
Let's get set up. Just like the previous options, we'll create a new app, set up our app, create our view/route/controller and try it out.
Setup
Because html2canvas is a JavaScript library, we're going to use StimulusJS to make integrating all of the JavaScript-related pieces really easy for ourselves.
In the terminal, run:
rails new htm2canvas && cd html2canvas
Then, inside your gemfile, add gem 'stimulus-rails'
then bundle install
. This will create a few files for you, including hello_controller.rb
which we'll use in just a few steps.
We'll then add html2canvas by installing it via npm with the following command:
npm install html2canvas
Because we're using Rails 7, we can pin html2canvas to our import map by running:
./bin/importmap pin html2canvas
Adding a route and creating our view and controller files
Similar to the examples above, we'll add a basic route, view, and controller action.
First up, create a root route in routes.rb
file by adding root "screenshot#show"
before the last end tag.
Then, create a new file called show.html.erb
in app/views/screenshot
. We'll update show.html.erb to look like this:
The data-controller
tells StimulusJS we want to use the controller named "hello" that's located at app/javascript/controllers/hello_controller.js
. Inside that file, we will have a method called capture
that will use html2canvas to take a screenshot of our site. Remember, html2canvas can not take screenshots of external URLs.
Inside hello_controller.js
we'll add the following:
Now, when you run your Rails server, you should see a button that can take a screenshot of your application and display it in a new window.
Benefits and Drawbacks of Using html2canvas for Screenshots
Again, the use case for html2canvas is rather narrow and does not offer many customizations. However, for simple screenshots of your own application, html2canvas may be just what you're looking for.
Urlbox
Next up is Urlbox. Setup for Urlbox is easier than others for this example. They're also working on a gem that'll help speed this process up even faster.
Let's spin up a new app and call it urlbox
rails new urlbox && cd urlbox
Adding a route and creating our view and controller files
Similar to the examples above, we'll add a basic route, view, and controller action.
First up, create a root route in routes.rb
file by adding root "screenshot#show"
before the last end tag.
Then, create a new file called show.html.erb
in app/views/screenshot
. We'll update show.html.erb to look like this:
This will create a button that submits the user entered URL address to Urlbox and then displays it if it exists.
In the app/controlls/screenshot_controller.rb
, we'll add the code below. While we'll put this in the controller for this example, you could extract this into a concern or as a module in you /lib
folder.
Don't forget to swap your own API key in for the fillers in the def urlbox
method!
Once you have this in your controller, fire up your server by running rails server
in your terminal. Enter a URL (ex. https://wsj.com) and a full-size, retina-quality screenshot of the site will appear - without ads and any cookie banners you would usually get. Heads up, because the image quality is so high, it can take a couple of seconds to load!
Using Webhooks to Render Screenshots Asynchronously with Urlbox
Urlbox offers a webhook option to make rendering screenshots asynchronously incredibly easy. Simply pass your webhook URL in as an option and Urlbox will send a POST request back to that url with data about the screenshot in JSON format once it has completed rendering. 🤯
Let's add it to our sample app.
First up, in your routes.rb
file, add the following line:
post 'screenshot/urlbox_webhook', to: 'screenshot#urlbox_webhook'
This will create a route that Urlbox will be able to POST the screenshot data to. We'll do more with this route shortly.
In order to test out our webhook, we'll use ngrok. If you haven't installed it yet, there are great instructions on how to do so here.
Let's fire ngrok up with the following command:
ngrok http 3000
Once we have ngrok up and running, we can start with making some modifications to our options and call to Urlbox in with the following lines in screenshot_controller.rb
:
In the def urlbox
method inside the query
definition where we have our existing options, we'll add the following option:
:webhook_url => options[:webhook_url]
We'll then update our call to Urlbox to include information for our new option:
@image = urlbox(url, width: 1920, height: 1080, block_ads: true, hide_cookie_banners: true, retina: false, dark_mode: true, webhook_url: "https://12a3-45-67-89-000.ngrok.io/screenshot/urlbox_webhook")
Note: you'll want to replace the numbers & letters part of ngrok URL with the ones visible in your ngrok terminal.
Next up, we'll create a controller action for our new webhook route. This will allow us to take the data Urlbox gives us and do things with it.
In screenshot_controller.rb
we'll add the following under our show action:
That's it! Now, when we ask Urlbox for our screenshot, we'll also get a POST request. If you visit your web interface's inspect page (typically at http://127.0.0.1:4040/inspect/http), you should be able to see the following:
Urlbox's webhook option is a great way to process screenshots in the background so that you and your users can continue to perform tasks while waiting for your Urlbox renderings to come back.
Benefits and Drawbacks of Using Urlbox for Screenshots
You may notice the different options where we define query
above. Urlbox has a large amount of options to choose from including retina-quality images, ad blocking, selector targeting, and more. You can check out the long list of options here.
Plus, if you don't want to store your screenshots locally or in ActiveStorage, Urlbox lets you set an S3 bucket (docs here) that you've configured in your account so that you can send all your screenshots there automatically. Once you have Urlbox set up, you can also connect it to Zapier so non-engineering staff can create workflows around the screenshots you're capturing.
Now go take some screenshots in Rails!
As you can see, there are multiple ways to generate screenshots in your Ruby on Rails apps. Some approaches like URL2png are good for simple, straightforward use cases while others, like Urlbox, allow for multiple options like S3 integration, webhooks, target selection, retina-quality captures, and more.
If you're looking for an easy way to take website screenshots or PDFs and add them to your Rails project, give Urlbox a try. It’s free to get started, and as you can see in the example above, setup is super easy. Just sign up for an account, generate a token, and start taking screenshots!