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 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}")


Share Share Tweet