AverageDevs
BillingNext.js

How to Get AdSense Approval for a Next.js Website (Step‑by‑Step)

A complete, actionable guide to getting Google AdSense approval on a Next.js site - prerequisites, policy checks, ads.txt, consent mode, code integration, and troubleshooting.

How to Get AdSense Approval for a Next.js Website (Step‑by‑Step)

Getting approved for Google AdSense is less about inserting a script and more about proving your site is high‑quality, policy‑compliant, and technically sound. This guide focuses on the concrete steps that matter for a Next.js (App Router) site - from content and policy prep to ads.txt, Consent Mode v2, and production‑safe code snippets.

TL;DR

  • Have quality content first: 10–15 solid posts/pages, unique, helpful, and original.
  • Ship required pages: About, Contact, Privacy Policy, Terms; clear navigation; no broken pages.
  • Make it crawlable: No noindex, working robots, sitemap, fast Core Web Vitals, mobile‑friendly.
  • Publish ads.txt and set Consent Mode v2. Wait 24–72 hours for propagation.
  • Add the AdSense script site‑wide using next/script. Use a client‑only ad unit.
  • Submit the site in AdSense and keep it online while under review (1–14 days typical).

1) Eligibility and Policy Checklist

Before you apply, verify these:

  • Original, human‑written content; no AI spam, no mass‑generated or scraped content.
  • Clear site purpose and niche; value beyond directory/aggregator pages.
  • Minimum viable content footprint: 10–15 high‑quality posts/pages with internal links.
  • Required pages: About, Contact, Privacy Policy (must disclose AdSense/ads), Terms.
  • Clean UX: readable typography, contrast, consistent navigation, functional search.
  • Technical quality: fast (Core Web Vitals), responsive, accessible; no broken links.
  • Policy‑safe: no prohibited content (adult, illegal, pirated, dangerous, clickbait/encouragement to click ads, etc.).

2) Technical SEO + Crawlability (Next.js)

  • Ensure production pages do not use noindex. In the App Router, you typically control bots via app/robots.ts. Keep index: true for public sections and ensure important pages are discoverable from your homepage.
  • Provide a sitemap (Next.js supports app/sitemap.ts) and submit it in Google Search Console.
  • Remove placeholder lorem ipsum, “coming soon” pages, and thin tag/category pages before applying.
  • Fix all client and server errors (404/500), and keep redirects clean.

3) Add ads.txt (required)

Google strongly recommends an ads.txt file to declare authorized sellers. This reduces policy warnings and speeds up monetization accuracy.

Place ads.txt at the site root (https://yourdomain.com/ads.txt). Easiest: add it to public/ads.txt in your Next.js app.

google.com, pub-0000000000000000, DIRECT, f08c47fec0942fa0
  • Replace pub-0000000000000000 with your own AdSense Publisher ID (format ca-pub-XXXXXXXXXXXXXXX → use the numeric part only if required by your network; AdSense accepts ca-pub-... form in many cases, but Google’s canonical example uses the numeric pub-...).
  • It can take 24–72 hours for ads.txt to propagate and warnings to clear.

If any traffic comes from the EEA/UK, you must implement Consent Mode v2 and use a CMP or your own consent UI. A minimal default‑denied setup in Next.js (update to granted after user consent):

// app/layout.tsx (excerpt)
import Script from "next/script";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <Script id="consent-default" strategy="beforeInteractive">
          {`
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('consent', 'default', {
              ad_storage: 'denied',
              ad_user_data: 'denied',
              ad_personalization: 'denied',
              analytics_storage: 'denied'
            });
          `}
        </Script>
        {children}
      </body>
    </html>
  );
}

When a user grants consent in your CMP, update consent to granted at runtime:

// somewhere in your consent banner handler
export const grantAdsConsent = () => {
  // @ts-expect-error dataLayer injected globally
  window.gtag?.('consent', 'update', {
    ad_storage: 'granted',
    ad_user_data: 'granted',
    ad_personalization: 'granted',
    analytics_storage: 'granted',
  });
};

Use a Google‑certified CMP if you serve EEA/UK. Always reflect the user’s choice accurately.

5) Load AdSense globally (Next.js App Router)

AdSense requires loading its script site‑wide. Use next/script with your client ID.

// app/layout.tsx (excerpt)
import Script from "next/script";

const ADSENSE_CLIENT_ID = process.env.NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID; // e.g., "ca-pub-1234567890123456"

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {ADSENSE_CLIENT_ID ? (
          <Script
            id="adsense-loader"
            strategy="afterInteractive"
            src={`https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${ADSENSE_CLIENT_ID}`}
            crossOrigin="anonymous"
          />
        ) : null}
        {children}
      </body>
    </html>
  );
}

Add your variable to .env.local and restart your dev server:

# .env.local
NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID=ca-pub-1234567890123456

6) Create a safe, reusable AdSense unit (client component)

Use a client component to render ad slots without SSR issues. This pattern prevents hydration mismatches and retries gracefully.

