AI answer

Cloudflare Edge Analytics Worker Setup

This guide explains how to:

  1. Create a Cloudflare Worker
  2. Add environment variables securely
  3. Attach a route to your domain
  4. Validate that events are reaching aeo.press

The Worker sits in front of your existing site, forwards traffic to your origin normally, and asynchronously sends structured analytics data to ag-nts.

No changes to your application code are required.

Architecture

Visitor

Cloudflare Edge

Cloudflare Worker (logs request)

Your Origin Server

Response to Visitor

Worker (async)

POST → ag-nts Rails endpoint

The Worker:

  • Passes the request to your origin (fetch(request))
  • Measures response time
  • Captures metadata (IP, user agent, status, colo, country, etc.)
  • Sends a non-blocking POST to ag-nts using ctx.waitUntil()

This ensures:

  • No added latency to your users
  • Logging failures do not affect site availability

Step 1 — Create the Worker

  1. Log into your Cloudflare Dashboard
  2. Navigate to Workers & Pages
  3. Click Create Application
  4. Choose Create Worker
  5. Deploy the default Worker
  6. Open the Worker and replace the default code with the provided script
export default {  async fetch(request, env, ctx) {    const started = Date.now();    const response = await fetch(request);    const pageUrl = new URL(request.url);    pageUrl.hash = "";    const cfRay = request.headers.get("CF-Ray") || "";    const body = {      ip_address: request.headers.get("CF-Connecting-IP") || "",      user_agent: request.headers.get("User-Agent") || "",      referer: request.headers.get("Referer") || "",      path: pageUrl.toString(),      http_status: response.status,      epoch_ms: started,      response_time_ms: Date.now() - started,      event_type: "edge_view",      custom_data: {        source: "cloudflare",        request_id: cfRay,        ray_id: cfRay,        method: request.method,        colo: request.cf?.colo || "",        country: request.cf?.country || "",      },    };    ctx.waitUntil(      postToRails(        env.RAILS_URL || "https://app.aeo.press/analytics/cloudflare_event",        body,        env.log_secret      )    );    return response;  },};async function postToRails(url, obj, secret) {  const maxAttempts = 2;  const timeoutMs = 2500;  for (let attempt = 1; attempt <= maxAttempts; attempt++) {    const controller = new AbortController();    const timer = setTimeout(() => controller.abort(), timeoutMs);    try {      const res = await fetch(url, {        method: "POST",        headers: {          "content-type": "application/json",          ...(secret ? { "X-Auth": secret } : {}),        },        body: JSON.stringify(obj),        signal: controller.signal,      });      clearTimeout(timer);      if (res.ok) return;      const text = await res.text().catch(() => "");      // 4xx = non-retryable (bad secret, validation, etc.)      if (res.status >= 400 && res.status < 500) {        console.log(`[edge_event] Rails ${res.status} (no retry): ${text.slice(0, 200)}`);        return;      }      // 5xx retry once      console.log(`[edge_event] Rails ${res.status} (attempt ${attempt}): ${text.slice(0, 200)}`);    } catch (e) {      clearTimeout(timer);      // Network/timeout -> retry once      console.log(`[edge_event] POST failed (attempt ${attempt}): ${e?.message || String(e)}`);    }    // Backoff before retry (only if we have another attempt)    if (attempt < maxAttempts) {      await sleep(200 * attempt);    }  }}function sleep(ms) {  return new Promise((r) => setTimeout(r, ms));}

Click Save and Deploy

Step 2 — Add Environment Variables

In the Worker settings:

  1. Go to Settings → Variables
  2. Add the following:

Variable (non-secret)

Name: RAILS_URLValue: https://app.aeo.press/analytics/cloudflare_event

Secret (secure)

Name: LOG_SECRETValue: (provided by aeo.press)

IMPORTANT: LOG_SECRET must be added as a Secret, not a plain variable.

Save changes.

Step 3 — Add a Route

Now attach the Worker to your domain traffic.

  1. Go to Settings → Domains & Routes
  2. Click Add Route
  3. Select your zone
  4. Enter a route pattern

Typical Route Patterns
Log entire site:

example.com/*

Log only www:

www.example.com/*

Click Save

The Worker is now active.