Cloudflare Web Analytics API: Site Management, GraphQL, Setup, and Troubleshooting
Learn which Cloudflare Web Analytics API to use, how RUM setup differs from GraphQL, and how to build reliable analytics workflows.

Direct answer: Cloudflare exposes two related but different analytics surfaces. The Web Analytics site-info API manages the sites configured for Real User Monitoring (RUM): you use it to list, retrieve, create, update, and delete Web Analytics sites. The GraphQL Analytics API queries aggregated Cloudflare network and product data. It is a separate API with a separate endpoint and request model. Decide which surface you need before writing code.
The site-info reference is a REST-style resource family under Cloudflare’s API documentation. The available reference material does not expose the exact paths, request bodies, response schemas, or permission scope for each operation, so those details must be checked in the current API reference before implementation. This guide shows the safe architecture, setup choices, authentication practices, GraphQL request shape, operational limits, and debugging workflow without guessing undocumented fields.
Which Cloudflare Web Analytics API should you use?
| Need | Use | What it returns or changes |
|---|---|---|
| Manage the list of RUM sites | Web Analytics site-info API | Site resources: list, get, create, update, and delete operations. Verify paths and schemas in the live reference. |
| Query traffic or product analytics | GraphQL Analytics API | Aggregated datasets for Cloudflare network and products, filtered and grouped through GraphQL. |
| Collect browser performance and visitor measurements | Web Analytics setup (dashboard, snippet, or Pages) | RUM data sent by the Web Analytics Beacon after the site is enabled. |
Cloudflare describes the GraphQL API as providing “aggregated analytics about various Cloudflare products.” It is not a replacement name for the RUM site-management endpoints. A practical integration often uses both: configure a site through Web Analytics, then query available aggregated datasets through GraphQL where appropriate.

