Using PhantomJS to Capture Analytics for a Rails Email Template
Every Sunday Bark sends parents a weekly recap of their children’s activity online. The first iteration was pretty basic, things like “Your children sent X number of messages this past week” and “You have 10 messages to review”. But we wanted to go deeper…
Using PhantomJS, we were able to take screenshots of a modified version of the application’s child analytics page and include the image in the email sent to the parent. The email now contains everything the parent can see from the application, all without leaving their inbox.
If you’ve every attempted to style an HTML email with anything more than text, you’re sadly familiar with its limitations. Tables and other elements from the 90’s are the only tools we have to maintain cross-platform compatibility. One of those tools, the subject of this post, is images.
Our weekly recap email contained a line chart illustrating the number of messages the child exchanged during the past week. While this was somewhat helpful to parents, it didn’t tell the full story.
While this email does include a graph, it’s the result of calling out to a service that rendered the graph, stored it, and returned the URL to include as an image. While this service worked well for simple illustrations, it didn’t provide us the flexibility we had with modern web tools and visualizations. Aside from that, the styling of the charts is limited.
Elsewhere on Bark, we had already built the full story through other lists and illustrations.
Recreating the same lists and charts just for the email felt like a duplication nightmare and vulnerable to becoming stale. We wouldn’t be able to use the same rendering because most of the charts rendered SVGs, which aren’t compatible with most email clients. Additionally, there were a handful of CSS styles needed for the page that while possible to include in the email, felt excessive.
Stepping back from the problem, we realized we wanted the majority of the analytics page, just embedded in the email. Was there a way to do that without rewriting it for email clients?
We could take a screenshot of the analytics page and embed it as an image in the recap email.
Our first attempt was using
wkhtmltoimage and the
IMGKit ruby gem. Aside from the headaches of installing a working OSX version of
wkhtmltoimage due to a regression, getting a working configuration was non-trivial.
After spending almost a full day trying to get the right combination of settings, we gave up. There had to be a better way…
Frankly, our next step was to look for a Saas service that provided this functionality. Certainly I should be able to send a URL to an API, and they’d return an image, perhaps with some configuration options for size and response. To our surprise, there were none (based on a 15 minute internet search. If you know of one, we’d love to hear about it). There were plenty of services focused on rendering PDFs geared towards invoices and other documents one would want to email customers.
We were reminded of Capybara’s ability to capture screenshots on failed test runs. After poking around this functionality,
phantomjs emerged as a potential solution.
phantomjs was simplified using the
phantomjs-gem ruby gem, which installs the appropriate
phantomjs binary for the operating system and provides an API (
#run) to execute commands.
Script the Screenshot
Note: a variety of the settings (
timeout) were found using trial and error for our particular situation.
We use Sidekiq to enqueue the thousands of recap emails sent to parents each week. Because this approach relies on using our existing website as the source data for the screenshot, we have to be conscious of spreading the job processing over a certain period of time, so we don’t overload the application for regular users.
Create the Screenshot
With this script in hand, now we can use the following class to create the image for each child:
For each child, we’ll provide the URL to the child’s analytics page and run the following
file_path method to return the path of the screenshot:
Adding as an Inline Email Attachment
With an image for each child, we can iterate through each child and inline include the image in the mailer:
Then in the email template, we can include the following to render the image:
PhantomJS proved to be the simplest solution for the job. With a small script and no further configuration, we were able to lean on the analytics page we’d already built to improve the Bark recap emails.
Parents will now have more visibility in to their child’s online activity without leaving their inbox.