SDK & Export API

Next.js Integration

Last updated June 4, 2026

Next.js Integration

The cleanest way to use the SDK in Next.js App Router is from Server Components: the API key stays on the server, the body HTML renders without a client bundle, and you get fetch caching for free.

Keep the key in env

Use a server-only variable (no NEXT_PUBLIC_ prefix) so the key is never shipped to the browser:

RANKHIKER_API_KEY=rh_export_...

Server code does not strictly need the www baseUrl, but it is the safest default, so the examples set it.

Shared client

ts
// lib/rankhiker.ts
import { createClient } from '@rankhiker/sdk';

export const rh = createClient({ apiKey: process.env.RANKHIKER_API_KEY!, baseUrl: 'https://rankhiker.com', requestInit: { next: { revalidate: 300 } }, // ISR: refresh every 5 minutes });

To opt a client out of caching entirely, use requestInit: { cache: 'no-store' } instead.

Blog index: app/blog/page.tsx

tsx
import Link from 'next/link';
import { rh } from '@/lib/rankhiker';

export default async function BlogPage() { const posts = await rh.listArticles({ limit: 20 });

return ( <ul> {posts.map((post) => ( <li key={post.id}> <Link href={/blog/${post.slug}}>{post.title}</Link> </li> ))} </ul> ); }

Article page: app/blog/[slug]/page.tsx

getArticleBySlug returns null on a 404, which pairs naturally with Next.js notFound().

tsx
import { notFound } from 'next/navigation';
import type { Metadata } from 'next';
import { rh } from '@/lib/rankhiker';

export async function generateStaticParams() { const posts = await rh.listArticles({ limit: 1000 }); return posts.map((post) => ({ slug: post.slug })); }

export async function generateMetadata({ params, }: { params: Promise<{ slug: string }>; }): Promise<Metadata> { const { slug } = await params; const post = await rh.getArticleBySlug(slug); if (!post) return {}; return { title: post.title, description: post.metaDescription || post.excerpt, openGraph: post.featuredImage ? { images: [post.featuredImage] } : undefined, }; }

export default async function ArticlePage({ params, }: { params: Promise<{ slug: string }>; }) { const { slug } = await params; const post = await rh.getArticleBySlug(slug); if (!post) notFound();

return ( <article> <h1>{post.title}</h1> <div dangerouslySetInnerHTML={{ __html: post.content }} /> </article> ); }

generateStaticParams pre-renders each article at build time, and generateMetadata fills in per-article SEO tags. The requestInit: { next: { revalidate } } on the shared client controls how often the data refreshes.

When to use the React client adapter

Server Components cannot use hooks. Reach for @rankhiker/sdk/react (the provider, useArticles, useArticle, , ) when you need client-side behavior: live filtering, infinite scroll, or rendering inside an existing client component. Those pieces are 'use client', so they run in the browser and you should pass a NEXT_PUBLIC_ key (the default apex baseUrl works in the browser as-is). For static or server-rendered blogs, the Server Component approach above is simpler and keeps the key private.

Was this article helpful?