iTranslated by AI
Using Cloudflare's Purge by Single-File API for Advanced Cache Key Configurations
Introduction
This article provides notes on how to use the Cloudflare CDN Purge by single-file (URL) functionality via API.
While Instant Purge for a single file (URL) can be performed from the dashboard (available for all plans),

it cannot be used for the following cases:
-
Requests with headers that are part of the standard cache key.
-
When using Custom Cache Keys.
Exception: Device type and Country can also be used from the Advanced section of the dashboard.

The way to purge these requests by single file is by using API calls.
Changes to the cache key are made via Cache rules.
Therefore, we will look at how to perform purges via API according to those settings below.
API Usage Examples
Case: Purging by URL only
Default Cache Key
A single-file purge equivalent to the dashboard requires a body specified as follows.
In the case of the dashboard, you are only inputting the value of this URL.
First, let's look at a URL without a query string.
{
"files": [
{"url": "https://www.example.com/foo"}
]
}
log
# Caching in Cloudflare
http -h $TARGET | grep -i cf-cache-status
CF-Cache-Status: HIT
# Execute Purge via API
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"files": [
{"url": "'"$TARGET"'"}
]
}'
# Purge successful as cache becomes MISS
http -h $TARGET | grep -i cf-cache-status
CF-Cache-Status: MISS
If the request has a query string, by default, the query string is included in the cache key.
To purge, specify the URL including the target query string.
{
"files": [
{"url": "https://www.example.com/foo?id=1"}
]
}
log
# Cache query string 1
http -h "$TARGET?id=1" | grep -i cf-cache-status
CF-Cache-Status: MISS
http -h "$TARGET?id=1" | grep -i cf-cache-status
CF-Cache-Status: HIT
# Cache query string 2
http -h "$TARGET?id=2" | grep -i cf-cache-status
CF-Cache-Status: MISS
http -h "$TARGET?id=2" | grep -i cf-cache-status
CF-Cache-Status: HIT
# Purge query string 1
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"files": [
{"url": "'"$TARGET?id=1"'"}
]
}'
# Query string 2 is Hit
http -h "$TARGET?id=2" | grep -i cf-cache-status
CF-Cache-Status: HIT
# Query string 1 is Miss (Purge successful)
http -h "$TARGET?id=1" | grep -i cf-cache-status
CF-Cache-Status: MISS
If there are multiple query strings, different orders like a=0&b=1 and b=1&a=0 are treated as different cache keys.
Specifying as follows will only purge the former.
To purge the latter, specify b=1&a=0.
{
"files": [
{"url": "https://www.example.com/foo?a=0&b=1"}
]
}
log
# Cache query string 1
http -h "$TARGET?a=0&b=1" | grep -i cf-cache-status
CF-Cache-Status: MISS
http -h "$TARGET?a=0&b=1" | grep -i cf-cache-status
CF-Cache-Status: HIT
# Cache query string 2
http -h "$TARGET?b=1&a=0" | grep -i cf-cache-status
CF-Cache-Status: MISS
http -h "$TARGET?b=1&a=0" | grep -i cf-cache-status
CF-Cache-Status: HIT
# Purge query string 1
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"files": [
{"url": "'"$TARGET?a=0&b=1"'"}
]
}'
# Query string 2 is Hit
http -h "$TARGET?b=1&a=0" | grep -i cf-cache-status
CF-Cache-Status: HIT
# Query string 1 is Miss (Purge successful)
http -h "$TARGET?a=0&b=1" | grep -i cf-cache-status
CF-Cache-Status: MISS
Changing Cache Keys with Cache Rules
Now, let's change the default cache keys.
Query String Sort 📖

When the query string is sorted, different orders like a=0&b=1 and b=1&a=0 become the same cache key.
It will be purged regardless of which one you specify.
{
"files": [
{"url": "https://www.example.com/foo?a=0&b=1"}
]
}
log
# Cache query string 1
http -h "$TARGET?a=0&b=1" | grep -i cf-cache-status
CF-Cache-Status: MISS
# Query string 2 is also returned from the same cache
http -h "$TARGET?b=1&a=0" | grep -i cf-cache-status
CF-Cache-Status: HIT
# Purge query string 1
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"files": [
{"url": "'"$TARGET?a=0&b=1"'"}
]
}'
# Query string 2 is MISS (Purge successful)
http -h "$TARGET?b=1&a=0" | grep -i cf-cache-status
CF-Cache-Status: MISS
Ignore Query String 📖

