Server side rendering with puppeteer and headless chrome— a practical guide

Dejan Blazeski
Sep 21, 2019 · 4 min read

TL;DR — serve JS to users, server side rendered content to bots (the source code is available here — http://bit.ly/2m6HN8w)

While building Binge, my framework of choice was VueJs (and single page application). Happy with both choices.

If you (assuming a dev) view the source code — it would only show a couple of lines of code — some meta tags and an almost empty <body> tag with a root div and a bundled js file — so when people visit it, it’s a typical website, browsers download the bundle and render the page.

When Google (and other search engines or social networks) parses it, it’s that (almost) empty <body />.

Google understands JS, just needs a couple of days to index and process it (as this google’s webmaster videos says)

The solution I used: server side rendering with puppeteer and google chrome. My goal for implementing SSR was:

  • When people share a link on a social media platform, the link & html should be pre-rendered so a pretty preview (you know, text & image) is shown instead of just text or link. And if facebook can’t parse the html, they won’t make it look pretty.

The setup we will use:

  • node server (with expressjs)

Let’s use the existing github repo to speed up the setup, explaining the important bits.

#clone the repo
git clone https://github.com/dblazeski/express-chrome-ssr.git
#install the dependencies
cd express-chrome-ssr
yarn install

Our entry file is ./src/index.js Importing express for our server, puppeteer for managing our headless chrome instance and rendering the url, and booting our app using express looks like this:

That’s the minimum setup we need for the server.

Let’s add a route that will accept url parameter/ssr?url=http://google.com Once we start the server, we will pass our url’s and get the rendered html as response.

Here’s the code:

Our /ssr route handled by express and passed to the ssr function we imported above

What happens?

  • We’re registering our /ssr?url route

Let’s take a look at the ssr function that actually does the render:

Our ssr function, see the github repo for the full version

What happens?

  • #1 Our async function accepts two params — the url and the existing browserWSEndpoint chrome instance.

Once the render is complete, the response is passed back to our index.js file and sent back to the server #[18–20] in ssr-2.js — that’s the html we’re after!

The content can then be printed in the browser and bots can parse it 🎉

Sending the content to the browser

This final step can vary depending on your programming language / framework. I use Laravel, so the example will be in Laravel / PHP — but I’m sure it’s easy to understand.

  • Check if the visitor is a bot

A package for php that’s good for user agent detection is CrawlerDetect (and it has support for all popular frameworks).

Pseudo code example:

The source code with examples you can use is available on http://bit.ly/2m6HN8w. The repo also has ready server scripts (see package.json) you can use with nodemon or pm2.

Started using SSR in attempt to serve the content bots require for rich links preview. If you’re an avid movie fan, check out my latest project Binge.

Thanks for reading.

On an unrelated note, are your Macbook Pro animations lagging? You should try switching to the dedicated (more powerful) graphic card when on power — automate it with this app https://gum.co/mac-auto-gpu

The Startup

Get smarter at building your thing. Join The Startup’s +787K followers.

Sign up for Top 10 Stories

By The Startup

Get smarter at building your thing. Subscribe to receive The Startup's top 10 most read stories — delivered straight into your inbox, once a week. Take a look.

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Dejan Blazeski

Written by

Founder binge.app. Curious dev. Laravel / Angular / VueJs / React Native / Docker. Love stand up shows.

The Startup

Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +787K followers.

Dejan Blazeski

Written by

Founder binge.app. Curious dev. Laravel / Angular / VueJs / React Native / Docker. Love stand up shows.

The Startup

Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +787K followers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store