Skip to content
Ranqo
Docs
DashboardGet started
GuidesMethodologyIntegrations
Video tutorials

Overview

  • Integrations

Analytics

  • Google Analytics 4

Publishing

  • WordPress

Site Tracking

  • Site Tracking
  • Next.js
  • Express
  • Cloudflare Worker
  • Any backend
  • Verify
  • Site keys
  • Intake API
  • Privacy

2 sections

Site Tracking

Site Tracking for Next.js

View as MarkdownOpen this page as .md
ChatGPTOpen in ChatGPTAsk about this pageClaudeOpen in ClaudeAsk about this page

Send AI crawler visits and AI referrals from a Next.js site to Ranqo with one middleware file. Works on Next.js 15 and 16.

Ranqo's Site Tracking sees every request your server handles, including the AI crawlers that never run JavaScript and so never reach GA4. On Next.js it is one middleware file.

  1. Copy your site key

    Open Traffic in the dashboard and choose Set up Site Tracking. Select Generate site key, then copy the key. Keys start with rk_live_.

  2. Add the key to your environment

    .env
    RANQO_SITE_KEY=rk_live_YOUR_SITE_KEY

    Set it in your hosting provider's environment variables too, for every environment you want tracked.

  3. Add the middleware

    Create middleware.ts at the root of your project, next to app/ or pages/. On Next.js 16, name the file proxy.ts and the function proxy.

    middleware.ts
    // middleware.ts (Next.js 15) — or proxy.ts (Next.js 16, rename function to `proxy`)
    import { NextRequest, NextResponse } from 'next/server';
    
    // OPTIONAL: skip self-tracking on subdomains you don't want counted as
    // "marketing site visitors" (e.g. your authenticated dashboard on
    // app.yoursite.com). Most teams can leave this empty.
    const SKIP_HOSTS = new Set<string>([
      // 'app.yoursite.com',
      // 'admin.yoursite.com',
    ]);
    
    export function middleware(request: NextRequest) {
      // Only track GET. POST/PUT/DELETE/HEAD/OPTIONS never represent a page view.
      if (request.method !== 'GET') return NextResponse.next();
    
      // CRITICAL — skip Next.js prefetch / RSC requests. Without these checks,
      // every <Link> hover fires a fake page view; traffic inflates 5-10x.
      const secFetchDest = request.headers.get('sec-fetch-dest');
      if (secFetchDest && secFetchDest !== 'document') return NextResponse.next();
      if (request.headers.get('next-router-prefetch')) return NextResponse.next();
      if (request.headers.get('next-router-segment-prefetch')) return NextResponse.next();
      if (request.headers.get('rsc') === '1') return NextResponse.next();
      const secPurpose = request.headers.get('sec-purpose');
      if (secPurpose && secPurpose.startsWith('prefetch')) return NextResponse.next();
      if (request.headers.get('purpose') === 'prefetch') return NextResponse.next();
    
      const { pathname } = request.nextUrl;
      if (pathname.startsWith('/api/')) return NextResponse.next();
      if (SKIP_HOSTS.has(request.headers.get('host') || '')) return NextResponse.next();
    
      const params = new URLSearchParams({
        url: request.url,
        userAgent: request.headers.get('user-agent') || '',
        ref: request.headers.get('referer') || '',
        ip: request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() || '',
        websiteKey: process.env.RANQO_SITE_KEY!,
      });
    
      fetch(`https://app.ranqo.ai/api/v1/intake/pageview?${params}`).catch(() => {});
      return NextResponse.next();
    }
    
    // AI-discovery files (robots.txt, llms.txt, sitemap.xml, .well-known/*) are
    // the highest-signal hits — allowlist them above the static-asset skip rule.
    export const config = {
      matcher: [
        '/robots.txt',
        '/llms.txt',
        '/llms-full.txt',
        '/sitemap.xml',
        '/sitemap-:path*',
        '/ai.txt',
        '/.well-known/:path*',
        '/((?!api|_next/static|_next/image|favicon.ico|manifest.webmanifest|.*\\.(?:png|jpg|jpeg|svg|gif|webp|ico|css|js|mjs|map|woff2?|ttf|otf|eot|txt|xml|json)$).*)',
      ],
    };
  4. Deploy and verify

    Deploy, then run the check in Verify your install. The install page in the dashboard also watches for your first real visit and confirms it when it arrives.

What the middleware does#

  • Never slows your pages. The call to Ranqo is fired without waiting for an answer, so it adds no latency.
  • Counts page views only. It skips POST requests, API routes, and the prefetch and RSC requests Next.js makes when a visitor hovers a link. Without those checks, a site's traffic reads five to ten times higher than it is.
  • Keeps the files AI crawlers read first. robots.txt, llms.txt, sitemap.xml and /.well-known/* are the highest-signal requests an AI crawler makes, so the matcher lets them through ahead of the static-file rule.
  • Skips images, fonts, scripts and styles, which are noise.
Note: Dashboard on the same project?

If your authenticated app is served from the same Next.js project on another subdomain, add that host to SKIP_HOSTS at the top of the file so your own team's clicks are not counted as marketing traffic.

Next steps#

Verify your install

Send a test event and confirm Ranqo accepted it.

How Ranqo classifies visits

AI crawlers, AI assistants and human referrals, and how each is told apart.
Previous page: Site TrackingNext page: Express
On this page
Ranqo
Docs
Dashboardranqo.aiPrivacyTerms
Be the Source AI Cites.
Ranqo
Docs
GuidesMethodologyIntegrations

Overview

  • Integrations

Analytics

  • Google Analytics 4

Publishing

  • WordPress

Site Tracking

  • Site Tracking
  • Next.js
  • Express
  • Cloudflare Worker
  • Any backend
  • Verify
  • Site keys
  • Intake API
  • Privacy
Get started