How do I enable Cloudflare Web Analytics?
Non-proxied sites
- Open Web Analytics in the Cloudflare dashboard and add the site.
- Copy the JavaScript snippet Cloudflare provides.
- Place it in the site’s HTML before the closing
</body>tag. - Deploy the page and wait a few minutes for data to appear.
This path is for a hostname that is not proxied through Cloudflare. Do not assume that enabling a site in the dashboard injects code automatically when Cloudflare cannot proxy the response.
Proxied sites
Add the hostname in the Web Analytics dashboard. Automatic setup is enabled by default for proxied sites. The dashboard also provides options to exclude EU visitor data, install the snippet manually, or disable Web Analytics.
Automatic setup has an important caveat: when a response uses Cache-Control: public, no-transform, the proxy cannot modify the original payload to inject the Beacon script. In that case, install the snippet manually or change the response policy after reviewing your caching requirements.
Cloudflare Pages
For Pages, enable Web Analytics from the project’s Metrics view. Cloudflare adds the JavaScript snippet on the next deployment. Confirm the deployment completed before diagnosing missing events.
How do I use the Cloudflare Web Analytics site-info API?
The site-info family is the management API for RUM sites. The reference lists operations to:
- List Web Analytics sites for an account.
- Retrieve one site.
- Create a site.
- Update a site.
- Delete a site.
Because the exact endpoint paths, identifiers, payload properties, response envelopes, and permissions can change, copy those values directly from the live operation reference. Treat an endpoint name as a description of intent, not as a complete contract. Generate a client from Cloudflare’s current OpenAPI definition or pin the fields you have verified in the reference.
Safe implementation sequence
- Choose the account. Keep the account identifier in configuration, not in source code.
- Create a least-privilege API token. Confirm the site-info operation’s required permission in the current reference; do not copy GraphQL permissions blindly.
- Read before writing. List or retrieve existing sites and record their identifiers and hostnames.
- Make one change. Create or update a single site, then verify the returned resource.
- Deploy collection. Use the dashboard’s snippet or automatic setup rules for the hostname.
- Observe ingestion. Allow several minutes, then check the dashboard or a supported analytics query.
How do I get Web Analytics data from Cloudflare?
For aggregated Cloudflare data, send an HTTP POST request to:
https://api.cloudflare.com/client/v4/graphql
The JSON body contains query and variables. The query selects datasets, dimensions, measures, filters, and time ranges supported by the current GraphQL schema. Query names and fields are schema-specific; discover them from the live documentation or introspection instead of guessing.
Minimal schema discovery request
This request is useful when building a client because it verifies authentication and returns the schema’s top-level query fields. It does not assume a particular analytics dataset.
curl https://api.cloudflare.com/client/v4/graphql \
-H 'Authorization: Bearer YOUR_API_TOKEN' \
-H 'Content-Type: application/json' \
--data '{
"query": "query { __schema { queryType { fields { name } } } }",
"variables": {}
}'
GraphQL request with variables
Use this as the client structure, replacing the selection set with fields documented for the dataset you need:
curl https://api.cloudflare.com/client/v4/graphql \
-H 'Authorization: Bearer YOUR_API_TOKEN' \
-H 'Content-Type: application/json' \
--data @query.json
{
"query": "query Analytics($accountTag: String!, $start: Date!, $end: Date!) { REPLACE_WITH_DOCUMENTED_DATASET(accountTag: $accountTag, filter: { date_geq: $start, date_leq: $end }) { dimensions { REPLACE_WITH_DIMENSION } sum { REPLACE_WITH_MEASURE } } }",
"variables": {
"accountTag": "YOUR_ACCOUNT_ID",
"start": "2026-09-01",
"end": "2026-09-30"
}
}
The placeholder names are intentional. Cloudflare’s schema contains multiple datasets with different field names, and inventing a field produces a validation error. Start with the dataset documentation, then substitute its exact operation, argument, dimension, and measure names.
Python client
import os
import requests
query = """query { __schema { queryType { fields { name } } } }"""
response = requests.post(
"https://api.cloudflare.com/client/v4/graphql",
headers={
"Authorization": f"Bearer {os.environ['CLOUDFLARE_API_TOKEN']}",
"Content-Type": "application/json",
},
json={"query": query, "variables": {}},
timeout=30,
)
response.raise_for_status()
payload = response.json()
if payload.get("errors"):
raise RuntimeError(payload["errors"])
print(payload["data"])
Node.js client
const query = `query { __schema { queryType { fields { name } } } }`;
const res = await fetch('https://api.cloudflare.com/client/v4/graphql', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CLOUDFLARE_API_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ query, variables: {} })
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const payload = await res.json();
if (payload.errors) throw new Error(JSON.stringify(payload.errors));
console.log(payload.data);
Authentication and token safety
Cloudflare recommends API tokens for GraphQL Analytics. A documented example uses the Account → Account Analytics → Read permission and allows resource restrictions, client-IP restrictions, and a token lifetime. Configure only the account and zones the integration needs. The token is shown only at creation, so store it in a secret manager or environment variable immediately.
Those permissions are evidence for GraphQL Analytics. Verify the current RUM site-info reference for the exact scope required by each management operation. Never assume a token that can query GraphQL can create or delete Web Analytics sites.
Important GraphQL behavior and data limits
- A request can address multiple datasets, but Cloudflare waits for all dataset queries. If any one fails, the request fails; split unrelated queries when partial results are preferable.
- GraphQL data is aggregated and should not be used as a billing measure. Cloudflare notes that billable traffic excludes some traffic, such as DDoS traffic, while GraphQL measures overall consumption.
- The Web Analytics limits page, updated August 12, 2026, lists 10 non-proxied sites and no site-count limit for proxied sites.
- Dashboard aggregate viewing is limited to 1,000 websites in parallel. For larger portfolios, select specific sites or extract data with GraphQL.
- Rules apply only to proxied sites: Free has 0, Pro 5, Business 20, and Enterprise 100. With zero rules, Web Analytics injects the snippet on all subdomains.
Limits can change. Recheck Cloudflare’s limits page before publishing a long-lived internal standard.
Troubleshooting Cloudflare Web Analytics API integrations
| Symptom | Likely cause | Fix |
|---|---|---|
| HTTP 401 or 403 | Missing, expired, or insufficient token; wrong account resource. | Regenerate the token if necessary, verify its account scope, and check the operation’s documented permission. |
GraphQL response has errors with HTTP 200 |
GraphQL validation or resolver failure. | Always inspect the JSON errors array; validate field names and arguments against the current schema. |
| No RUM data after deployment | Snippet missing, deployment not live, blocked script, or normal ingestion delay. | View page source, check browser network requests, confirm the deployment, and wait several minutes. |
| Automatic setup does not inject the Beacon | Hostname is not proxied, or response has Cache-Control: public, no-transform. |
Proxy the hostname where appropriate or install the snippet manually. |
| Only some subdomains collect data | Rules or hostname selection do not cover every subdomain. | Review Web Analytics rules and the documented plan limit; Free has zero rules and injects on all subdomains. |
| Dashboard cannot show the whole portfolio | More than 1,000 websites selected for aggregate viewing. | Query smaller groups or use GraphQL extraction. |
| Numbers do not match billing | GraphQL measures aggregated consumption, including traffic excluded from billing. | Use billing reports for billing; use GraphQL for analysis and trends. |
Performance, reliability, and cost planning
Performance
- Keep GraphQL selections narrow: request only dimensions and measures needed for the visualization or export.
- Use variables for dates and filters so the query text stays stable and cacheable in your client.
- Split independent dataset queries when one failure should not discard unrelated results.
- For dashboards, pre-aggregate on a schedule and serve your application’s cache instead of issuing the same broad query for every viewer.
Reliability
- Set explicit HTTP timeouts and retry only transient transport failures.
- Do not retry GraphQL validation errors; fix the query first.
- Log request IDs, account identifiers, time ranges, HTTP status, and the GraphQL error payload without logging tokens.
- Pin a tested query shape and run schema checks when Cloudflare changes documented datasets.
Cost and interpretation
Cloudflare’s GraphQL documentation warns against using analytics values as a billing meter. Build financial controls from the billing product and use analytics for operational reporting, segmentation, and trend analysis. Keep the RUM site count and plan limits in your capacity model, especially for non-proxied sites.
Or skip the browser setup
If your actual job is creating reliable page images for documentation, previews, monitoring, or an AI workflow, ScreenshotNeo provides a single screenshot API call instead of maintaining a browser worker.

