# GTM setup for the Cloudflare move

> **This is the small download with media placeholders.** Before uploading, put each original media file beside its `INSERT_<filename>.txt` placeholder, then delete the TXT placeholder. Follow `READ-ME-FIRST.txt`. Website code and media URLs are unchanged.

Updated **22 October 2026**. Production is now **https://yunadata.pages.dev/**. The website still uses **GTM-KH2HGFPW**. This guide replaces the previous migration instructions and starts from your existing, unchanged published GTM container. No GTM, GA4, Clarity, Firebase, GitHub, or Cloudflare account settings have been changed for you.

**Keep the GitHub website working during the gradual move. Do not globally pause its banner tags or replace all existing triggers with the new consent guard.** Instead, separate the old and new sites by hostname within the existing container. No new GTM container or GA4 measurement ID is required.

## 1. Back up and create the two hostname branches

Export the current container and record its published version. Create a workspace for the Cloudflare migration. Enable the built-in **Page Hostname**, **Page URL**, and **Page Path** variables under Variables → Configure.

| Branch | Exact Page Hostname | Consent owner |
| --- | --- | --- |
| Existing GitHub website | `yunadata.github.io` | Its existing GTM banner and logic |
| New Cloudflare website | `yunadata.pages.dev` | The website's `consent.js`, `consent-ui.js`, and `consent.css` |

For **each existing tag that currently serves the GitHub website**, copy each of its firing triggers, keep its existing event type and conditions, and add **Page Hostname equals yunadata.github.io**. Give these copies a `GitHub -` prefix. Replace that tag's original firing triggers with these scoped copies; don't leave an unscoped trigger attached as an alternative. This applies to the old consent/style tags, Google tag, Clarity, gameplay/portfolio event tags, and other legacy measurement tags.

In particular, keep these two tags active **only on the GitHub branch**:

- `CMP - Consent Banner & Logic`
- `Style - Custom Cookie Banner CSS`

Keep their original code, consent event names, and consent settings. The old `cookie_consent_update` event remains relevant to the old website. The new website uses `yd_analytics_ready` instead.

If the container also serves other websites, preserve their existing host conditions too; exclude `yunadata.pages.dev` from that legacy branch rather than unintentionally stopping those sites. Review all firing triggers: GTM treats separate firing triggers as alternatives, so adding one restricted trigger alongside an unrestricted one does not restrict the tag.

## 2. Add a Cloudflare consent guard

Create a **Custom JavaScript variable**, named **JS - Yuna analytics allowed**:

```javascript
function() {
  return window.location.hostname === 'yunadata.pages.dev' &&
    !!(window.YunaConsent && window.YunaConsent.analyticsAllowed());
}
```

Create a **Custom Event trigger**, named **CF - Yuna analytics ready**:

| Setting | Value |
| --- | --- |
| Event name | `yd_analytics_ready` |
| Regex matching | Off |
| Fires on | Some Custom Events |
| Condition 1 | `Page Hostname` equals `yunadata.pages.dev` |
| Condition 2 | `JS - Yuna analytics allowed` equals `true` |

Both conditions belong in the **same trigger**. The event occurs once per page after GTM loads and after the website has sent consent defaults and the current opt-in. It works for a new opt-in and a returning visitor.

The website's production allowlist already contains only `yunadata.pages.dev`. Localhost, the private design preview, and Cloudflare branch/hash preview subdomains do not start production analytics, even after acceptance. Do not use a broad `pages.dev` or suffix match.

## 3. Create Cloudflare copies of your measurement tags

Duplicate the existing measurement tags you want on the new website and give them a `CF -` prefix. Reuse their actual Google measurement IDs, event names, parameter mappings, and Clarity project ID. Their account values were not all present in the attachments; do not invent replacement IDs. **Do not duplicate the old banner or banner CSS tags.**

Configure only the Cloudflare copies as follows:

| Cloudflare tag | Firing trigger | Additional consent |
| --- | --- | --- |
| Google tag / GA4 configuration | `CF - Yuna analytics ready` only | Require `analytics_storage` |
| Clarity installation | `CF - Yuna analytics ready` only | Require `analytics_storage` |
| GA4 event tags, including gameplay and `portfolio_interaction` | Cloudflare copies of their relevant event triggers, with both hostname and consent guard conditions | Require `analytics_storage` |

