# Cloudflare (Worker)

### Overview

This integration runs a Cloudflare Worker as middleware. On each request, the Worker extracts metadata and sends it to Agent Monitoring — without interfering with normal request flow.

{% hint style="info" %}
For additional details about Logpush, refer to Cloudflare’s official documentation.\
Cloudflare Worker is free up to 100K requests per day, for additional details, refer to [Cloudflare’s official documentation](https://developers.cloudflare.com/workers/platform/pricing/).
{% endhint %}

{% stepper %}
{% step %}

Open Terminal and install the following using npm

```
npm create cloudflare@2.37.4 -- log-shipping
```

Follow the instructions  below

<figure><img src="/files/YjmlWT9eOhEyd3gRwKU6" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/aqcsZSp48Ryulc9nLktE" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/U5ydIjUGbULKneybC90M" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/w2RWDptQxIB4FIMUIY85" alt=""><figcaption></figcaption></figure>

Running the CLI creates the `log-shipping` project and handles dependency installation automatically.

**VERY IMPORTANT - DO NOT DEPLOY YET**

<figure><img src="/files/5YrGAWuHxQZ1uqFBfLF7" alt=""><figcaption></figcaption></figure>

{% endstep %}

{% step %}

#### Configure your worker

Edit your `wrangler.jsonc` file to configure `LIMY_URL` environment variable to our endpoint and replace the `domain.com/*` placeholder should match your organization's domain. If your site is `https://www.domain.com`, use `domain.com/*` as the pattern and `domain.com` for zone\_name

```javascript
{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "log-collector",
  "main": "src/index.ts",
  "compatibility_date": "2025-12-09",
  "observability": {
    "enabled": true
  },
  "route": {
    "pattern": "domain.com/*",
    "zone_name": "domain.com"
  },
  "vars": { "LIMY_URL": "https://stream.getlimy.ai" }
}
```

Then replace `src/index.ts` code within the code below :

{% hint style="danger" %}
If your unsure- contact us at <kbd><answers@limy.ai></kbd>
{% endhint %}

```tsx
/**
 * Cloudflare Worker for Log Collection
 *
 * This worker captures HTTP request/response data and forwards it to Limy's log collection API.
 * It runs as a middleware, meaning it doesn't interfere with the actual request handling.
 */

export interface Env {
     LIMY_KEY: string;
    LIMY_URL: string;
}

export default {
    async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {

    // Get the original response
    const response = await fetch(request);

    // Clone the response so we can read it multiple times
        const responseClone = response.clone();
    
        ctx.waitUntil(handleRequest(request, responseClone, env));
        return response;
    }
} satisfies ExportedHandler<Env>;

async function handleRequest(request: Request, response: Response, env: Env) {
	const requestUrl = new URL(request.url);
	const cf = request.cf;
  
	const headerSize = Array.from(response.headers.entries())
	  .reduce((total, [key, value]) => total + key.length + value.length + 4, 0);
	
	const responseBody = await response.blob();
	const bodySize = responseBody.size;

    // Total bytes sent includes headers and body
    const totalBytesSent = headerSize + bodySize;

    const logData = {
		// Timing
		timestamp: Date.now(),
		
		// Request basics
		host: requestUrl.hostname,
		method: request.method,
		pathname: requestUrl.pathname,
		query_params: Object.fromEntries(requestUrl.searchParams),
		
		// Client info
		ip: request.headers.get('cf-connecting-ip'),
		userAgent: request.headers.get('user-agent'),
		referer: request.headers.get('referer'),
		acceptLanguage: request.headers.get('accept-language'),
		
		// Response info
		bytes: headerSize + bodySize,
		status: response.status,
		contentType: response.headers.get('content-type'),
		
		// Cloudflare request ID
		rayId: request.headers.get('cf-ray'),
		
		// Geographic (from cf object)
		country: cf?.country,
		city: cf?.city,
		region: cf?.region,
		regionCode: cf?.regionCode,
		continent: cf?.continent,
		postalCode: cf?.postalCode,
		latitude: cf?.latitude,
		longitude: cf?.longitude,
		timezone: cf?.timezone,
		
		// Network
		asn: cf?.asn,
		asOrganization: cf?.asOrganization,
		colo: cf?.colo,  // Cloudflare datacenter
		
		// Connection
		httpProtocol: cf?.httpProtocol,
		tlsVersion: cf?.tlsVersion,
		tlsCipher: cf?.tlsCipher,
    }

    await fetch(env.LIMY_URL, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-API-Key': env.LIMY_KEY,
			'User-Agent': 'Cloudflare-Worker-Logs'
        },
        body: JSON.stringify([logData])
    }).catch(error => console.error('Failed to send logs:', error))
}
```

{% endstep %}

{% step %}

#### Login to Cloudflare

Deploy the worker using Wrangler CLI:

```typescript
//Login to Cloudflare
npx wrangler login
```

**Configure Limy API key**

Cloudflare Workers Secrets let you store sensitive values like API keys securely, outside of your code.

```typescript
npx wrangler secret put LIMY_KEY
```

{% endstep %}

{% step %}

#### Deploy your worker

```
npx wrangler deploy
```

<figure><img src="/files/aYpJIGcHxddezpZLL01v" alt=""><figcaption></figcaption></figure>
{% endstep %}
{% endstepper %}

### Need More Help? <a href="#additional-resources" id="additional-resources"></a>

* [Cloudflare Workers Documentation](https://developers.cloudflare.com/workers/)
* [Wrangler CLI Documentation](https://developers.cloudflare.com/workers/wrangler/)
* Contact <kbd><answers@limy.ai></kbd> for API-related questions


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.getlimy.ai/limy-pixel/cdn-integration/cloudflare-worker.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
