# React + Vite / CRA

> Add a blog to a client-rendered React app via a thin server proxy that hides the API key.

# React + Vite / Create React App

Vite/CRA apps don't have a built-in server, so you need a tiny proxy to keep `MENTIONWELL_API_KEY` off the client. The most common pattern is a serverless function (Vercel, Netlify, Cloudflare).

## 1. Proxy endpoint

Pick whichever runtime fits.

### Vercel Edge Function

```ts
// api/blog/[...path].ts
export default async function handler(req: Request) {
  const url = new URL(req.url);
  const target = `${process.env.MENTIONWELL_API_URL}/api/public/${process.env.MENTIONWELL_SITE_SLUG}/${url.pathname.split("/").slice(3).join("/")}${url.search}`;
  const upstream = await fetch(target, {
    headers: { Authorization: `Bearer ${process.env.MENTIONWELL_API_KEY}` }
  });
  return new Response(upstream.body, {
    status: upstream.status,
    headers: { "content-type": upstream.headers.get("content-type") ?? "application/json" }
  });
}
```

### Cloudflare Worker

```ts
export default {
  async fetch(req: Request, env: { MENTIONWELL_API_URL: string; MENTIONWELL_SITE_SLUG: string; MENTIONWELL_API_KEY: string }) {
    const url = new URL(req.url);
    const target = `${env.MENTIONWELL_API_URL}/api/public/${env.MENTIONWELL_SITE_SLUG}/${url.pathname.replace(/^\/blog/, "posts")}`;
    const upstream = await fetch(target, {
      headers: { Authorization: `Bearer ${env.MENTIONWELL_API_KEY}` }
    });
    return new Response(upstream.body, upstream);
  }
};
```

## 2. Client fetch

```tsx
// src/Blog.tsx
import { useEffect, useState } from "react";

export function Blog() {
  const [posts, setPosts] = useState<any[]>([]);
  useEffect(() => {
    fetch("/api/blog/posts")
      .then((r) => r.json())
      .then((data) => setPosts(data.posts ?? []));
  }, []);
  return (
    <ul>
      {posts.map((post) => <li key={post.slug}>{post.title}</li>)}
    </ul>
  );
}
```

## 3. Detail page

Match `/blog/:slug` in your router (React Router, TanStack Router) and fetch `/api/blog/posts/{slug}`. Render `post.html` via `dangerouslySetInnerHTML`.

> If you really want to call the Mentionwell API directly from the browser, you can — the API supports CORS — but you'll need to **embed the API key in the bundle**, which makes it visible. Only do this on a deliberately public-info app.


---

Canonical URL: https://mentionwell.com/docs/frameworks/react
Live HTML version: https://mentionwell.com/docs/frameworks/react
Section: Quickstarts by stack
Site index for AI ingestion: https://mentionwell.com/llms.txt
Full reference: https://mentionwell.com/llms-full.txt