When ignoring query strings, perform the purge without specifying a query string.
It will be purged even if you attach an arbitrary query string.
{
"files": [
{"url": "https://www.example.com/foo"}
]
}
log
# Cache query string 1
http -h "$TARGET?id=1" | grep -i cf-cache-status
CF-Cache-Status: MISS
http -h "$TARGET?id=1" | grep -i cf-cache-status
CF-Cache-Status: HIT
# Query string 2 is also returned from the same cache
http -h "$TARGET?id=2" | grep -i cf-cache-status
CF-Cache-Status: HIT
# Purge URL
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"files": [
{"url": "'"$TARGET"'"}
]
}'
# Query string 1 is MISS (Purge successful)
http -h "$TARGET?id=1" | grep -i cf-cache-status
CF-Cache-Status: MISS
# Ignored and purged even if you attach an arbitrary query string
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"files": [
{"url": "'"$TARGET?hoge=2345"'"}
]
}'
http -h "$TARGET?id=1" | grep -i cf-cache-status
CF-Cache-Status: MISS
Case: Purging by specifying URL + Headers
Requests with headers that are included in the cache key by default
Purge cache containing headers that are included in the cache key by default.
| Request Header |
|---|
| Origin X-Forwarded-Host X-Host X-Forwarded-Scheme X-Original-URL X-Rewrite-URL Forwarded |
In addition to the URL, add the relevant header and value to the headers field and issue the purge.
For example, to purge a cache of a request with an Origin header, it would look like this:
{
"files": [
{"url": "https://www.example.com/foo", "headers": {"origin":"https://example.net"}}
]
}
log
# Cache Origin header 1
http -h $TARGET origin:https://example.com | grep -i cf-cache-status
CF-Cache-Status: MISS
http -h $TARGET origin:https://example.com | grep -i cf-cache-status
CF-Cache-Status: HIT
# Cache Origin header 2
http -h $TARGET origin:https://example.net | grep -i cf-cache-status
CF-Cache-Status: MISS
http -h $TARGET origin:https://example.net | grep -i cf-cache-status
CF-Cache-Status: HIT
# Purge Origin header 1
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"files": [
{"url": "'"$TARGET"'", "headers": {"origin":"https://example.com"}}
]
}'
# Origin header 2 is Hit
http -h $TARGET origin:https://example.net | grep -i cf-cache-status
CF-Cache-Status: HIT
# Origin header 1 is Miss (Purge successful)
http -h $TARGET origin:https://example.com | grep -i cf-cache-status
CF-Cache-Status: MISS
Changing Cache Keys with Cache Rules
Now, let's change the default cache keys.
Specified Request Header and Value 📖

Add the specified request header and its value to the cache key.
Perform the purge by including the header and value in the headers field.
{
"files": [
{"url": "https://www.example.com/foo", "headers": {"z-id":"1"}}
]
}
log
# Cache header 1
http -h $TARGET z-id:1 | grep -i cf-cache-status
CF-Cache-Status: MISS
http -h $TARGET z-id:1 | grep -i cf-cache-status
CF-Cache-Status: HIT
# Cache header 2
http -h $TARGET z-id:2 | grep -i cf-cache-status
CF-Cache-Status: MISS
http -h $TARGET z-id:2 | grep -i cf-cache-status
CF-Cache-Status: HIT
# Purge header 1
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"files": [
{"url": "'"$TARGET"'", "headers": {"z-id":"1"}}
]
}'
# Header 2 is Hit
http -h $TARGET z-id:2 | grep -i cf-cache-status
CF-Cache-Status: HIT
# Header 1 is MISS (Purge successful)
http -h $TARGET z-id:1 | grep -i cf-cache-status
CF-Cache-Status: MISS
Existence of Specified Request Header 📖

Use the existence of the specified request header in the cache key (boolean).
Perform the purge by setting the relevant header and a value (anything works).
{
"files": [
{"url": "https://www.example.com/foo", "headers": {"z-id":"hoge"}}
]
}
log
# Cache header 1
http -h "$TARGET" z-id:1 | grep -i cf-cache-status
CF-Cache-Status: MISS
# Header 2 is the same cache
http -h "$TARGET" z-id:2 | grep -i cf-cache-status
CF-Cache-Status: HIT
# Purge specified header (value is arbitrary)
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"files": [
{"url": "'"$TARGET"'", "headers": {"z-id":"hoge"}}
]
}'
# Header 2 is MISS (Purge successful)
http -h "$TARGET" z-id:2 | grep -i cf-cache-status
CF-Cache-Status: MISS
Specified Cookie and Value 📖

