← ClerkCONTENT HISTORYWHAT CHANGED · RULE-BASED ANALYSIS
Update to Clerk
Snapshot Sep 30, 2026 · 23:09 UTC · version 0.1.0
Collection source: not recorded for this historical snapshot.
First saved snapshot
No earlier snapshot is available to establish a change.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"name": "clerk-react-patterns",
"description": "React SPA auth patterns with @clerk/react for Vite/CRA - ClerkProvider setup, useAuth/useUser/useClerk hooks, React Router protected routes, custom sign-in flows. Triggers on: Vite Clerk setup, React Router auth, useAuth hook, protected route, custom sign-in form React.",
"included_files": [
{
"relative_path": "evals/evals.json",
"size_in_bytes": 4586
},
{
"relative_path": "references/custom-flows.md",
"size_in_bytes": 2741
},
{
"relative_path": "references/hooks.md",
"size_in_bytes": 2366
},
{
"relative_path": "references/protected-routes.md",
"size_in_bytes": 2230
},
{
"relative_path": "references/router-integration.md",
"size_in_bytes": 2084
},
{
"relative_path": "templates/react-basic-auth/index.html",
"size_in_bytes": 300
},
{
"relative_path": "templates/react-basic-auth/package.json",
"size_in_bytes": 429
},
{
"relative_path": "templates/react-basic-auth/src/App.tsx",
"size_in_bytes": 310
},
{
"relative_path": "templates/react-basic-auth/src/main.tsx",
"size_in_bytes": 288
},
{
"relative_path": "templates/react-basic-auth/tsconfig.json",
"size_in_bytes": 234
},
{
"relative_path": "templates/react-basic-auth/vite.config.ts",
"size_in_bytes": 132
}
],
"skill_md_contents": "---\nname: clerk-react-patterns\ndescription: 'React SPA auth patterns with @clerk/react for Vite/CRA - ClerkProvider\n setup, useAuth/useUser/useClerk hooks, React Router protected routes, custom sign-in\n flows. Triggers on: Vite Clerk setup, React Router auth, useAuth hook, protected\n route, custom sign-in form React.'\nlicense: MIT\nallowed-tools: WebFetch\nmetadata:\n author: clerk\n version: 1.0.0\n---\n\n# React SPA Patterns\n\n> This skill covers `@clerk/react` for Vite/CRA SPAs. For Next.js use `clerk-nextjs-patterns`. For TanStack Start use `clerk-tanstack-patterns`.\n\n## What Do You Need?\n\n| Task | Reference |\n|------|-----------|\n| useAuth / useUser / useClerk hooks | references/hooks.md |\n| Protected routes with React Router | references/protected-routes.md |\n| Custom sign-in / sign-up forms | references/custom-flows.md |\n| React Router v6/v7 integration | references/router-integration.md |\n\n## References\n\n| Reference | Description |\n|-----------|-------------|\n| `references/hooks.md` | useAuth, isLoaded guard |\n| `references/protected-routes.md` | ProtectedRoute pattern |\n| `references/custom-flows.md` | useSignIn, useSignUp flows |\n| `references/router-integration.md` | React Router v6/v7 setup |\n\n## Setup\n\n```\nnpm install @clerk/react\n```\n\n`.env`:\n```\nVITE_CLERK_PUBLISHABLE_KEY=pk_...\n```\n\n`src/main.tsx`:\n```tsx\nimport { StrictMode } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport { ClerkProvider } from '@clerk/react'\nimport App from './App.tsx'\n\nconst PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY\n\ncreateRoot(document.getElementById('root')!).render(\n <StrictMode>\n <ClerkProvider publishableKey={PUBLISHABLE_KEY}>\n <App />\n </ClerkProvider>\n </StrictMode>,\n)\n```\n\n## Mental Model\n\n`@clerk/react` is client-only — there is no server-side `auth()`. All auth state comes from hooks.\n\n- `isLoaded` must be `true` before trusting `isSignedIn` — always guard on `isLoaded`\n- `useClerk()` gives access to `signOut`, `openSignIn`, `openUserProfile` and other methods\n- `getToken()` from `useAuth()` fetches the session JWT for API calls\n\n## Minimal Pattern\n\n```tsx\nimport { useAuth } from '@clerk/react'\n\nexport function Dashboard() {\n const { isLoaded, isSignedIn, userId } = useAuth()\n\n if (!isLoaded) return <div>Loading...</div>\n if (!isSignedIn) return <div>Please sign in</div>\n\n return <div>Hello {userId}</div>\n}\n```\n\n## Protected Route (React Router v6/v7)\n\n```tsx\nimport { Navigate, Outlet } from 'react-router-dom'\nimport { useAuth } from '@clerk/react'\n\nexport function ProtectedRoute() {\n const { isLoaded, isSignedIn } = useAuth()\n\n if (!isLoaded) return <div>Loading...</div>\n if (!isSignedIn) return <Navigate to=\"/sign-in\" replace />\n\n return <Outlet />\n}\n```\n\n```tsx\n<Routes>\n <Route element={<ProtectedRoute />}>\n <Route path=\"/dashboard\" element={<Dashboard />} />\n <Route path=\"/settings\" element={<Settings />} />\n </Route>\n <Route path=\"/sign-in\" element={<SignIn />} />\n</Routes>\n```\n\n## Token for API Calls\n\n```tsx\nimport { useAuth } from '@clerk/react'\n\nexport function DataFetcher() {\n const { getToken } = useAuth()\n\n async function fetchData() {\n const token = await getToken()\n if (!token) return\n\n const res = await fetch('/api/data', {\n headers: { Authorization: `Bearer ${token}` },\n })\n return res.json()\n }\n\n return <button onClick={fetchData}>Load</button>\n}\n```\n\n## Common Pitfalls\n\n| Symptom | Cause | Fix |\n|---------|-------|-----|\n| `isSignedIn` is `undefined` | `isLoaded` is still `false` | Always check `isLoaded` first |\n| `ClerkProvider` missing | Provider not at root | Wrap `<App>` in `main.tsx` |\n| Env var undefined | Wrong Vite prefix | Use `VITE_CLERK_PUBLISHABLE_KEY`, access via `import.meta.env` |\n| Token is `null` | User not signed in | Null-check `getToken()` result |\n| Sign-in component shows blank | No `publishableKey` on provider | Pass `publishableKey` explicitly |\n\n## See Also\n\n- `clerk-setup` - Initial Clerk install\n- `clerk-custom-ui` - Custom flows & appearance\n- `clerk-orgs` - B2B organizations\n\n## Docs\n\n[React SDK](https://clerk.com/docs/react/getting-started/quickstart)\n"
}SHA-256: 7a4c1d6200bcadcfc9dfa63ce5c0e8e8431a1c6221be8a4fdb5628043631c887