Cloudflare : How to Get Unique Visitors Data

Deepanshu Bhalla Add Comment

This tutorial explains how to fetch unique visitors data from cloudflare.

Cloudflare allows you to download unique visitor data after logging into the dashboard. However it lacks flexibility in specifying date ranges and is not efficient for automation or further analysis.

Cloudflare gives an option to download various data points via GraphQL queries using its API. You need to have API key, email and zone id to use API.

Instructions : You can find your API key in the Cloudflare dashboard by clicking on profile icon (top-right) > My Profile > API Tokens. Either you can use global API key or you can create a custom API token with specific permissions. The Zone ID is available on the Overview page of your site in Cloudflare.

The following Python code returns the total unique visitors to your site in the past 24 hours along with unique visitors per hour.

import requests
import json
import pandas as pd
from datetime import datetime, timedelta, timezone
from tzlocal import get_localzone
local_timezone = get_localzone()

# Define date range (Past 24 hours)
now = datetime.now(timezone.utc).replace(minute=0, second=0, microsecond=0)
start_date = now - timedelta(days=1)
end_date = now

# ISO Format
start_date_str = start_date.strftime("%Y-%m-%dT%H:%M:%SZ")
end_date_str = end_date.strftime("%Y-%m-%dT%H:%M:%SZ")

# Cloudflare API credentials
API_KEY = "xxxxxxxxx"
ZONE_ID = "xxxxxxxxxxxx"
API_EMAIL = "xxxxxxx@xxxx.com"

# Set up headers
headers = {
    "X-Auth-Email": API_EMAIL,
    "X-Auth-Key": API_KEY,
    "Content-Type": "application/json"
}

# GraphQL query with date range filter
query = """
query GetZoneAnalytics($zoneTag: String!, $datetime_geq: DateTime!, $datetime_lt: DateTime!) {
  viewer {
    zones(filter: { zoneTag: $zoneTag }) {
      totals: httpRequests1hGroups(limit: 10000, filter: { datetime_geq: $datetime_geq, datetime_lt: $datetime_lt }) {
        uniq {
          uniques
        }
      }
      zones: httpRequests1hGroups(orderBy: [datetime_ASC], limit: 10000, filter: { datetime_geq: $datetime_geq, datetime_lt: $datetime_lt }) {
        dimensions {
          timeslot: datetime
        }
        uniq {
          uniques
        }
      }
    }
  }
}
"""

# Create request body
payload = {
    "query": query,
    "variables": {
        "zoneTag": ZONE_ID,
        "datetime_geq": start_date_str,
        "datetime_lt": end_date_str
    }
}

# Make API request
response = requests.post(
    url="https://api.cloudflare.com/client/v4/graphql",
    headers=headers,
    json=payload
)

# Process response
if response.status_code > 200:
    raise Exception(f"Error: {response.status_code}, {response.text}")

data = response.json()

# Print full JSON response (optional)
print(json.dumps(data, indent=4))

# Extract data safely
try:
    # Try accessing both totals and zones data from the response
    zones_data = data.get('data', {}).get('viewer', {}).get('zones', [{}])[0]
    
    # Extract totals and zone data, ensuring the keys exist
    totals = zones_data.get('totals', [])
    http_requests = zones_data.get('zones', [])
    
    # Calculate total unique visits
    total_uniques = sum(group.get('uniq', {}).get('uniques', 0) for group in totals)

    # Create list of records for DataFrame
    records = []
    for entry in http_requests:
        timeslot = entry.get("dimensions", {}).get("timeslot", "N/A")
        uniques = entry.get("uniq", {}).get("uniques", 0)
        records.append({"datetime": timeslot, "Unique Visits": uniques})

    # Convert to DataFrame
    df = pd.DataFrame(records)
    df['datetime'] = pd.to_datetime(df['datetime']).dt.tz_localize(None)
    df['datetime'] = df['datetime'].dt.tz_localize('UTC').dt.tz_convert(local_timezone).dt.tz_localize(None)
    df = df.sort_values(by='datetime', ascending=False)

    # Append total row
    total_row = pd.DataFrame([{"datetime": "Total", "Unique Visits": total_uniques}])
    df = pd.concat([df, total_row], ignore_index=True)

    # Save to Excel
    output_file = "cloudflare_analytics.xlsx"
    df.to_excel(output_file, index=False)

    # Print total
    print(f"\nTotal Unique Visits from {start_date} to {end_date}: {total_uniques}")
    print(f"Data saved to {output_file}")

