> ## Documentation Index
> Fetch the complete documentation index at: https://docs.adxensor.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Next.js

> Integrate AdXensor with the Next.js App Router and Pages Router using the npm package, with full TypeScript and SSR support.

AdXensor works with both the **App Router** (Next.js 13+) and the **Pages Router**. Use the npm package for full TypeScript support and SSR compatibility.

## Installation

```bash theme={null}
npm install @adxensor/publisher-sdk
```

## App Router (Next.js 13+)

<Steps>
  <Step title="Create an AdSlot component">
    The SDK manipulates the DOM, so it must run on the client. Create a reusable `AdSlot` component:

    ```tsx theme={null}
    // components/AdSlot.tsx
    'use client';

    import { useEffect, useRef } from 'react';
    import { AdXensor } from '@adxensor/publisher-sdk';

    interface AdSlotProps {
      slot: string;
      format?: string;
      className?: string;
    }

    export function AdSlot({ slot, format = 'auto', className }: AdSlotProps) {
      const ref = useRef<HTMLElement>(null);

      useEffect(() => {
        if (!ref.current) return;

        const adx = AdXensor.getInstance({
          siteId: process.env.NEXT_PUBLIC_ADXENSOR_SITE_ID!,
        });

        adx.init();
        adx.fill(ref.current, { format: format as any });
      }, [slot, format]);

      return (
        <ins
          ref={ref}
          className={`adxensor${className ? ` ${className}` : ''}`}
          style={{ display: 'block' }}
          data-ad-slot={slot}
          data-ad-format={format}
        />
      );
    }
    ```
  </Step>

  <Step title="Add your Site ID to the environment">
    ```bash theme={null}
    # .env.local
    NEXT_PUBLIC_ADXENSOR_SITE_ID=pub-XXXXXXXX
    ```
  </Step>

  <Step title="Use the component in any Server or Client component">
    ```tsx theme={null}
    // app/page.tsx  (Server Component — AdSlot itself is 'use client')
    import { AdSlot } from '@/components/AdSlot';

    export default function HomePage() {
      return (
        <main>
          <h1>Welcome</h1>

          {/* Leaderboard at the top */}
          <AdSlot slot="header-banner" format="728x90" />

          <article>…your content…</article>

          {/* In-content rectangle */}
          <AdSlot slot="in-content" format="300x250" />
        </main>
      );
    }
    ```
  </Step>
</Steps>

## Pages Router (Next.js 12 and below)

<Steps>
  <Step title="Create the AdSlot component">
    Same component as above — the `'use client'` directive is ignored in the Pages Router and has no effect.
  </Step>

  <Step title="Initialize once in _app.tsx">
    ```tsx theme={null}
    // pages/_app.tsx
    import { useEffect } from 'react';
    import type { AppProps } from 'next/app';
    import { AdXensor } from '@adxensor/publisher-sdk';
    import { useRouter } from 'next/router';

    export default function App({ Component, pageProps }: AppProps) {
      const router = useRouter();

      useEffect(() => {
        const adx = AdXensor.getInstance({
          siteId: process.env.NEXT_PUBLIC_ADXENSOR_SITE_ID!,
        });

        adx.init();

        // Re-fill slots after client-side navigation
        const handleRouteChange = () => {
          AdXensor.reset();
          AdXensor.getInstance({
            siteId: process.env.NEXT_PUBLIC_ADXENSOR_SITE_ID!,
          }).init();
        };

        router.events.on('routeChangeComplete', handleRouteChange);
        return () => router.events.off('routeChangeComplete', handleRouteChange);
      }, [router.events]);

      return <Component {...pageProps} />;
    }
    ```
  </Step>

  <Step title="Place slots on any page">
    ```tsx theme={null}
    // pages/index.tsx
    import { AdSlot } from '@/components/AdSlot';

    export default function Home() {
      return (
        <main>
          <AdSlot slot="header-banner" format="728x90" />
          <p>Your content here.</p>
          <AdSlot slot="footer-banner" format="320x50" />
        </main>
      );
    }
    ```
  </Step>
</Steps>

## SPA route changes (App Router)

The App Router handles client-side navigation automatically. If you notice ads not refreshing after navigation, reset the singleton on route changes using the `usePathname` hook:

```tsx theme={null}
// components/AdXensorProvider.tsx
'use client';

import { useEffect } from 'react';
import { usePathname } from 'next/navigation';
import { AdXensor } from '@adxensor/publisher-sdk';

export function AdXensorProvider({ children }: { children: React.ReactNode }) {
  const pathname = usePathname();

  useEffect(() => {
    AdXensor.reset();
    AdXensor.getInstance({
      siteId: process.env.NEXT_PUBLIC_ADXENSOR_SITE_ID!,
    }).init();
  }, [pathname]);

  return <>{children}</>;
}
```

Mount it in your root `layout.tsx`:

```tsx theme={null}
// app/layout.tsx
import { AdXensorProvider } from '@/components/AdXensorProvider';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <AdXensorProvider>
          {children}
        </AdXensorProvider>
      </body>
    </html>
  );
}
```

## TypeScript types

```typescript theme={null}
import type { AdFormat } from '@adxensor/publisher-sdk';

const format: AdFormat = '300x250';
```

## Environment variables

| Variable                       | Description                   |
| ------------------------------ | ----------------------------- |
| `NEXT_PUBLIC_ADXENSOR_SITE_ID` | Your Site ID (`pub-XXXXXXXX`) |

Because it is prefixed with `NEXT_PUBLIC_`, it is exposed to the browser. This is intentional — the Site ID is not a secret.

## Full configuration options

```typescript theme={null}
AdXensor.getInstance({
  siteId:   'pub-XXXXXXXX', // required
  apiKey:   'YOUR_KEY',     // optional — for authenticated publishers
  lazyLoad: true,           // default: true
  debug:    false,          // enables console logs
});
```

## Troubleshooting

| Symptom                           | Solution                                                                                              |
| --------------------------------- | ----------------------------------------------------------------------------------------------------- |
| Slots remain blank                | Check that `NEXT_PUBLIC_ADXENSOR_SITE_ID` is set and the site is approved in the dashboard            |
| Duplicate ads on navigation       | Use `AdXensor.reset()` before re-initializing on route change                                         |
| `window is not defined` SSR error | Ensure the component has `'use client'` and uses `useEffect` — never call SDK methods at module level |

→ [Full troubleshooting guide](/publishers/support/troubleshooting)
