Open Graph Tags in React and Vite: Fix Missing Previews

If your React page looks right in a browser but shares the wrong image, compare the initial HTML with the document after React runs. The fix depends on where the metadata is generated.

Compare the HTML response with DevTools

A typical client-rendered Vite app sends an HTML shell and loads JavaScript to build the page. A head-management library can update the browser document after that JavaScript runs. That does not by itself establish what an external preview crawler receives.

curl -sS -L 'https://example.com/products/blue-mug'

Search this response for your product title and og:image. Then compare it with the browser's Elements panel. If the response has a default homepage image but Elements shows the mug, you have identified a rendering difference. Do not start with cache purges.

Current React versions support rendering metadata elements from components. That API and server rendering are separate concerns. Adding a meta element to a component does not make a client-only deployment serve route-specific HTML.

For one landing page, put defaults in index.html

A single-page marketing site may only need one preview. In that case, static tags in Vite's root index.html are a straightforward starting point. Replace every example value with your public production URL:

<meta property="og:type" content="website" />
<meta property="og:title" content="Blue Mug Studio" />
<meta property="og:description" content="Handmade mugs for everyday coffee." />
<meta property="og:url" content="https://example.com/" />
<meta property="og:image" content="https://example.com/share.jpg" />

Build and inspect the deployed response. A development file changing locally does not confirm that the production HTML or image changed. Use the meta tag generator if you want help preparing the markup.

For several pages, generate HTML for each route

A shop, directory, or blog needs the product or article's metadata in the response for its own URL. If the host rewrites every path to an identical index.html, a client-side router alone will not supply that distinction to an HTML-only fetch.

For a known set of routes, generate HTML at build time. For content that must be resolved on request, use a server-rendered route or a suitable framework integration. Vite documents both server rendering and prerendering; Vite itself does not choose your application's publishing strategy.

A useful acceptance test is simple: fetch two detail-page URLs and confirm their returned titles, page URLs, and images match their respective records. See why every page shows the same preview for a side-by-side debugging workflow.

Check route fallbacks, absolute URLs, and duplicates

After rendering is addressed, check that a direct visit to a nested route works. Navigation from your homepage can succeed while a fresh request to that same path fails or redirects elsewhere.

Use public absolute URLs for share images. During development, a preview image may point to localhost or a protected asset. Those values must not reach a public share. Also inspect the output for conflicting tags left by both your HTML template and your component library. Remove stale defaults through the template or framework rather than relying on whichever value a consumer happens to choose.

For a Next.js project, use the existing Next.js metadata guide; it covers a different rendering system. If the HTML is right but the image fails, check the image response independently.

Verify the deployed page, then test sharing

  1. Deploy the change to a public test URL.
  2. Fetch the exact nested route without cookies.
  3. Confirm the expected metadata exists in the response.
  4. Open its image URL without authentication.
  5. Use Proovd to inspect the fetched metadata, then test the affected sharing app.

If only your local app is ready, follow the localhost testing guide. A correct initial response removes one source of failure, but platform caches and presentation rules still need a separate check.

References