For each Cloudflare copy, open **Advanced Settings → Consent Settings → Require additional consent for tag to fire** and add `analytics_storage`. Set the Google and Clarity installation tags to **Once per page**. Remove inherited All Pages, Initialization, DOM Ready, and `cookie_consent_update` firing triggers from these two Cloudflare installation tags.

For event tags, copy the original trigger and preserve its event conditions. Replace any old hostname condition with **Page Hostname equals yunadata.pages.dev**, then add **JS - Yuna analytics allowed equals true** to that same trigger. Apply both conditions to every firing trigger attached to the tag. Keep the original gameplay event names and fields; their exact mapping is in [GAME-TRACKING.md](GAME-TRACKING.md).

Check Cloudflare-only variables, lookup tables, and trigger conditions for hardcoded old URLs. Cloudflare uses clean paths such as `/games-stats`, `/privacy-policy`, and `/blog/ahrefs-certificate`; games still use `/bubble-pop/`, `/crystal-guard/`, and `/spooder-solitaire/`. Change exact `.html` URL/path filters in the Cloudflare copies to match these paths. Preserve the legacy variables/filters used on GitHub. Normal built-in Page URL/Page Hostname values update automatically.

Review **Tag Sequencing** on every Cloudflare copy: sequenced setup/cleanup tags ignore their own firing triggers. Do not let a Cloudflare tag invoke a legacy banner, legacy Google initializer, or other GitHub-only tag. Use the appropriate Cloudflare setup tag only if needed, and ensure it does not duplicate an initializer already running. Inspect custom templates and Custom HTML for hardcoded old-domain filters or additional tracker installation.

Do not copy advertising tags or other tools outside the banner's analytics purpose into the Cloudflare branch. All advertising consent remains denied. Other legacy tags must also be restricted to their intended hosts so they cannot start on Cloudflare when GTM loads.

### Keep game destinations and payloads intact

Only initialization tags use `yd_analytics_ready`; gameplay tags keep their gameplay triggers. The existing 13 event payloads are unchanged, including Crystal Guard's `score` field on `score_submission` (the other games use `game_score`).

Bubble Pop already initializes Firebase Analytics destination `G-CH120T2QKY` and Crystal Guard initializes `G-4PZEYHZLYW`, now only after consent. Do not add a second Google initializer for these same IDs. If an existing GTM configuration already initializes either ID, make the Cloudflare copy exclude that game's page or otherwise keep one initializer for that destination; keep event routing intact. Spooder retains its original Firebase config but does not initialize Firebase Analytics.

Firestore leaderboard connections are separate, continue to use the same projects and records, and need no rule changes for this domain migration. No Firebase Auth or new authentication flow was added.

## 4. GA4 and Clarity settings

You can retain the existing GA4 properties, streams, and measurement IDs. In **GA4 → Admin → Data streams → your web stream → edit stream details**, update its website URL to `https://yunadata.pages.dev/` (or the corresponding game URL for a game-specific stream). This does not rewrite historical events. During coexistence, use the **Hostname** dimension to distinguish GitHub and Cloudflare traffic. Review any reporting filters or dashboard filters that explicitly match the old host.

No cross-domain linking is required just to accept events from the new host. Consent preferences and first-party cookies belong to each origin, so visitors make a fresh choice on Cloudflare. Do not copy the old site's local-storage consent into the new site.

The Cloudflare code already queues this Clarity signal before its loader:

```javascript
window.clarity('consentv2', {
  ad_Storage: 'denied',
  analytics_Storage: 'granted'
});
```

The capital `S` is intentional. This is explanatory code, not another GTM tag to install. Withdrawal sends denied and refreshes the page to unload running trackers.

**The earlier blanket instruction to change Clarity's project-wide cookie setting is superseded during coexistence.** If both sites share a Clarity project, that setting affects GitHub too. The new site gates the loader and sends its own explicit signal; verify this in Clarity without blindly changing settings used by the old site. If you choose a separate Clarity project for Cloudflare, use that project's ID only in the Cloudflare tag and turn cookies-by-default off in its Settings → Setup. Review masking and retention for whichever project you use.