Add the specified Cookie and its value to the cache key.
Perform the purge by including the Cookie and value in the headers field.
{
"files": [
{"url": "https://www.example.com/foo", "headers": {"cookie":"z-id=1"}}
]
}
log
# Cache cookie 1
http -h "$TARGET" cookie:"z-id=1" | grep -i cf-cache-status
CF-Cache-Status: HIT
# Cache cookie 2
http -h "$TARGET" cookie:"z-id=2" | grep -i cf-cache-status
CF-Cache-Status: HIT
# Purge cookie 1
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"files": [
{"url": "'"$TARGET"'", "headers": {"cookie":"z-id=1"}}
]
}'
# Cookie 2 is HIT
http -h "$TARGET" cookie:"z-id=2" | grep -i cf-cache-status
CF-Cache-Status: HIT
# Cookie 1 is MISS (Purge successful)
http -h "$TARGET" cookie:"z-id=1" | grep -i cf-cache-status
CF-Cache-Status: MISS
Existence of Specified Cookie 📖

Use the existence of the specified Cookie in the cache key (boolean).
Perform the purge by setting the Cookie and a value (anything works).
{
"files": [
{"url": "https://www.example.com/foo", "headers": {"cookie":"z-id=hoge"}}
]
}
log
# Cache cookie 1
http -h "$TARGET" cookie:z-id=1 | grep -i cf-cache-status
CF-Cache-Status: HIT
# Purge specified cookie (value is arbitrary)
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"files": [
{"url": "'"$TARGET"'", "headers": {"cookie":"z-id=hoge"}}
]
}'
# Cookie 2 is MISS (Purge successful)
http -h "$TARGET" cookie:z-id=1 | grep -i cf-cache-status
CF-Cache-Status: MISS
Device type 📖

Or

Set only one of them
An error will occur if you try to set both.

API Setting Location
This is the output from the Cache rules API.
# When set via toggle
{
"action": "set_cache_settings",
"action_parameters": {
"cache": true,
"cache_key": {
"cache_by_device_type": true
}
},
# When set via checkbox
{
"action": "set_cache_settings",
"action_parameters": {
"cache": true,
"cache_key": {
"custom_key": {
"user": {
"device_type": true
}
}
}
},
Headers added during origin forwarding
Regardless of the method, the following header is added to requests to the origin server.
# One of desktop, mobile, tablet
Cf-Device-Type: desktop
Add the device type determined by Cloudflare to the cache key.
It is classified into 3 types based on User agent and added to the cf-device-type header.
Perform the purge by specifying cf-device-type and its type in headers.
{
"files": [
{"url": "https://www.example.com/foo", "headers": {"cf-device-type":"mobile"}}
]
}
log
# Cache user-agent 1
http -h $TARGET user-agent:$ANDROID | grep -i cf-cache-status
CF-Cache-Status: HIT
# Cache user-agent 2
http -h $TARGET user-agent:$WINDOWS | grep -i cf-cache-status
CF-Cache-Status: HIT
# Purge device type mobile
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"files": [
{"url": "'"$TARGET"'", "headers": {"cf-device-type":"mobile"}}
]
}'
# User-agent 2 is HIT
http -h $TARGET user-agent:$WINDOWS | grep -i cf-cache-status
CF-Cache-Status: HIT
# User-agent 1 is MISS (Purge successful)
http -h $TARGET user-agent:$ANDROID | grep -i cf-cache-status
CF-Cache-Status: MISS
Country 📖

Add the country code (2 letters) of the client seen by Cloudflare to the cache key cf-ipcountry.
Perform the purge by specifying cf-ipcountry in headers, but note that the country code must be specified in uppercase.
About the cf-ipcountry header
Cf-Ipcountry is one of the headers notified to the origin by default.
Cf-Ipcountry: JP
You can also verify it in HTTP logs.
Example of Instant logs

As an aside, you can get other information by using this.

{
"files": [
{"url": "https://www.example.com/foo", "headers": {"cf-ipcountry":"JP"}}
]
}
log
# Cache request from Japan
http -h $TARGET | grep -i cf-cache-status
CF-Cache-Status: HIT
# Cache request from Australia
http -h $TARGET | grep -i cf-cache-status
CF-Cache-Status: HIT
# Purge country code JP
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"files": [
{"url": "'"$TARGET"'", "headers": {"cf-ipcountry":"JP"}}
]
}'
# Request from Australia is HIT
http -h $TARGET | grep -i cf-cache-status
CF-Cache-Status: HIT
# Request from Japan is MISS (Purge successful)
http -h $TARGET | grep -i cf-cache-status
CF-Cache-Status: MISS
Language 📖

