coiai Logo

This article is an English translation of the original Japanese post. Read the Japanese original →

A Complete SEO Checklist for a React-Built SPA

January 15, 2025

Categories: React · Tags: react, SEO

This time around I built a site using the WordPress REST API and React.
Here I'll jot down notes on the SEO measures I took along the way.

Handling Direct URL Access

React is fundamentally a SPA, so the server needs to be configured to redirect every request to the React app's entry point.

Add the following to your .htaccess.

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^ /index.html [L]
</IfModule>

Setting Up GA4

If you want to use a package, try react-ga4.

I created a file called Analytics.ts and loaded it into App.tsx.

import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import ReactGA from 'react-ga4';

const TRACKING_ID = 'G-yourcode'; // GoogleアナリティクスのトラッキングIDを設定

ReactGA.initialize(TRACKING_ID);

function Analytics() {
  const location = useLocation();

  useEffect(() => {
    // ページが変更されるたびにトラッキング情報を送信
    ReactGA.send({ hitType: 'pageview', page: location.pathname });
  }, [location]);

  return null; // UIに表示するものはない
}

export default Analytics;
function App() {
  return (
    <RecoilRoot>
      <Router>
        <Header />
        <Analytics />
        <Routes>
          <Route path="/" element={<top />} />
        </Routes>
      </Router>
    </RecoilRoot>
  );
}

Setting Up Meta Tags and OG Tags

React-helmet causes errors in the current environment. Use react-helmet-async instead.

To set meta information dynamically in React, use react-helmet-async or @tankstack/react-head.

Below is an example using React helmet-async.

import React from 'react';
import ReactDOM from 'react-dom/client'
import './styles/index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

// helmet
import { HelmetProvider } from 'react-helmet-async';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <HelmetProvider>
      <App />
    </HelmetProvider>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
import { Helmet } from "react-helmet-async";

function MyPage() {
  return (
    <div>
      <Helmet>
        <title>ページタイトル</title>
        <meta name="description" content="ページの説明文" />
        <meta property="og:title" content="ページタイトル" />
        <meta property="og:description" content="ページの説明文" />
        <meta property="og:image" content="画像URL" />
        <meta name="robots" content="index, follow" />
      </Helmet>
      <h1>コンテンツ</h1>
    </div>
  );
}

https://www.npmjs.com/package/react-helmet-async ← reference documentation

Setting Up Sitemap and robots.txt

Generate it automatically with react-router-sitemap (if you're using node.js),
or add it manually.

I've covered the steps in a separate post.

https://coiai.net/blog/3784

Marking Up Structured Data

Use JSON-LD.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "WebPage",
  "name": "ページタイトル",
  "description": "ページの説明文",
  "url": "https://example.com"
}
</script>

Introducing SSR (Server-Side Rendering)

Implement SSR using a framework such as Next.js.

Dynamic Rendering

Use Rendertron or Prerender.io.

↓ Google Search Central's official explanation of Rendertronhttps://developers.google.com/search/blog/2019/01/dynamic-rendering-with-rendertron?hl=ja

A Quick Primer on Rendertron

Rendertron is a tool that generates and serves static HTML so that search engines can properly index JavaScript applications.

1. User Request

A normal user request is served the JavaScript app (the React app) as-is.

2. Crawler Request

It detects requests coming from Googlebot and other crawlers, and uses Rendertron to generate and serve static HTML for them.

SSG: Static Site Generation

If the content doesn't change, you can pre-generate the HTML for each page.

Using a generator such as Gatsby is one option.

Or, if you're running React on its own, there's also the option of using react-snap.

A Complete SEO Checklist for a React-Built SPA | coiai Inc.