Concepts / Building Search UI / Server-side rendering
Oct. 11, 2019

Server-side Rendering

InstantSearch.js does not support server-side rendering. However, it is possible to get some of the server-side rendering benefits using another technique: dynamic rendering.

Dynamic Rendering

In a nutshell, dynamic rendering allows to switch between client-side rendered and pre-rendered content for specific user agents, namely search engines user agents. This means that whenever your server receives a requests, it first looks at the user agent to determine whether it’s coming from a search engine or a regular user.

  • If the request is coming from a search engine, the response is proxied through a headless browser that pre-renders it.
  • If the request is coming from a regular user, the response is rendered client-side.

1. Build an InstantSearch app

The easiest way to setup a basic InstantSearch app is using create-instantsearch-app. Install create-instantsearch-app and create your app.

$
$
npm install -g create-instantsearch-app
create-instantsearch-app my-app

Feel free to pick any InstantSearch flavor your like. Pick the default values for the rest of the options.

Run the build command and confirm it produced a dist/ folder.

$
$
cd my-app
npm run build

Add a basic Express.js server that will serve our static files.

$
$
npm install --save express
touch index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// index.js
const express = require('express');
const app = express();

app.use(express.static('dist'));

const port = process.env.PORT || 3000;
app.listen(port, err => {
  if (err) {
    console.error('failed to start server.');
    return;
  }
  console.log(`server started at http://localhost:${port}/`);
});

Now run the server and visit http://localhost:3000 to make sure everything is working.

$
node index.js

2. Setup and configure a dynamic renderer

Google recommends using either rendertron (free, self-hosted) or prerender.io (fully hosted). In this example, we’ll be using rendertron.

$
$
npm install -g rendertron
PORT=3001 rendertron &

Our pre-renderer is now listening on port 3001 and ready to render JavaScript generated content into HTML.

3. Proxy your requests through rendertron

You need to send every request with the Content-Type: text/html header and the relevant user agent to the URL of rendertron: http://localhost:3001/render.

Depending on your stack, there are multiple ways you can achieve this kind of proxying, but if you’re using an Express.js server, rendertron-middleware can handle this proxying for you.

$
npm install --save rendertron-middleware
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const rendertronMiddleware = require('rendertron-middleware');

/* ... */

app.use(
  rendertronMiddleware.makeMiddleware({
    proxyUrl: `http://localhost:3001/render/`, // rendertron address with a /render/ suffix
    timeout: 60 * 1000,
    userAgentPattern: /googlebot|bingbot/i // by default
  })
);

app.use(express.static('dist'));

/* ... */

Feel free to adjust the userAgentPattern or use the default values.

Close and restart your server, then run this curl command to confirm pre-rendering works.

$
curl --user-agent "googlebot" http://localhost:3000/

Did you find this page helpful?