---
title: "Netlify Integration"
description: "Track AI crawler visits on Netlify — a zero-code Log Drain on Enterprise, or a small Edge Function on any plan."
---

> Documentation Index
> Fetch the complete documentation index at: /llms.txt
> Use this file to discover all available pages before exploring further.

# Netlify Integration

Both options power [AI Impressions](/docs/impressions/); to also track [Clicks](/docs/clicks/), add the client-side tracking script from **Site Settings → Tracking Script**. Send all traffic — Airefs classifies bots versus humans and drops assets and errors server-side.

Your access token is in your Airefs account under **Site Settings → Access Token**.

## Option A: Log Drain (Enterprise)

Recommended on Enterprise: no code, and it sees every request including CDN-cached responses.

1.  In the Netlify dashboard, go to **Logs → Log Drains** and enable the **General HTTP endpoint** drain.
2.  Endpoint URL:

```text
https://api.getairefs.com/v1/logs/netlify
```

3.  Authorization header value — the `Bearer` prefix is required:

```text
Bearer YOUR_ACCESS_TOKEN
```

4.  Format: **NDJSON** (JSON also works).
5.  Log types: enable **Traffic logs** only; disable Function, Edge function, Deploy, and WAF logs.
6.  Leave the personally identifiable information exclusion **off** — it strips `user_agent` and `client_ip`, which Airefs needs for AI crawler detection.
7.  Click **Connect**.

## Option B: Edge Function (any plan)

1.  Save this file as `netlify/edge-functions/airefs.ts` in your repository:

```ts
declare const Netlify: {
  env: { get(name: string): string | undefined };
};

interface EdgeContext {
  next(): Promise<Response>;
  waitUntil(promise: Promise<unknown>): void;
  ip: string;
  requestId?: string;
  geo?: { country?: { code?: string } };
}

const AIREFS_LOG_ENDPOINT = "https://api.getairefs.com/v1/logs/http";

async function forwardLogRecord(
  request: Request,
  response: Response,
  context: EdgeContext,
): Promise<void> {
  const accessToken = Netlify.env.get("AIREFS_ACCESS_TOKEN");
  if (!accessToken) {
    return;
  }

  // Netlify does not add request headers; the stable request id lives on the
  // context object and makes retried deliveries idempotent.
  const url = new URL(request.url);
  const record = {
    event_id: context.requestId || undefined,
    timestamp: new Date().toISOString(),
    status_code: response.status,
    request_method: request.method,
    request_path: url.pathname,
    query_string: url.search.slice(1) || undefined,
    hostname: url.hostname,
    content_type: response.headers.get("content-type")?.split(";")[0] ?? undefined,
    client_ip: context.ip,
    user_agent: request.headers.get("user-agent") ?? undefined,
    referrer: request.headers.get("referer") ?? undefined,
    country_code: context.geo?.country?.code,
    event_client: "netlify-edge-function@1.0.0",
  };

  await fetch(AIREFS_LOG_ENDPOINT, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-API-Key": accessToken,
    },
    body: JSON.stringify(record),
  });
}

export default async (request: Request, context: EdgeContext): Promise<Response> => {
  const response = await context.next();
  context.waitUntil(forwardLogRecord(request, response, context).catch(() => {}));
  return response;
};

export const config = {
  path: "/*",
  excludedPath: ["/.netlify/*"],
};
```

2.  In the Netlify dashboard, add an environment variable `AIREFS_ACCESS_TOKEN` with your access token.
3.  Deploy. The function passes every request through untouched and reports it in the background with `context.waitUntil`, adding no latency.

## Verification

Visit a few pages on your site. Events appear in your Airefs dashboard within a few minutes.

Outside dry-run mode, a successful response means Airefs stored every accepted record and reports why the rest were dropped. For a one-off test before going live, POST a sample record with `?dry_run=1` appended to the endpoint URL: Airefs returns a per-record verdict, including the bot classification it detected, without storing anything.

Log Drain returning a validation error with status `400`? The Authorization value is almost certainly missing the `Bearer` prefix. Edge Function deployed but no events? Confirm the `AIREFS_ACCESS_TOKEN` environment variable is set. Need help? Email [support@getairefs.com](mailto:support@getairefs.com).

Source: /docs/integrations/netlify/
