React CRA and SEO 2019

Warning this is pretty old. You should probably use NextJS and leave CRA behind.

I found React's CRA (Create React App) to be interesting when it comes to SEO/SMO and getting it to work with Search Console and Analytics for individual pages. For a starting point you'll want to make sure you're using the create-react-app setup for the following guide, Parcel and Webpack have similar ways of accomplishing the following, however for the sake of time we will use create-react-app.

What

If you haven't done so already, check out NFL's react-helmet package for getting the DOM to recognize your individual page title, description tags etc.

import { Helmet } from 'react-helmet'
<Helmet>
  <title>ABOUT PAGE</title>
</Helmet>

Now we need to install react-snap to enable SEO and SMO for our React app:

npm i --dev react-snap

While that's installing, go into your package.json and add the following to your scripts:

"scripts": {
  "postbuild": "react-snap"
}

Then change your scr/index.js imports for react-dom and add the following for React 16+:

import { hydrate, render } from 'react-dom'
const rootElement = document.getElementById('root')
if (rootElement.hasChildNodes()) {
  hydrate(<App />, rootElement)
} else {
  render(<App />, rootElement)
}

Adding React Snap will prep your app for SEO and SMO, along with performance optimizations on loading times.

Assuming you have your Analytics tags in your public/index.html, you can move on to installing a few polyfills to help get your pages indexed. But first you need to install 2 packages:

npm i --s babel-polyfill whatwg-fetch

Once you've installed those packages, create a file in your config directory called polyfill.js, and fill in the following:

require('babel-polyfill')
require('whatwg-fetch')
 
if (process.env.NODE_ENV === 'test') {
  require('raf').polyfill(global)
}

This polyfill from WoWAnalyzer uses babel-polyfill and whatwg-fetch and has tons of comments to give a great explanation for the polyfill service. [Reference to the source in comments of this Reddit thread.]

Now add the polyfill imports to the top of your index.js to continue on.

import 'babel-polyfill'
import './config/polyfills'

For the next step you could install yet another package, however I found that just writing out a sitemap.xml file to put in the public directory is simple enough to not require more dependencies.

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
  <url> <loc>https://www.some-react-example.com/</loc> </url>
  <url> <loc>https://www.some-react-example.com/about</loc> </url>
  <url> <loc>https://www.some-react-example.com/random</loc> </url>
  <url> <loc>https://www.some-react-example.com/404</loc> </url>
</urlset>

Troubleshooting:

If you're still having issues with your Analytics tags, try deleting property then re-creating the property. Don't forget to add the new analytics ID to your public/index.html and run build a fresh build.

If Search Console isn't recognizing anything still, try installing react-app-polyfill.

I've also created a Github repo example for your reference.