Skip to content

stubbies/next-ai-shield

Repository files navigation

next-ai-shield

Shield specific UI components or entire routes from LLM scrapers with zero hydration mismatches and built-in fallback support.

Install

npm i next-ai-shield

What you get

  • isAIBot(userAgent): small utility for Next.js Middleware (or anywhere).
  • AI_BOTS: the default bot list (exported for reuse/extension).
  • <ShieldRegistry>: a Server Component that reads user-agent via next/headers and provides isBlocked to Client Components via context.
  • <Shield fallback> / <ServerShield fallback> / <ClientShield fallback>:
    • In Server Components, Shield resolves to the server implementation.
    • In Client Components, Shield resolves to the client implementation (reading from context).
  • Pages Router helpers (import from next-ai-shield/pages):
    • withShieldGetServerSideProps() to inject pageProps.aiShield.isBlocked.
    • getUserAgentFromReq() / getIsBlockedFromReq() utilities.

App Router usage

1) Wrap your app once (recommended)

app/layout.tsx (Server Component):

import { ShieldRegistry } from 'next-ai-shield';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <ShieldRegistry>{children}</ShieldRegistry>
      </body>
    </html>
  );
}

2) Use Shield in Server Components

app/page.tsx (Server Component):

import { Shield } from 'next-ai-shield';

export default function Page() {
  return (
    <Shield fallback={<p>Protected</p>}>
      <div>Secret server content</div>
    </Shield>
  );
}

3) Use Shield in Client Components

app/secret/ClientThing.tsx:

'use client';

import { Shield } from 'next-ai-shield';

export function ClientThing() {
  return (
    <Shield fallback={<p>Protected</p>}>
      <button>Secret client content</button>
    </Shield>
  );
}

Customizing detection (override/extend/whitelist)

All detection uses case-insensitive substring matching against a bot list.

Extend the default list

import { isAIBot } from 'next-ai-shield';

isAIBot(userAgent, { extendBots: ['MyCustomBot'] });

Override the list entirely

import { AI_BOTS, isAIBot } from 'next-ai-shield';

isAIBot(userAgent, { bots: [...AI_BOTS, 'MyCustomBot'] });

Whitelist specific bots (allowed)

If you want a known bot to be allowed, put it in allowBots.

import { isAIBot } from 'next-ai-shield';

// Claude-Web will NOT be blocked, but other bots still will be.
isAIBot(userAgent, { allowBots: ['Claude-Web'] });

Pages Router usage

Pages Router doesn’t have next/headers, so use next-ai-shield/pages to detect on the server and pass a flag into pageProps.

1) Wrap _app once

pages/_app.tsx:

import type { AppProps } from 'next/app';
import { ShieldProvider } from 'next-ai-shield';
import type { AiShieldPageProps } from 'next-ai-shield/pages';

export default function App({ Component, pageProps }: AppProps<AiShieldPageProps>) {
  const isBlocked = pageProps.aiShield?.isBlocked ?? false;

  return (
    <ShieldProvider isBlocked={isBlocked}>
      <Component {...pageProps} />
    </ShieldProvider>
  );
}

2) Add getServerSideProps per page

pages/secret.tsx:

import { Shield } from 'next-ai-shield';
import { withShieldGetServerSideProps } from 'next-ai-shield/pages';

export const getServerSideProps = withShieldGetServerSideProps(async () => {
  return { props: {} };
});

export default function SecretPage() {
  return (
    <Shield fallback={<p>Protected</p>}>
      <div>Secret content</div>
    </Shield>
  );
}

Notes

  • getStaticProps cannot reliably detect bots (there’s no per-request user-agent), so it will not block.
  • Pages Router users should not use ShieldRegistry (it is App Router / Server Components only).

Pages Router: allow/extend/override

import { withShieldGetServerSideProps } from 'next-ai-shield/pages';

export const getServerSideProps = withShieldGetServerSideProps(
  async () => ({ props: {} }),
  { allowBots: ['Claude-Web'], extendBots: ['MyCustomBot'] }
);

Middleware example

middleware.ts:

import { NextResponse, type NextRequest } from 'next/server';
import { isAIBot } from 'next-ai-shield';

export function middleware(req: NextRequest) {
  const ua = req.headers.get('user-agent');
  if (isAIBot(ua, { allowBots: ['Claude-Web'] })) {
    const url = req.nextUrl.clone();
    url.pathname = '/protected';
    return NextResponse.rewrite(url);
  }
  return NextResponse.next();
}

export const config = {
  matcher: ['/((?!_next/static|_next/image|favicon.ico).*)']
};

About

The easiest way to protect your Next.js content from AI crawlers. Shield specific UI components or entire routes from LLM scrapers with zero hydration mismatches and built-in fallback support.

Topics

Resources

License

Stars

Watchers

Forks

Contributors