RoosterDocs
Rooster Docs
Installation
Integrations
Examples
Plain HTMLNext.js App RouterReact SPAVue 3SvelteKitWebflowWixWordPressFramerSquarespace
Troubleshooting
HomeApp
Rooster Docs
RoosterDocs
Rooster Docs
Installation
Integrations
Examples
Plain HTMLNext.js App RouterReact SPAVue 3SvelteKitWebflowWixWordPressFramerSquarespace
Troubleshooting
HomeApp
Docs/Next.js App Router

Next.js App Router

Install Rooster in Next.js with `next/script` and route-scoped form collection.

Analytics Only

Put analytics in app/layout.tsx when you want Rooster to track every route and enforce page-level bot protection globally.

import Script from "next/script";
 
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Script src="https://api.rooster.host/analytics/YOUR_PUBLIC_KEY.js" strategy="afterInteractive" />
      </body>
    </html>
  );
}

Collect Every Form

Only put the form collector in the layout when every public form in the app should be collected.

import Script from "next/script";
 
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Script src="https://api.rooster.host/analytics/YOUR_PUBLIC_KEY.js" strategy="afterInteractive" />
        <Script src="https://rooster.ink/embed/YOUR_PUBLIC_KEY.js" strategy="afterInteractive" />
      </body>
    </html>
  );
}

Then map each form to a Rooster form group.

export function NewsletterForm() {
  return (
    <form data-rooster-form="default">
      <input name="email" type="email" required />
      <button type="submit">Subscribe</button>
    </form>
  );
}

Collect One Route Form

Use this when the collector should only run on one route, such as /contact.

import Script from "next/script";
 
export default function ContactPage() {
  return (
    <>
      <Script
        src="https://rooster.ink/embed/YOUR_PUBLIC_KEY.js"
        data-rooster-form="support"
        strategy="afterInteractive"
      />
 
      <form data-rooster-form="support">
        <input name="email" type="email" required />
        <textarea name="message" required />
        <button type="submit">Send</button>
      </form>
    </>
  );
}

Multi-Stage Form

The form collector saves partial progress when a visitor clicks a data-rooster-continue button.

"use client";
 
import { useState } from "react";
import Script from "next/script";
 
export default function DemoRequestPage() {
  const [step, setStep] = useState(1);
 
  return (
    <>
      <Script
        src="https://rooster.ink/embed/YOUR_PUBLIC_KEY.js"
        data-rooster-form="sales"
        strategy="afterInteractive"
      />
 
      <form data-rooster-form="sales">
        {step === 1 ? (
          <section>
            <input name="work_email" type="email" required />
            <button type="button" data-rooster-continue onClick={() => setStep(2)}>
              Next
            </button>
          </section>
        ) : null}
 
        {step === 2 ? (
          <section>
            <select name="company_size" defaultValue="11-50">
              <option>1-10</option>
              <option>11-50</option>
              <option>51-200</option>
            </select>
            <button type="button" data-rooster-continue onClick={() => setStep(3)}>
              Next
            </button>
          </section>
        ) : null}
 
        {step === 3 ? (
          <section>
            <textarea name="project_notes" />
            <button type="submit" data-rooster-continue data-rooster-final="true">
              Submit
            </button>
          </section>
        ) : null}
      </form>
    </>
  );
}
PreviousPlain HTMLNextReact SPA

On this page

Analytics OnlyCollect Every FormCollect One Route FormMulti-Stage Form