// components/adsense-unit.tsx
"use client";
import { useEffect, useMemo, useRef } from "react";

const ADSENSE_CLIENT_ID = process.env.NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID ?? "";

/**
 * Renders a single AdSense slot. Use different slots (data-ad-slot) from your AdSense account.
 * Place this component in content pages with meaningful spacing and labels.
 */
export type AdSenseUnitProps = {
  slotId: string; // e.g., "1234567890" from your AdSense ad unit
  className?: string;
  format?: "auto" | "fluid";
  fullWidthResponsive?: boolean;
};

export const AdSenseUnit = ({
  slotId,
  className,
  format = "auto",
  fullWidthResponsive = true,
}: AdSenseUnitProps) => {
  const insRef = useRef<HTMLModElement | null>(null);
  const isReady = useMemo(() => typeof window !== "undefined" && !!ADSENSE_CLIENT_ID, []);

  useEffect(() => {
    if (!isReady || !insRef.current) return;
    try {
      // @ts-expect-error injected by AdSense script
      (window.adsbygoogle = window.adsbygoogle || []).push({});
    } catch (err) {
      // swallow errors to avoid breaking the page; AdSense may retry
      console.error("AdSense push error", err);
    }
  }, [isReady]);

  if (!ADSENSE_CLIENT_ID) return null;

  return (
    <div aria-label="Advertisement" role="complementary" className={className}>
      <ins
        ref={insRef as any}
        className="adsbygoogle"
        style={{ display: "block" }}
        data-ad-client={ADSENSE_CLIENT_ID}
        data-ad-slot={slotId}
        data-ad-format={format}
        data-full-width-responsive={fullWidthResponsive ? "true" : "false"}
      />
    </div>
  );
};

Usage example in a page or MDX mapping:

// Example usage in a React page
import { AdSenseUnit } from "@/components/adsense-unit";

export const ArticleWithAds = () => {
  return (
    <article className="prose mx-auto">
      <h1>My Great Article</h1>
      <p>Intro content…</p>
      <AdSenseUnit slotId="1234567890" className="my-8" />
      <p>More content…</p>
    </article>
  );
};

Notes:

  • Mark ad containers with accessible labels. Keep ad density reasonable and avoid placing ads too close to interactive elements.
  • Each ad unit has its own slotId from your AdSense dashboard.

7) Submit for AdSense review

  1. Create/Sign in to AdSense and add your site domain.
  2. Ensure ads.txt is live and your site is indexable with solid content and legal pages.
  3. Install the global AdSense script in app/layout.tsx.
  4. Place at least one ad unit in a visible area on a few content pages.
  5. Submit for review and keep the site online; avoid large changes during review.

Typical review time: 1–14 days. If denied, you can re‑apply after fixing issues.

8) Common rejection reasons and fixes

  • Insufficient content / value: Publish deeper posts (1000–2000+ words), add visuals, fix internal linking.
  • Site under construction: Remove “coming soon”, complete navigation, ensure no 404s.
  • Policy violations: Remove prohibited content, mature content, click‑bait, or encouragement to click ads.
  • Low quality or scraped content: Replace with original work; cite sources; add author info and E‑E‑A‑T signals.
  • Poor UX / slow pages: Improve Core Web Vitals, image optimization, font loading, and mobile layout.
  • Domain or ownership issues: Verify domain in Search Console; ensure www and apex both resolve.
  • ads.txt warnings: Publish ads.txt at the root and wait 24–72 hours.

9) Production hygiene and best practices

  • Store IDs in env vars (e.g., NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID). Never hardcode in components.
  • Use a CMP to manage Consent Mode v2; set default denied and update after explicit consent.
  • Don’t render ads on pages where they degrade UX (e.g., checkout) - gate rendering by route.
  • Avoid showing ads to logged‑in admins while editing (simple user guard).
  • Keep ad placements stable; moving them frequently can delay learning and reduce RPM.

10) Quick pre‑submission checklist

  • Original content with real value; 10–15+ solid posts.
  • Clean navigation; About, Contact, Privacy, Terms live.
  • No noindex; sitemap submitted; no broken links.
  • Core Web Vitals within good thresholds; mobile responsive.
  • ads.txt live at /ads.txt and valid.
  • Consent Mode v2 implemented (EEA/UK).
  • AdSense script installed; at least one visible ad unit placed.

FAQ

How long does approval take? 1–14 days typically; can be faster or slower. Keep the site stable and online.

Can I apply without many posts? You can, but approval odds are much higher with a meaningful content base and a clear site purpose.

Do I need traffic first? Not strictly, but some organic traffic and indexed pages help demonstrate value and compliance.

Will ads.txt errors block approval? Not always, but fixing them reduces warnings and improves monetization quality once approved.


If you follow the content, policy, and technical steps above, AdSense approval for a Next.js site becomes straightforward. Focus on value, keep the site clean and fast, implement ads.txt and Consent Mode correctly, and place ad units conservatively to start.