BlueJar Fix Plan Implementation · React

You get the fix plan. Our developers ship it in your Next.js, Gatsby, or Remix codebase.

A pure client-side React app, a Create React App or Vite SPA with no server rendering, sends back an initial response that's just <div id="root"></div>. Most AI crawlers run little to no JavaScript, so they may see nothing there, a risk WordPress and Shopify don't share since both serve full HTML by default. Instead of leaving that as a checklist item for whoever owns your frontend, BlueJar's own developers migrate the pages that matter to SSR or SSG, ship server-rendered meta tags and schema, and verify the fix in the raw HTML response themselves.

Our developers work in Next.js (App Router & Pages Router), Gatsby & Remix · SSR, SSG & hybrid rendering

Why we implement it ourselves

"Just add meta tags" doesn't work if your page never reaches the crawler rendered.

A fix plan that says "add JSON-LD" or "fix your meta tags" assumes those tags show up in the response a crawler actually receives. On a client-side-only React build, they often don't, they exist only after JavaScript runs in a browser. Our developers dig into your specific rendering setup, whether that's Next.js, Gatsby, Remix, or a plain CRA/Vite SPA, and ship the fix in the codebase itself.

<div id="root">
is all a pure client-side-rendered React app sends in its initial HTML response. Many AI/LLM crawlers can't execute the JavaScript that fills it in, so a CSR-only page can be functionally invisible to them.
useEffect
is a common but broken way to inject meta tags and JSON-LD. It works fine in a browser tab, but a crawler that doesn't run JS never sees what document.head ends up holding.
/public
is where llms.txt lives on Next.js, CRA, and Vite builds (or /static on Gatsby), served at the true root path automatically. Same-day, no workaround needed.
01 · SSR/SSG migration

We migrate your marketing and content pages off client-side-only rendering.

Our developers identify which routes are CSR-only and prioritize the ones AI engines actually need to cite: product pages, blog posts, docs, landing pages. We migrate them to Next.js SSR/SSG, Gatsby's build-time static HTML, or Remix's loader-based rendering, whichever your stack already runs. Logged-in views and dashboards stay exactly as they are, this is scoped to what needs to be crawlable.

  • We audit your routes to find which ones render an empty shell to non-JS crawlers
  • We ship the App Router, Pages Router, Gatsby, or Remix migration, not just a recommendation
  • We leave app-only, logged-in surfaces untouched, only the citable pages move
app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const posts = await getAllPosts();
  return posts.map((post) => ({ slug: post.slug }));
}

export default async function Page({ params }) {
  const post = await getPost(params.slug);
  return <Article post={post} />;
}
02 · Meta tags & JSON-LD, server-rendered

We move your meta tags and schema out of useEffect and into the server response.

A common mistake our developers find: title, description, and JSON-LD getting injected client-side via a useEffect + document.head hack. That defeats the purpose, non-JS crawlers never see it. We replace it with Next.js App Router's generateMetadata() and emit JSON-LD from a Server Component, so both are present in the HTML a crawler actually gets on the first request.

  • We replace client-only document.head hacks with generateMetadata() or SSR-based head management
  • We emit JSON-LD from a Server Component so it's in the raw HTML, not injected post-hydration
  • We verify every fix with curl or View Page Source, never DevTools' rendered Inspect Element view
app/product/[slug]/page.tsx
export async function generateMetadata({ params }) {
  const product = await getProduct(params.slug);
  return {
    title: product.title,
    description: product.description,
    openGraph: { images: [product.ogImage] },
  };
}

export default async function Page({ params }) {
  const product = await getProduct(params.slug);
  return (
    <>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(product.schema) }}
      />
      <ProductView product={product} />
    </>
  );
}
03 · robots, sitemap & llms.txt

We drop in the crawl-access files your stack is already built to serve.

Next.js supports app/robots.ts and app/sitemap.ts as Route Handlers, we wire those up directly. For simpler setups, we drop a static robots.txt straight into /public. And because llms.txt is just a static file at the true root on a React stack, we ship it the same day, no workaround required like on platforms such as Shopify.

  • We add app/robots.ts and app/sitemap.ts on App Router, or static files in /public otherwise
  • We ship llms.txt into /public (Next.js, CRA) or /static (Gatsby) the same day
  • We open the specific AI crawler user agents your existing robots rules were silently blocking
app/robots.ts
import { MetadataRoute } from 'next';

export default function robots(): MetadataRoute.Robots {
  return {
    rules: [
      { userAgent: '*', allow: '/' },
      { userAgent: 'GPTBot', allow: '/' },
    ],
    sitemap: 'https://example.com/sitemap.xml',
  };
}

What a real React implementation looks like

Not "migrate to SSR." Our developer, in your repo, shipping the PR.

High priority Zone: Technical AI accessibility Stack: Vite SPA → Next.js

What was broken

The client's marketing site was a Vite single-page app with no server rendering. A curl against the homepage returned an empty <div id="root"></div>: every meta tag and JSON-LD block was injected client-side via a useEffect hack. AI crawlers with limited JS execution had nothing to read.

What we shipped

  • Migrated the five AI-citation-worthy marketing routes to Next.js App Router with generateStaticParams
  • Moved meta tags into generateMetadata() and JSON-LD into a Server Component <script> tag
  • Added app/robots.ts, app/sitemap.ts, and a same-day llms.txt in /public

Timeline

  • 3 days PR merged: five routes now serve full server-rendered HTML on the first response, verified with curl.
  • Ongoing Re-audit confirms AI engines can parse and cite the migrated pages in the next fix plan cycle.

This is what happens to every fix in your plan: named down to the file and the function, then shipped by us.

React implementation FAQ

Is Fix Plan Implementation a separate service from the audit?

Yes. The GEO audit and fix plan are their own product. Implementation is a standalone engagement on top of it: our developers execute the plan directly in your codebase, whether you ran the audit with us or already have a fix plan from somewhere else.

What access do you need to implement fixes in our codebase?

Repo access (GitHub or GitLab) and a way to ship the changes: a Vercel or Netlify preview deploy, or a direct PR that your team reviews and merges. We scope exactly what's needed before starting, and you keep full ownership and review rights over everything we ship.

Which frameworks does your team work with?

Next.js (App Router and Pages Router), Gatsby, Remix, and similar React-based meta-frameworks. We also work with plain Create React App or Vite SPAs when the fix requires migrating specific routes to server rendering.

Will this conflict with our existing engineering team?

No. We can open PRs for your team to review and merge, or ship directly with a deploy preview if you'd rather your engineers stay focused elsewhere. Either way, every change goes through your normal repo, so you keep full visibility into what changed and why.

How is implementation priced, and how long does it take?

Pricing scopes to the size of your fix plan and whether it involves an SSR/SSG migration, most React engagements run one-time, not a subscription. Critical and High-priority fixes are typically shipped within the first week; get a firm quote and timeline on a call.

Get the fix plan shipped, not just written

Tell us about your React stack and your fix plan (ours or someone else's). We'll scope the implementation and quote a timeline on the call.