---
title: "CDN Cache-Tag Headers - PerfLocale"
description: "Emit Cache-Tag response headers so Cloudflare, Bunny, Fastly and other CDNs can purge by language or by specific content."
canonical: "https://perflocale.com/docs/cache-tags/"
source: "https://perflocale.com/docs/cache-tags/"
format: "markdown"
---
# CDN Cache-Tag Headers

Emit a `Cache-Tag` response header on every frontend HTML request, giving your CDN per-resource tags to purge against - “flush everything tagged `lang:fr_FR`” or “flush `post:42`” without nuking the whole edge cache.

**Disabled by default.** Enable via _PerfLocale → Settings → Advanced → CDN Cache-Tag Headers_, or programmatically with `add_filter( 'perflocale/cache_tags/enabled', '__return_true' )`. When off, no `send_headers` callback is registered and no class is loaded.

## What gets emitted

One `Cache-Tag` header per response, with a comma-separated list of tags for that request’s context:

```
Cache-Tag: perflocale,lang:fr_FR,lang-slug:fr,post:42,post-type:post
```

| Always | Per-context |
| --- | --- |
| perflocalelang:<locale>lang-slug:<slug> | Singular: post:<id>, post-type:<type>Term archive: tax:<taxonomy>, term:<term_id>Post-type archive: archive:<type>Author archive: author:<id>Date archive: date:YYYY-MM (or date:YYYY on a year archive)Search: search404: 404Home/front page: home |

## CDN support matrix

| CDN | Header name | Out of the box? |
| --- | --- | --- |
| Cloudflare (Enterprise Cache Tags) | Cache-Tag | Yes |
| Bunny.net | Cache-Tag | Yes |
| Fastly | Surrogate-Key | Filter perflocale/cache_tags/header_name |
| KeyCDN | Cache-Tag | Yes |
| Akamai | Edge-Cache-Tag | Filter perflocale/cache_tags/header_name |

For Fastly:

```php
add_filter( 'perflocale/cache_tags/header_name', fn() => 'Surrogate-Key' );
```

## Sanitisation + limits

-   Tags are filtered to `[A-Za-z0-9\-_:.]` only - no whitespace, quotes, commas, or control characters
-   Per-tag length capped at 128 characters
-   Maximum 32 tags per response
-   Header value is hard-capped at 8000 bytes (filterable via `perflocale/cache_tags/max_header_length`); tags overflowing the budget are dropped silently
-   Header is never emitted on admin, AJAX, cron, REST, XMLRPC, or feed requests; also skipped for paths in the routing-exclusion list

## Customising the tag list

```php
add_filter( 'perflocale/cache_tags/tags', function ( array $tags ): array {
	$tags[] = 'theme:' . get_template();

	if ( is_singular( 'product' ) ) {
		$product = wc_get_product( get_queried_object_id() );
		foreach ( $product->get_category_ids() as $cat_id ) {
			$tags[] = 'wc-cat:' . (int) $cat_id;
		}
	}

	return $tags;
} );
```

The filter runs _before_ PerfLocale’s sanitisation pass, so your custom tags go through the same `[A-Za-z0-9\-_:.]` guard, the 128-character per-tag cap, and the 32-tag limit before emission.

## Purging from your CDN

PerfLocale does not issue remote purges - that’s host-specific and there are plenty of existing plugins for each CDN. Instead, PerfLocale fires an action whenever an object’s cache is flushed (post save, term edit, translation linked), passing the object’s id and type - map that to your CDN’s cache tag and purge it:

```php
add_action( 'perflocale/cache/flush_object', function ( int $object_id, string $object_type ): void {
	// Map "$object_type:$object_id" to your Cache-Tag and purge via an existing CDN plugin.
	do_action( 'cloudflare_purge_tags', [ $object_type . ':' . $object_id ] );
}, 10, 2 );

// For a full-layer flush (language lifecycle, settings change):
// add_action( 'perflocale/cache/flush_all', function (): void { /* purge everything */ } );
```

This fires on relevant content-change hooks (post save, term edit, translation linked) so sibling-language variants get purged alongside the source content.

## Disabling per path

If you need to suppress the header for specific routes without turning the whole feature off, add the path to _Settings → URL & Routing → Excluded Paths_. PerfLocale uses the same exclusion list for routing and for Cache-Tag emission.

## Related

-   [Hooks reference](https://perflocale.com/docs/hooks/#cache-tags) - the cache-tag filters (enabled / header name / tags) and the cache-flush actions
-   [Edge integration](https://perflocale.com/docs/edge-integration/) - pair Cache-Tag headers with edge-based language routing for near-100% edge cache hit rates