## 5. Publish the container, then upload to Cloudflare

1. In GTM Preview, check the GitHub website: the old banner and intended legacy tags should behave as before, and no `CF -` tags should fire there.
2. Publish the hostname-scoped GTM workspace. This keeps the legacy branch in place while preparing the new branch. Do not publish the earlier global-pause/global-retrigger plan.
3. Upload the complete updated website to the existing `yunadata` Cloudflare Pages project. See [CLOUDFLARE-SETUP.md](CLOUDFLARE-SETUP.md). Keep GitHub files unchanged.
4. Test `https://yunadata.pages.dev/`, first in a clean browser without Tag Assistant, then with GTM Preview. A branch preview URL intentionally cannot test production analytics.

Do not upload the new production site while the old GTM banner and legacy tags are still allowed to run on all hostnames: after acceptance, they could conflict with the new consent controls. If you have already uploaded it, finish this container separation before inviting visitors.

## 6. Verify both websites

| Check | Expected result |
| --- | --- |
| GitHub first visit / accept / reject | Existing banner and intended legacy tracking still work; no Cloudflare tags |
| Cloudflare before choosing / after rejection | New banner only; no GTM, GA, Firebase Analytics, Clarity, or embedded report requests |
| Cloudflare analytics only | One GTM loader; intended Cloudflare measurement tags only; ads denied; report stays unloaded |
| Cloudflare embedded reports only | Looker Studio report can load; analytics stays off |
| Cloudflare returning visitor / deep blog URL | Valid choice restored before analytics starts; one initializer per destination |
| Cloudflare late opt-in during a game | Only subsequent gameplay is tracked; accepted events can wait briefly in memory for GTM |
| Cloudflare withdrawal | Analytics consent denied, accessible measurement cookies cleared, page refreshed; a running game restarts |
| Other open Cloudflare tabs | Consent changes propagate; withdrawal refreshes tabs with running tracking |
| Game privacy / settings | Privacy opens in a new tab; saved choice appears in settings; leaderboards remain independent |
| Local/private/Cloudflare branch preview | No production GTM or Firebase Analytics, even after acceptance |

In Tag Assistant, confirm denied defaults precede the grant, only `analytics_storage` is granted, initialization fires on `yd_analytics_ready`, and legacy banner/measurement tags never fire on Cloudflare. Basic consent mode intentionally prevents Tag Assistant from seeing GTM until analytics is allowed.

Check GA4 DebugView for the original gameplay events and one initial page view per intended destination. Check Clarity receives analytics granted and advertising denied. Test real play on desktop and phone; avoid synthetic writes to the live leaderboard. Ordinary hosting/media/font, selected fragrance-feed, and Firestore requests are independent of optional analytics.

To repeat a first-visit test, remove only `yunadata_consent_v1` from local storage and `yunadata_consent_v1_session` from session storage, then reload. Withdrawing consent is the supported way to stop already-running tracking. Do not delete unrelated game/browser data.

The code and URL migration were checked offline. The managed browser service was unavailable, and your unpublished GTM workspace/account settings cannot be verified from these source files. These live checks remain required before relying on the tracking reports.

## Official references

- [Google: trigger filters](https://support.google.com/tagmanager/answer/7679316?hl=en)
- [Google: trigger alternatives, exceptions, and sequencing](https://support.google.com/tagmanager/answer/7679318?hl=en)
- [Google: GTM consent settings](https://support.google.com/tagmanager/answer/10718549?hl=en)
- [Google: website consent implementation](https://developers.google.com/tag-platform/security/guides/consent)
- [Google: edit a web data stream URL](https://support.google.com/analytics/answer/9304776?hl=en)
- [Microsoft: Clarity consent mode](https://learn.microsoft.com/en-us/clarity/setup-and-installation/consent-mode)
- [Microsoft: Clarity ConsentV2 API](https://learn.microsoft.com/en-us/clarity/setup-and-installation/clarity-consent-api-v2)
- [Firebase: Web Analytics APIs](https://firebase.google.com/docs/reference/js/analytics)
