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.
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.