--- title: "cloudflarer cheatsheet" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{cloudflarer cheatsheet} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r} #| label: setup #| include: false source("_vcr-setup.R") ``` One-page reference of the most-used cloudflarer calls. Every list endpoint returns a data.frame (with `tbl_df` classes for tibble users); pass `as_df = FALSE` for the raw nested list. ## Setup ```{r} #| cassette: cheat-sitrep # In ~/.Renviron # CLOUDFLARE_API_TOKEN=... # recommended # CLOUDFLARE_EMAIL=you@example.com # OR (legacy) # CLOUDFLARE_API_KEY=... library(cloudflarer) cf_sitrep() ``` ## Discover what you can reach ```{r} #| cassette: cheat-discover cf_user() cf_list_accounts() cf_list_zones() cf_list_zones(name = "example.com") ``` ## Quick overview of a zone ```{r} #| cassette: cheat-overview zones <- cf_list_zones() zone_id <- zones$id[1] account_id <- zones$account[[1]]$id cf_zone_overview(zone_id, account_id = account_id) ``` `cf_zone_overview()` pulls traffic, cache ratio, DNS queries, firewall events, and RUM top countries into one tidy bundle. Each component is wrapped so a missing permission or Pro-only feature yields `NULL` for that slot instead of failing the whole call. ## Traffic analytics ```{r} #| cassette: cheat-traffic cf_zone_requests(zone_id, Sys.Date() - 7, Sys.Date(), by = "day") cf_zone_requests(zone_id, Sys.time() - 12 * 3600, Sys.time(), by = "hour") cf_cache_ratio(zone_id, Sys.Date() - 7, Sys.Date()) cf_dns_queries(zone_id, Sys.Date() - 7, Sys.Date()) # Pro+ only: cf_firewall_events_by_day(zone_id, Sys.Date() - 7, Sys.Date()) cf_firewall_events_top( zone_id, Sys.Date() - 7, Sys.Date(), dimension = "action", limit = 10 ) ``` ## Web Analytics (RUM) ```{r} #| cassette: cheat-rum sites <- cf_list_rum_sites(account_id) site_tag <- sites$site_tag[1] cf_rum_page_views(account_id, site_tag, since = Sys.Date() - 30, until = Sys.Date()) cf_rum_top(account_id, site_tag, since = Sys.Date() - 30, until = Sys.Date(), dimension = "countryName", limit = 10) ``` ## DNS records ```{r} #| cassette: cheat-dns cf_list_dns_records(zone_id, type = "A") cf_create_dns_record( zone_id, type = "A", name = "blog", content = "192.0.2.5", proxied = TRUE ) cf_update_dns_record(zone_id, "rec-1", content = "192.0.2.99") cf_delete_dns_record(zone_id, "rec-1") ``` ## Page Rules ```{r} #| cassette: cheat-pagerules cf_list_page_rules(zone_id) cf_create_page_rule( zone_id, targets = list(cf_page_rule_target("*example.com/static/*")), actions = list( cf_page_rule_action("cache_level", "cache_everything"), cf_page_rule_action("edge_cache_ttl", 7200) ) ) cf_update_page_rule(zone_id, "rule-1", status = "disabled") cf_delete_page_rule(zone_id, "rule-1") ``` ## Cache purging ```{r} #| cassette: cheat-cache cf_purge_cache(zone_id, files = c( "https://example.com/index.html", "https://example.com/style.css" )) cf_purge_cache(zone_id, prefixes = "example.com/blog") cf_purge_cache(zone_id, purge_everything = TRUE) ``` ## Zone settings ```{r} #| cassette: cheat-settings cf_get_zone_settings(zone_id) cf_get_zone_setting(zone_id, "ssl") ``` ## Email Routing ```{r} #| cassette: cheat-email cf_get_email_routing_settings(zone_id) cf_list_email_routing_rules(zone_id) cf_list_email_routing_addresses(account_id) ``` ## Turnstile (CAPTCHA replacement) ```{r} #| cassette: cheat-turnstile cf_list_turnstile_widgets(account_id) cf_create_turnstile_widget( account_id, name = "comment-form", domains = c("example.com", "www.example.com"), mode = "managed" ) ``` ## Workers ```{r} #| cassette: cheat-workers cf_list_workers_scripts(account_id) cf_workers_invocations(account_id, Sys.Date() - 7, Sys.Date()) cf_list_kv_namespaces(account_id) ``` ## Pages, R2, Tunnels ```{r} #| cassette: cheat-storage cf_list_pages_projects(account_id) cf_list_pages_deployments(account_id, "my-project") cf_list_r2_buckets(account_id) cf_list_tunnels(account_id) ``` ## Firewall + Rulesets ```{r} #| cassette: cheat-rulesets cf_list_firewall_rules(zone_id) # Modern rulesets surface: cf_list_rulesets(zone_id) cf_get_ruleset(zone_id, "rs-1") cf_list_account_rulesets(account_id) ``` ## Escape hatches For anything cloudflarer does not wrap, drop down to the generics. They handle auth and the envelope; you handle the path. ```{r} #| cassette: cheat-escape # Any REST endpoint: build -> pipe httr2 verbs -> perform -> unwrap cf_request("user/tokens/verify") |> httr2::req_perform() |> cf_resp() cf_request("zones/abc/dns_records") |> httr2::req_method("POST") |> httr2::req_body_json(list(type = "A", name = "x", content = "192.0.2.1")) |> httr2::req_perform() |> cf_resp() # Paginated REST list (returns a raw list): cf_request("accounts/abc/access/apps") |> cf_collect(per_page = 50) # Any GraphQL Analytics query: cf_graphql( "query Q($zoneTag: String!) { viewer { zones(filter: {zoneTag: $zoneTag}) { httpRequests1dGroups( limit: 7, filter: { date_geq: \"2026-05-14\", date_lt: \"2026-05-21\" } ) { dimensions { date } sum { requests } } } } }", zoneTag = zone_id ) ``` ## Error handling Every cloudflarer failure (HTTP error, envelope `success: false`, GraphQL `errors[]`) raises a classed condition: ```{r} #| cassette: cheat-error tryCatch( cf_get_zone("does-not-exist"), cloudflarer_error = function(err) { message("Cloudflare said: ", conditionMessage(err)) NULL } ) ```