Use the value of the request header accept-language in the cache key.
Perform the purge by including accept-language and its value in the headers field.
The value is a strict case-sensitive match with the request.
In the case below, a request with 'ja' is effective, but 'Ja' will not match.
{
"files": [
{"url": "https://www.example.com/foo", "headers": {"accept-language":"ja"}}
]
}
log
# Cache accept-language:ja
http -h $TARGET accept-language:ja | grep -i cf-cache-status
CF-Cache-Status: HIT
# Cache accept-language:de
http -h $TARGET accept-language:de | grep -i cf-cache-status
CF-Cache-Status: HIT
# Purge accept-language:ja
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"files": [
{"url": "'"$TARGET"'", "headers": {"accept-language":"ja"}}
]
}'
# accept-language:de is HIT
http -h $TARGET accept-language:de | grep -i cf-cache-status
CF-Cache-Status: HIT
# accept-language:ja is MISS (Purge successful)
http -h $TARGET accept-language:ja | grep -i cf-cache-status
CF-Cache-Status: MISS
# The case of the specified value must match the request header
# It will not be effective if it does not match the request header
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"files": [
{"url": "'"$TARGET"'", "headers": {"accept-language":"DE"}}
]
}'
http -h $TARGET accept-language:de | grep -i cf-cache-status
CF-Cache-Status: HIT
# Cache key changes with case sensitivity
http -h $TARGET accept-language:ja-jp | grep -i cf-cache-status
CF-Cache-Status: HIT
http -h $TARGET accept-language:ja-Jp | grep -i cf-cache-status
CF-Cache-Status: MISS
Other
Changing Cache Keys with Cache Rules
Host Header 📖

Rewrite the host header during origin connection.
Use this rewritten host header in the cache key.
I am currently looking for a way to purge by single file.
As an alternative, I have confirmed that purge is possible by host name instead of single file.
{
"hosts": [
"o1.oymk.work"
]
}
How to rewrite the Host header
You can rewrite the host header with Origin rules.
The following rewrites the host header depending on the cookie value.


log
# Cache Origin 1
http -h $TARGET cookie:"o=1"| grep -i cf-cache-status
CF-Cache-Status: MISS
http -h $TARGET cookie:"o=1"| grep -i cf-cache-status
CF-Cache-Status: HIT
# Cache Origin 2
http -h $TARGET cookie:"o=2"| grep -i cf-cache-status
CF-Cache-Status: MISS
http -h $TARGET cookie:"o=2"| grep -i cf-cache-status
CF-Cache-Status: HIT
# Received at the origin side with a different host name
o1.oymk.work - "GET /custom/ts.bin HTTP/2.0" 200 3 "-" "HTTPie/3.2.4"
o2.oymk.work - "GET /custom/ts.bin HTTP/2.0" 200 3 "-" "HTTPie/3.2.4"
# Purge Origin 1
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"hosts": [
"o1.oymk.work"
]
}'
# Origin 2 is HIT
http -h $TARGET cookie:"o=2"| grep -i cf-cache-status
CF-Cache-Status: HIT
# Origin 1 is MISS (Purge successful)
http -h $TARGET cookie:"o=1"| grep -i cf-cache-status
CF-Cache-Status: MISS
Origin Header 📖

Remove the origin header from the cache key.
Perform the purge without specifying the origin header.
{
"files": [
{"url": "https://www.example.com/foo"}
]
}
log
# Cache at Origin 1
http -h $TARGET origin:https://example.com | grep -i cf-cache-status
CF-Cache-Status: MISS
# Origin 2 is the same cache
http -h $TARGET origin:https://example.net | grep -i cf-cache-status
CF-Cache-Status: HIT
# Purge without specifying origin
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"files": [
{"url": "'"$TARGET"'"}
]
}'
# Origin 2 is MISS (Purge successful)
http -h $TARGET origin:https://example.net | grep -i cf-cache-status
CF-Cache-Status: MISS
Cache deception armor 📖

Even when Cache deception armor is enabled, purge is issued against the default URL.
About Cache deception armor
See this blog
Enable Origin Cache Control as well
To enable Cache detection armor, enable Origin Cache Control.

{
"files": [
{"url": "https://www.example.com/foo"}
]
}
log
# File extension of the request does not match the Content-Type of the response
GET /deception/foo.jpg HTTP/1.1
# Because the response from the origin for jpg is application/json
# BYPASS by Cache deception armor
# - It would be cached if Cache deception armor were disabled
HTTP/1.1 200 OK
CF-Cache-Status: BYPASS
Content-Type: application/json; charset=utf-8
# File extension of the request matches the Content-Type of the response
GET /deception/foo.png HTTP/1.1
# Because the response from the origin for png is image/png
# Cache and HIT
HTTP/1.1 200 OK
CF-Cache-Status: HIT
Content-Type: image/png
# Purge png by URL
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"files": [
{"url": "'"$TARGET"'"}
]
}'
# Changes to MISS (Purge successful)
HTTP/1.1 200 OK
CF-Cache-Status: MISS
Conclusion
I have confirmed that Purge by single-file (URL) via API is possible. I did not demonstrate cases where multiple URLs (files) are specified or multiple items are added to the cache key, but they would follow the form shown in the API examples.

Regarding purge via Cloudflare Workers' fetch API and cache API, there is an explanation here.
I hope to try that separately.
Discussion