One request returns a PNG, JPEG, WebP, or PDF. Before capture, it accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and whether it was billed.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo also supports full-page capture with lazy images loaded, CSS-selector element capture, dark mode, device presets, custom viewports, retina scale, PDF paper and pagination controls, custom CSS and JavaScript, clicks, selector or network-idle waits, request blocking, headers, cookies, user agents, Authorization, timezone, geolocation, transparent backgrounds, resizing, configurable caching, signed image links, asynchronous jobs with signed webhooks, bulk capture for 100 URLs per call, a usage API, and an OpenAPI specification. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. See the ScreenshotNeo documentation for parameter details.
There is a free plan with 1,000 shots per month and no card. Paid plans start at $5 for 3,000 shots, and every feature is available on every plan. Create a free ScreenshotNeo account.
FAQ
Is the Cloudflare GraphQL Analytics API the same as Web Analytics?
No. Web Analytics site-info endpoints manage RUM site resources. GraphQL queries aggregated Cloudflare network and product datasets.
Can I use GraphQL to create a Web Analytics site?
Use the Web Analytics site-info API for site management. GraphQL is the analytics query surface.
How long before new Web Analytics data appears?
Cloudflare’s setup guide says data may take a few minutes. Check deployment, snippet loading, and browser requests before treating a short delay as an outage.
Should GraphQL totals be used for invoices?
No. Cloudflare explicitly says GraphQL aggregation differs from billable traffic. Use billing data for invoices.
What should I verify before automating site deletion?
Confirm the live operation’s identifier, permissions, response behavior, and an approval process. Deletion is a site-management action, not a GraphQL query.


