# React SDK Guide (/docs/react-sdk)



Overview [#overview]

This guide covers using EarlySEO in client-side React apps — Vite, Remix, or any SPA setup. For **Next.js App Router**, use the [Next.js SDK Guide](/docs/next-sdk) instead, which supports server components and the `npx @earlyseo/blog init` CLI scaffold.

***

Prerequisites [#prerequisites]

* A React project (Vite, Remix, Create React App, etc.)
* **SDK integration** enabled in EarlySEO (Dashboard → Integrations → SDK)
* **Site ID** from the SDK integration card
* At least one **published article**

***

1. Install package [#1-install-package]

```bash
npm install @earlyseo/blog
```

2. Add provider [#2-add-provider]

Wrap your app (or the blog section) with `EarlySeoProvider`. This makes the site ID and base path available to all child components.

```tsx
import { EarlySeoProvider } from "@earlyseo/blog/react";

export function AppProviders({ children }: { children: React.ReactNode }) {
  return (
    <EarlySeoProvider siteId="your-site-id" basePath="/blog">
      {children}
    </EarlySeoProvider>
  );
}
```

| Prop       | Type     | Description                                   |
| ---------- | -------- | --------------------------------------------- |
| `siteId`   | `string` | Your EarlySEO site ID (required)              |
| `basePath` | `string` | URL prefix for blog routes (default: `/blog`) |

3. Render built-in components [#3-render-built-in-components]

Use the pre-built components for a zero-config blog UI:

```tsx
import { BlogList, BlogPost, ArticleStyles } from "@earlyseo/blog/react";

// Blog listing page
export function BlogPage() {
  return (
    <>
      <ArticleStyles />
      <BlogList />
    </>
  );
}

// Single article page
export function BlogPostPage({ slug }: { slug: string }) {
  return (
    <>
      <ArticleStyles />
      <BlogPost slug={slug} />
    </>
  );
}
```

| Component       | Description                                 |
| --------------- | ------------------------------------------- |
| `ArticleStyles` | Injects EarlySEO CSS styles into the page   |
| `BlogList`      | Renders a paginated article list with links |
| `BlogPost`      | Renders a single article by slug            |

4. Headless mode with hooks [#4-headless-mode-with-hooks]

Build a fully custom UI using the data hooks:

```tsx
import { useArticles, useArticle } from "@earlyseo/blog/react";

export function CustomList() {
  const { articles, loading } = useArticles();
  if (loading) return <div>Loading...</div>;

  return (
    <div>
      {articles.map((article) => (
        <a key={article.slug} href={`/blog/${article.slug}`}>
          <h3>{article.title}</h3>
          <p>{article.metaDescription}</p>
        </a>
      ))}
    </div>
  );
}

export function CustomPost({ slug }: { slug: string }) {
  const { article, loading } = useArticle(slug);
  if (loading) return <div>Loading...</div>;
  if (!article) return <div>Not found</div>;

  return <div dangerouslySetInnerHTML={{ __html: article.contentRawHtml }} />;
}
```

| Hook               | Returns                 | Description                      |
| ------------------ | ----------------------- | -------------------------------- |
| `useArticles()`    | `{ articles, loading }` | Fetches paginated article list   |
| `useArticle(slug)` | `{ article, loading }`  | Fetches a single article by slug |

***

How publishing works [#how-publishing-works]

1. Publish an article from the EarlySEO dashboard
2. Article data updates automatically
3. Your React app reads the updated data on the next fetch
4. No rebuild or redeploy needed

***

Routing example (React Router) [#routing-example-react-router]

```tsx
import { Routes, Route } from "react-router-dom";

function App() {
  return (
    <EarlySeoProvider siteId="your-site-id" basePath="/blog">
      <Routes>
        <Route path="/blog" element={<BlogPage />} />
        <Route path="/blog/:slug" element={<BlogPostRoute />} />
      </Routes>
    </EarlySeoProvider>
  );
}

function BlogPostRoute() {
  const { slug } = useParams();
  return <BlogPostPage slug={slug!} />;
}
```

***

Troubleshooting [#troubleshooting]

**No content returned**

* Verify your `siteId` is correct
* Confirm the integration type is **SDK** in the dashboard
* Confirm the article status is **published**

**CORS issues**

* EarlySEO handles cross-origin requests automatically — no proxy needed
* If using a custom proxy, ensure CORS headers are set

**Inconsistent styling**

* Always render `<ArticleStyles />` before `<BlogList />` or `<BlogPost />`
* For fully custom styles, use `contentRawHtml` from the hooks and apply your own CSS

***

Need help? [#need-help]

* [SDK Integration Setup](/docs/sdk)
* [Next.js SDK Guide](/docs/next-sdk) (for server-rendered setups)
* [SDK Troubleshooting](/docs/sdk-troubleshooting)
* Email [team@earlyseo.com](mailto:team@earlyseo.com)
