Back to Blog
Web Development

How to Fix Meta Tags on Your Replit React Site (So Social Shares Actually Work)

Paul Mulligan January 23, 2026
Share:
How to Fix Meta Tags on Your Replit React Site (So Social Shares Actually Work)

If you've built a React site on Replit and tried sharing it on LinkedIn or Twitter, you may have noticed something frustrating: every page shows the same generic preview, no matter which URL you share.

That's because React apps are client-side rendered. The meta tags in your HTML are static defaults, and social media crawlers don't execute JavaScript—they only see what's in the initial HTML response.

I ran into this exact problem with this very portfolio site you're reading. Here's how I fixed it.

The Problem with Client-Side Meta Tags

You might have set up react-helmet or react-helmet-async to manage your meta tags. The code looks correct, the tags update when you navigate around your site, and everything seems fine when you inspect the page in your browser.

But when LinkedIn's crawler fetches your /about page, it doesn't run your React code. It just reads the raw HTML, which contains your default homepage meta tags baked into index.html.

This means sharing your carefully crafted blog post on LinkedIn shows "My App - Welcome" instead of your actual post title. Not exactly the professional impression you're going for.

Why Pre-rendering Doesn't Work Well on Replit

The typical solution for this is pre-rendering or static site generation—tools like vite-plugin-prerender or react-snap that generate static HTML for each route at build time.

However, Replit's build environment doesn't always play nicely with these tools. The Vite config modifications can be tricky, and the build process may not have access to everything these tools need (like a proper headless browser environment).

I spent several hours trying to get pre-rendering working before realizing there was a simpler solution already available to me.

The Solution: Server-Side Meta Tag Injection

Since Replit apps typically run on an Express server (check your server/index.ts), we can intercept requests and inject the correct meta tags before sending the HTML to the browser—or more importantly, to the crawler.

Here's the approach I used:

First, create a configuration object that maps your routes to their meta tags. Store the title, description, and OG image for each page you want to have unique social previews. For my site, this includes the homepage, about page, services pages, blog listing, and individual blog posts.

Then, in your Express server, intercept requests for your pages. Read the base index.html file, find the default meta tags, and replace them with the page-specific ones based on the requested URL.

The key meta tags to replace are: the title tag, meta description, og:title, og:description, og:image, og:url, and their Twitter Card equivalents (twitter:card, twitter:title, twitter:description, twitter:image).

The Tricky Part: Multi-Line HTML

One gotcha that caught me: Vite builds multi-line meta tags in the production HTML. A simple regex like /<meta property="og:title"[^>]*>/ won't match tags that span multiple lines.

The fix is to use [\s\S]*? instead of [^>]* in your regex patterns. This matches any character including newlines, non-greedily. So your pattern becomes: /<meta[\s\S]*?property="og:title"[\s\S]*?>/g

This small change was the difference between my meta tag injection working perfectly and not working at all.

Handling Dynamic Blog Posts

For blog posts with dynamic slugs (like /blog/my-post-title), you can either maintain a lookup object with each post's metadata, or query your database/CMS for the post details and inject them dynamically.

I chose to keep my blog post metadata in a shared TypeScript file that both the server and client can import. This means the source of truth for titles, excerpts, and OG images lives in one place, reducing the chance of mismatches.

What This Looks Like in Practice

When a request comes to /about, my Express server reads the built index.html, swaps out the generic meta tags for my About page content, and sends the modified HTML. The crawler sees exactly what I want it to see, with no JavaScript execution required.

For users with JavaScript enabled (which is everyone actually browsing the site), the React app still hydrates and works normally. The react-helmet tags take over for client-side navigation between pages, providing a seamless experience.

Testing Your Implementation

After deploying, test your meta tags with these tools:

LinkedIn Post Inspector (linkedin.com/post-inspector) lets you preview exactly what LinkedIn will show when someone shares your URL. It also lets you clear LinkedIn's cache if you've made changes—very useful during development.

Facebook Sharing Debugger (developers.facebook.com/tools/debug) shows you what Facebook sees and lets you scrape fresh information. Facebook caches aggressively, so use the "Scrape Again" button after making changes.

Twitter Card Validator (cards-dev.twitter.com/validator) previews your Twitter card appearance. Note that Twitter/X has been less consistent about updating their validator, but it still works for basic testing.

Enter different page URLs from your site and verify each one shows unique, correct information. If you see your new meta tags appearing correctly, you've done it!

Key Takeaways

React-helmet alone isn't enough for social sharing on client-rendered apps. Social crawlers don't execute JavaScript, so they need the correct meta tags in the initial HTML response.

Server-side injection on Replit's Express server is a reliable solution that works for all crawlers without complex build tooling. It's also more maintainable than pre-rendering solutions that might break with Replit updates.

The extra setup is worth it. When you share your blog posts or portfolio pieces on LinkedIn, the preview will actually match the content—which means more clicks and better engagement with your professional network.

Need Help With Your Website's SEO?

Meta tags are just one piece of the SEO puzzle. If you're struggling to get your website noticed on search engines and social media, I can help. From technical SEO fixes to complete website builds, I work with small businesses to create websites that actually get found.

Get in touch for a free consultation—let's talk about how to improve your online presence.


Building a website for a small business? I also build professional WordPress and Webflow sites for small businesses, starting at $1,000. If you or someone you know needs a site, check out my services or get in touch.

Paul Mulligan

Freelance Web Developer

Paul Mulligan is a freelance web developer based in Baltimore, MD with 10+ years of experience building WordPress and Webflow sites for small businesses. He focuses on clean design, fast performance, and real results.

Support My Open Source Work

I build free, open-source developer tools like Flavian and Aurelius. If you find my work helpful, consider supporting me on Patreon.

Support on Patreon

Related Articles

How I Use Claude Code to Debug WordPress Style Issues

Read Article

SEO Strategies That Actually Work for Small Businesses

Read Article

5 Signs Your Small Business Website Needs a Redesign

Read Article

Ready to Transform Your Business's Website?

Let's discuss how I can create a website that attracts and converts more customers.

Get a Free Consultation