Skip to content
React SPA실무 경험

Fixing duplicate meta tags in a React SPA by building a library (feat. react-head-safe)

3 min readWorkMoved from my Tistory blogRead the Korean original

Hi, I'm Sungjun Um, a frontend developer.

In React-based SPAs, react-helmet and react-helmet-async have been used as a de facto standard for SEO optimization. I have also used these libraries steadily in personal projects and in services at work.

But while running a real service, I found a problem where the initial meta tags defined in index.html and the meta tags created dynamically on page navigation were duplicated. Below are the limits of the existing libraries and how I came to build react-head-safe myself to solve this.

1. Why SEO is still tricky in an SPA

On the first load, a React SPA receives empty HTML (with only the root div) from the server. Then JavaScript runs and renders the content and meta tags, and two problems come up here.

  • Crawler limits: Some crawlers only collect the static HTML from before JS runs.
  • No initial information: Until JS runs, the title and og tags are empty, so the information is missing when the page is shared on social media.

To prevent this, people usually also write basic meta tags in index.html ahead of time.

2. The duplication issue with react-helmet-async

If you keep default tags in index.html and try to manage them dynamically with react-helmet-async, this is what happens.

  • Symptom: The title tag is replaced correctly, but for meta and og tags, new tags keep piling up after the existing ones.
  • Cause: react-helmet-async only controls the tags it creates and manages itself (tags with a data attribute). That means it doesn't touch static tags that already exist in index.html.

Result: Two or more meta tags with the same property end up inside <head>, and crawlers can't tell which information to trust. (They usually give priority to the static tag found first.)

3. My choice for a fix: building it myself

I considered two options to solve this problem.

  1. Contribute to an existing open source project (PR)
  2. Define the problem clearly and build my own library

I took the second path to act on a goal I'd had for a while, "publishing open source that solves a real problem," and that is how I came to build react-head-safe.

4. react-head-safe: safe head management

react-head-safe focuses on managing meta tags predictably in an SPA.

Core design principles

  • Conflict prevention: Even if there are initial tags defined in index.html, the moment the library runs, it finds tags with those attributes (name, property) and removes them.
  • Single instance (Singleton): It ensures that only the meta tags for the current page exist in <head>.
  • Predictability: On page navigation in CSR, it uses useLayoutEffect to give DOM updates a higher priority.
Aspect react-helmet-async react-head-safe
Handling static tags Ignored (duplicates occur) Detected, then replaced/removed right away
Tag management Controls only the tags it manages Controls all tags with the same attribute
Setup complexity Needs a Context Provider Works right away without a Provider

5. Quick usage

Usage is very intuitive. You use it declaratively inside the component that needs it, without setting up a Provider.

jsx
import { ReactHeadSafe } from 'react-head-safe';

function MyPage() {
  return (
    <>
      <ReactHeadSafe
        title="My Page Title"
        description="This is the page description for SEO."
        keywords="react,seo,meta tags"
        ogTitle="My Page Title for Social Media"
        ogDescription="This is the description for social media."
        ogImage="https://example.com/image.jpg"
      />
      <div>Your page content...</div>
    </>
  );
}

6. Check out the project

react-head-safe is open source. If you are dealing with duplicate meta tags in an SPA, see the links below for detailed usage and try it in your project!

Feedback, bug reports, and stars help a lot in maintaining and improving the project.

GitHub - umsungjun/react-head-safe: A CSR-only React head manager that prevents duplicate meta tags and safely manages document

Wrapping up

react-head-safe takes the most practical SEO approach: on the first visit, it shows the default information in index.html to handle crawlers, and after a page change, it safely replaces it with the new information.

It is still at an early stage, but it was meaningful work because I solved a pain point I ran into at work myself.

  • #description
  • #GitHub
  • #keywords
  • #meta
  • #npm
  • #open source
  • #react-head-safe
  • #react-helmet
  • #react-helmet-async
  • #title

More in Work