Clicky Analytics Anti‑Adblock Tracking on Cloudflare Pages

(Using Cloudflare Pages Functions as a Reverse Proxy)


Overview

Standard analytics trackers are blocked by ~20% of users due to adblockers.

Clicky provides an anti-adblock proxy method, which works by:

To adblockers, this appears as first-party traffic. This guide shows how to implement it using Cloudflare Pages Functions, with no nginx, Workers dashboard setup, or DNS changes.


How This Works (Architecture)

Browser → static.getclicky.com (blocked)

We will proxy it like this:

Browser → customdomain.com/<CLICKY_JS_PATH>
         → Cloudflare Pages Function
         → static.getclicky.com
         → Response returned
Browser → customdomain.com/<CLICKY_BEACON_PATH>
         → Cloudflare Pages Function
         → in.getclicky.com
         → Response returned

Phase 1 — Prerequisites

1. Cloudflare Pages Project

wrangler pages deploy .

2. Custom Domain Connected

Your Pages project must already be connected to:

customdomain.com
OR
customdomain.pages.dev

3. Clicky Anti-Adblock Paths

Inside your Clicky dashboard, you will see:

Replace in this guide:


Phase 2 — Project Structure

Inside your local project folder:

your-project/
│
├── functions/
│
└── (your other files)

Create two new files inside /functions.


Phase 3 — Create the JavaScript Proxy

Create this file:

/functions/<CLICKY_JS_PATH>.js

Example:

/functions/0a3b1c9d8e7f.js

Paste this code:

export async function onRequest(context) {
  const beaconPath = "/<CLICKY_BEACON_PATH>";

  const upstreamURL = `https://static.getclicky.com/js?in=${encodeURIComponent(beaconPath)}`;

  const response = await fetch(upstreamURL, {
    method: "GET",
    headers: {
      "Host": "static.getclicky.com"
    }
  });

  return new Response(response.body, {
    status: response.status,
    headers: response.headers
  });
}

Phase 4 — Create the Beacon Proxy

Create this file:

/functions/<CLICKY_BEACON_PATH>.js

Example:

/functions/9f8e7d6c5b4a.js

Paste this code:

export async function onRequest(context) {
  const request = context.request;

  // Extract only Clicky-related cookies
  const cookieHeader = request.headers.get("cookie") || "";
  let filteredCookies = "";

  const ignoreMatch = cookieHeader.match(/_cky_ignore=[^;]+/);
  const osaMatch = cookieHeader.match(/_cky_osa=[^;]+/);

  if (ignoreMatch) {
    filteredCookies += ignoreMatch[0];
  }

  if (osaMatch) {
    if (filteredCookies.length > 0) filteredCookies += "; ";
    filteredCookies += osaMatch[0];
  }

  const url = new URL(request.url);
  const upstreamURL = `https://in.getclicky.com/in.php${url.search}`;

  const response = await fetch(upstreamURL, {
    method: request.method,
    headers: {
      "Host": "in.getclicky.com",
      "X-Forwarded-For": request.headers.get("CF-Connecting-IP"),
      "X-Forwarded-Proto": "https",
      "X-Forwarded-Host": url.hostname,
      "Cookie": filteredCookies
    }
  });

  return new Response(response.body, {
    status: response.status,
    headers: response.headers
  });
}

Phase 5 — Deploy

wrangler pages deploy .

Phase 6 — Verification

1️⃣ Test JavaScript Endpoint

Visit:

https://customdomain.com/<CLICKY_JS_PATH>

2️⃣ Test Beacon Endpoint

Visit:

https://customdomain.com/<CLICKY_BEACON_PATH>?site_id=<SITE_ID>

3️⃣ Install Tracking Code

<script async data-id="<SITE_ID>" src="/<CLICKY_JS_PATH>"></script>

Phase 8 — Confirm It Works


Clean Removal


What We Intentionally Did Not Use