except (TypeError, IndexError, KeyError) as e:
    print(f"Error processing data: {e}")

The code above creates a pandas dataframe named df and store data in it. Then it writes the dataframe to an excel file in your working directory.

Unique Visitors Data From Cloudflare

Unique Visitors by Day

The following Python code returns the total unique visitors to your site in the past 7 days along with unique visitors per day.

import requests
import json
import pandas as pd
from datetime import datetime, timedelta, timezone
from tzlocal import get_localzone
local_timezone = get_localzone()

# Define date range (Past 7 days)
now = datetime.now(timezone.utc).replace(minute=0, second=0, microsecond=0)
start_date = now - timedelta(days=7)
end_date = now

# ISO Format
start_date_str = start_date.strftime("%Y-%m-%d")
end_date_str = end_date.strftime("%Y-%m-%d")

# Cloudflare API credentials
API_KEY = "xxxxxxxxxxxxxxxxx"
ZONE_ID = "xxxxxxxxxxxxxxxxx"
API_EMAIL = "xxxxxxx@xxxx.com"

# Set up headers
headers = {
    "X-Auth-Email": API_EMAIL,
    "X-Auth-Key": API_KEY,
    "Content-Type": "application/json"
}

# GraphQL query with date range filter
query = """
query GetZoneAnalytics($zoneTag: string, $date_geq: string, $date_lt: string) {
  viewer {
    zones(filter: { zoneTag: $zoneTag }) {
      totals: httpRequests1dGroups(limit: 10000, filter: { date_geq: $date_geq, date_lt: $date_lt }) {
        uniq {
          uniques
        }
      }
      zones: httpRequests1dGroups(orderBy: [date_ASC], limit: 10000, filter: { date_geq: $date_geq, date_lt: $date_lt }) {
        dimensions {
          timeslot: date
        }
        uniq {
          uniques
        }
      }
    }
  }
}
"""

# Create request body
payload = {
    "query": query,
    "variables": {
        "zoneTag": ZONE_ID,
        "date_geq": start_date_str,
        "date_lt": end_date_str
    }
}

# Make API request
response = requests.post(
    url="https://api.cloudflare.com/client/v4/graphql",
    headers=headers,
    json=payload
)

# Process response
if response.status_code > 200:
    raise Exception(f"Error: {response.status_code}, {response.text}")

data = response.json()

# Print full JSON response (optional)
print(json.dumps(data, indent=4))

# Extract data safely
try:
    # Try accessing both totals and zones data from the response
    zones_data = data.get('data', {}).get('viewer', {}).get('zones', [{}])[0]
    
    # Extract totals and zone data, ensuring the keys exist
    totals = zones_data.get('totals', [])
    http_requests = zones_data.get('zones', [])
    
    # Calculate total unique visits
    total_uniques = sum(group.get('uniq', {}).get('uniques', 0) for group in totals)

    # Create list of records for DataFrame
    records = []
    for entry in http_requests:
        timeslot = entry.get("dimensions", {}).get("timeslot", "N/A")
        uniques = entry.get("uniq", {}).get("uniques", 0)
        records.append({"Date": timeslot, "Unique Visits": uniques})

    # Convert to DataFrame
    df = pd.DataFrame(records)

    # Append total row
    total_row = pd.DataFrame([{"Date": "Total", "Unique Visits": total_uniques}])
    df = pd.concat([df, total_row], ignore_index=True)

    # Save to Excel
    output_file = "cloudflare_analytics2.xlsx"
    df.to_excel(output_file, index=False)

    # Print total
    print(f"\nTotal Unique Visits from {start_date} to {end_date}: {total_uniques}")
    print(f"Data saved to {output_file}")

except (TypeError, IndexError, KeyError) as e:
    print(f"Error processing data: {e}")
Related Posts
Spread the Word!
Share
About Author:
Deepanshu Bhalla

Deepanshu founded ListenData with a simple objective - Make analytics easy to understand and follow. He has over 10 years of experience in data science. During his tenure, he worked with global clients in various domains like Banking, Insurance, Private Equity, Telecom and HR.

Post Comment 0 Response to "Cloudflare : How to Get Unique Visitors Data"
Next → ← Prev