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 Cloudflare Workers

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 to Ranqo from a Cloudflare Worker in front of your site, whatever the site itself runs on.

If your site's traffic passes through Cloudflare, a Worker can report every page request to Ranqo without touching the site's own code. The Worker forwards each request to your site as usual and sends the report in the background.

  1. Copy your site key

    On the Traffic page, press Set up Site Tracking, then Generate site key on the Install Site Tracking page. Copy the key. It starts with rk_live_.

  2. Store the key as a secret

    The Worker reads the key from env.RANQO_SITE_KEY. Add it as an encrypted secret rather than a plain variable, from your Worker's settings in the Cloudflare dashboard or with Wrangler:

    Terminal
    npx wrangler secret put RANQO_SITE_KEY
  3. Add the Worker

    worker.ts
    // worker.ts — wire to your route in wrangler.toml
    const SKIP_EXT = /\.(png|jpg|jpeg|svg|gif|webp|ico|css|js|mjs|map|woff2?|ttf|otf|eot|txt|xml|json)$/i;
    const TRACK_AI = /^\/(robots\.txt|llms(-full)?\.txt|sitemap(-.*)?\.xml|ai\.txt|\.well-known\/.*)$/;
    
    // OPTIONAL: skip self-tracking on subdomains you don't want counted as
    // "marketing site visitors" (e.g. your authenticated dashboard).
    const SKIP_HOSTS = new Set<string>([
      // 'app.yoursite.com',
      // 'admin.yoursite.com',
    ]);
    
    export interface Env { RANQO_SITE_KEY: string }
    
    export default {
      async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
        const url = new URL(request.url);
        const path = url.pathname;
    
        // Only GET is a page view. Skip non-GET and any prefetch / RSC
        // request (Next.js apps behind a Worker would otherwise inflate).
        const secFetchDest = request.headers.get('sec-fetch-dest');
        const secPurpose = request.headers.get('sec-purpose');
        const isPrefetch =
          request.method !== 'GET' ||
          (secFetchDest && secFetchDest !== 'document') ||
          !!request.headers.get('next-router-prefetch') ||
          !!request.headers.get('next-router-segment-prefetch') ||
          request.headers.get('rsc') === '1' ||
          (secPurpose && secPurpose.startsWith('prefetch')) ||
          request.headers.get('purpose') === 'prefetch';
    
        const shouldTrack =
          !isPrefetch &&
          !path.startsWith('/api/') &&
          !SKIP_HOSTS.has(url.host) &&
          (TRACK_AI.test(path) || !SKIP_EXT.test(path));
    
        if (shouldTrack) {
          const params = new URLSearchParams({
            url: request.url,
            userAgent: request.headers.get('user-agent') || '',
            ref: request.headers.get('referer') || '',
            ip: request.headers.get('cf-connecting-ip') || '',
            websiteKey: env.RANQO_SITE_KEY,
          });
          // waitUntil keeps the fetch alive after we return the response.
          ctx.waitUntil(fetch(`https://app.ranqo.ai/api/v1/intake/pageview?${params}`).catch(() => {}));
        }
    
        return fetch(request);
      },
    };

    If you already run a Worker on these routes, add the tracking block to its fetch handler instead, before it returns its response.

  4. Route it in front of your site

    Attach the Worker to a route that covers your site, such as example.com/*, in the Cloudflare dashboard or in your Wrangler configuration. The Worker only sees requests on the routes it is attached to.

  5. Deploy and verify

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

What the Worker does#

  • Passes every request through. It returns fetch(request), so your site answers exactly as it did before.
  • Keeps the report alive after responding. ctx.waitUntil() lets the call to Ranqo finish after the response has gone to the visitor. Without it, Cloudflare can stop the Worker as soon as the response is returned and the report is lost. A failed report is ignored.
  • Sends the real visitor address. It reads cf-connecting-ip, the header Cloudflare sets to the visitor's IP. Ranqo uses it to check whether a crawler is genuine.
  • Counts page views only. It skips anything but GET, prefetch and framework data requests, paths under /api/, and static assets.
  • Keeps the files AI crawlers read first. robots.txt, llms.txt, sitemap.xml and /.well-known/* are reported even though other files with those extensions are skipped.

The ExecutionContext type comes from Cloudflare's Workers types package. In plain JavaScript, drop the type annotations.

Note: Dashboard on the same zone?

If your signed-in product runs on a host this Worker also covers, add it to SKIP_HOSTS at the top of the file so your team's own clicks are not counted as site visitors.

Next steps#

Verify your install

Send a test event and confirm Ranqo accepted it.

How Ranqo classifies visits

Crawlers, assistants and human referrals, and how each is told apart.
Previous page: ExpressNext page: Any backend
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