> For the complete documentation index, see [llms.txt](https://staysignal.gitbook.io/staysignal-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://staysignal.gitbook.io/staysignal-docs/integration-guides/nextjs-integration-app-router.md).

# NextJS integration (App Router)

### Next.js Integration (App Router)

Follow these steps to integrate the Staysignal widget into your Next.js application:

#### 1. Create a Client Component Provider

This component handles loading the widget script (using the Site ID in the URL) and initialization. Place it in your root layout.

```typescript

// app/layout.tsx
import { StaySignalWidget } from '@/components/StaySignalWidget'; // Adjust path

export default function RootLayout({ children }: { children: React.ReactNode }) {

  const handleComplete = (payload: any) => { console.log('StaySignal Complete:', payload); };
  const handleError = (error: any) => { console.error('StaySignal Error:', error); };

  return (
    <html lang="en">
      <body>
        {children}
        {/* Render StaySignalWidget - siteId prop is only needed if not loading via /api/widget/script/[siteId] */}
        <StaySignalWidget onComplete={handleComplete} onError={handleError} />
      </body>
    </html>
  );
}
```

#### 2. Create a Cancel Button Component

```typescript
// components/CancelButton.tsx
'use client';

import { useEffect, useRef } from 'react';

interface CancelButtonProps {
  subscriptionId: string;
  className?: string;
  children?: React.ReactNode;
}

export function CancelButton({ subscriptionId, className = '', children }: CancelButtonProps) {
  const buttonRef = useRef<HTMLButtonElement>(null);

  useEffect(() => {
    const button = buttonRef.current;
    if (!button) return;

    button.classList.add('staysignal-cancel');
    button.setAttribute('data-subscription_id', subscriptionId);

    return () => {
      button.classList.remove('staysignal-cancel');
      button.removeAttribute('data-subscription_id');
    };
  }, [subscriptionId]);

  return (
    <button ref={buttonRef} className={className}>
      {children || 'Cancel Subscription'}
    </button>
  );
}
```

#### 3. Use in Your App

```typescript

// app/layout.tsx
import { StaySignalWidget } from '@/components/StaySignalWidget'; // Adjust path

export default function RootLayout({ children }: { children: React.ReactNode }) {

  const handleComplete = (payload: any) => { console.log('StaySignal Complete:', payload); };
  const handleError = (error: any) => { console.error('StaySignal Error:', error); };

  return (
    <html lang="en">
      <body>
        {children}
        {/* Render StaySignalWidget - siteId prop is only needed if not loading via /api/widget/script/[siteId] */}
        <StaySignalWidget onComplete={handleComplete} onError={handleError} />
      </body>
    </html>
  );
}
```

[Learn how to find the Stripe subscription ID](https://app.gitbook.com/o/L1J4IXndMOL7SI7HjRkS/s/vYa98TfDh2GiMvr5EyYo/~/changes/10/basics/integrations/finding-stripe-subscription-ids)

For the Pages Router, the implementation is similar but you would typically initialize the widget in \_app.tsx.

### Need Help?

If you encounter any issues with the integration, please contact our support team or refer to our documentation.
