Client-side tracking & consent
Executive Summary
Searchflex has a severe and urgent data privacy crisis that requires immediate attention: credit card details are being transmitted to Meta Pixel, a critical compliance failure that exposes the business to significant regulatory risk under GDPR, CCPA, and payment card industry standards. The overall audit score is 0 out of 100, reflecting the gravity of the issues uncovered across just a single URL audited. Compounding the PII breach, tags are continuing to fire even after users select "Reject All" on the consent banner, meaning consent signals are being ignored entirely and user choices are not being honoured. On the implementation side, there are also duplicate installs of both GA4 and Google Tag Manager, which will corrupt analytics data and inflate reported metrics, making any business decisions based on that data unreliable. With 23 issues in total — two critical and 21 high severity — this site should be treated as non-compliant with immediate remediation required, starting with the suppression of all tags pending a full consent and data layer audit.
At a glance
Top recommendations
CRITICAL Stop credit card data leaking into Meta Pixel immediately
Raw credit card data is being transmitted to Facebook's /tr/ endpoint via the post_body parameter — this violates PCI-DSS, GDPR Article 9, and Meta's own platform policies, exposing the business to fines and potential account termination.
How to fix
- In GTM, open the Meta Pixel tag (ID 2322181838224260) and add a Tag Firing Exception tied to any trigger that fires on payment or form-submission pages to halt firing immediately while you investigate.
- Audit every form on the site that collects card data and confirm no GTM dataLayer.push() or fbq() call is made before the payment iframe/tokenisation step — card fields should never be in the DOM accessible to JavaScript at the point pixel fires.
- If you are using Meta's Advanced Matching or a custom fbq('track') call that passes form field values, remove all references to card-related input selectors (e.g. input[name*='card'], input[name*='cvv']) from any GTM Variable of type DOM Element or JavaScript Variable.
- Switch Meta Pixel conversion events to server-side via Meta Conversions API (CAPI) using a hashed, tokenised identifier only — never raw card data — and block the browser-side pixel from firing on checkout confirmation pages.
- Validate by loading the checkout flow in GTM Preview mode and inspecting the Meta Pixel tag's fired network request in the browser Network tab, filtering for facebook.com/tr — confirm post_body contains no card patterns before re-enabling the tag in production.
CRITICAL / HIGH — PII (phone numbers) leaking to Meta Pixel and GA4
Phone numbers detected across PageView, Lead, Contact, CompleteRegistration, and GA4 collect calls create GDPR Article 5(1)(c) data minimisation violations and can trigger ICO/DPA enforcement as well as platform policy bans.
How to fix
- In GTM, audit every Custom JavaScript Variable and DOM Element Variable that feeds parameters to the Meta Pixel fbq() calls and the GA4 Configuration / Event tags — identify any variable pulling from phone input fields, URL query strings containing tel: values, or dataLayer keys such as user_phone or phone_number.
- Remove or replace those variables; where Meta Advanced Matching requires phone, hash it client-side using SHA-256 before passing: fbq('init', 'PIXEL_ID', {ph: sha256(normalised_phone)}) — never pass raw digits.
- For GA4, open the GA4 Configuration tag in GTM and enable the Built-In Variable Redaction setting; additionally add a GA4 property-level data filter in the GA4 Admin > Data Settings > Data Filters to block internal and PII-bearing hits.
- Check URL query parameters on searchflex.com pages — if phone numbers appear in the dl= (document location) parameter, add a GA4 URL exclusion regex in Admin > Data Streams > Configure Tag Settings > List unwanted referrals / excluded parameters, or strip them server-side before the page renders.
- For Meta server-side events via CAPI, ensure the Conversions API Gateway or server payload hashes ph with SHA-256 and omits raw values.
- Validate by re-running GTM Preview, capturing a facebook.com/tr network request in the browser Network tab, and confirming no numeric strings matching phone patterns appear in any parameter; repeat for region1.google-analytics.com/g/collect requests.
HIGH GA4 and Meta Pixel tags fire after Reject All — fix Consent Mode v2 integration
Tags firing despite a Reject All consent signal breach GDPR/PECR and invalidate your CMP's consent records, creating direct regulatory liability and undermining user trust.
How to fix
- In your CMP (e.g. Cookiebot, OneTrust, Usercentrics), verify the Google Consent Mode v2 integration is publishing window.dataLayer pushes for 'consent' commands with ad_storage, analytics_storage, ad_user_data, and ad_personalization all set to 'denied' BEFORE the GTM container snippet executes.
- In GTM, open the GA4 Configuration tag and set the Consent Settings to require analytics_storage — under Advanced Settings > Consent Checks tick 'Require additional consent for tag to fire' and select analytics_storage.
- Open the Meta Pixel GTM tag and add a Trigger Exception using a Custom JavaScript Variable that returns true when the CMP consent object shows marketing/advertising cookies denied — or gate it on a dataLayer variable consent_state.advertising === 'denied'.
- Ensure GTM's own Consent Initialization trigger fires the CMP consent signal tag before all other tags; in GTM Trigger order, the CMP consent tag must use the Consent Initialization - All Pages trigger type, not Page View.
- Validate by opening GTM Preview, clicking Reject All in the CMP, then checking the Tags tab — GA4 Configuration and Meta Pixel tags must appear under 'Tags Not Fired'; also confirm in GA4 DebugView that no events appear for a rejected session.
HIGH Remove duplicate GTM, GA4, and Meta Pixel installations
Three instances each of GTM, GA4, and Meta Pixel on the same page will triple-count every event, inflating conversion data, skewing ROAS calculations, and corrupting audience segments used for paid media optimisation.
How to fix
- In GTM Preview, load the homepage and check the Tags summary — identify all GA4 Configuration tags and confirm only one fires per page; delete or pause duplicate GA4 Configuration tags, keeping a single tag tied to G-MEEH4ZY34T.
- Search the site's source HTML and server-side templates (including header.php, layout files, or CMS theme settings) for hardcoded gtag.js or analytics.js snippet calls and remove any that exist outside GTM — GA4 should fire only through GTM.
- For Meta Pixel, search codebase and CMS plugin settings for hardcoded fbq('init', '2322181838224260') calls outside GTM; remove duplicates leaving one GTM-managed Meta Pixel tag.
- For GTM itself, inspect the page source for multiple occurrences of googletagmanager.com/gtm.js?id=GTM-XXXXXX — each container should appear exactly once in <head> (script) and once in <body> (noscript iframe); remove surplus instances from theme files, plugins, or page builders.
- Validate by opening the browser Network tab, filtering for google-analytics.com/g/collect and facebook.com/tr — each page load should produce exactly one GA4 pageview hit and one Meta Pixel PageView hit; confirm in GA4 Realtime that page_view events are not duplicated.
HIGH Consent gate not blocking tags: implement Consent Mode v2 with Basic or Advanced mode
Without a properly configured Consent Mode v2 setup, Google's ad platforms cannot model conversions for consented users, degrading Smart Bidding performance and creating compliance gaps under the EU DMA.
How to fix
- Confirm your CMP supports Consent Mode v2 natively (Cookiebot, OneTrust, and Usercentrics all have certified GTM integrations) — enable the Google Consent Mode v2 template from the GTM Community Template Gallery for your CMP.
- Set the default consent state to 'denied' for analytics_storage, ad_storage, ad_user_data, and ad_personalization using gtag('consent', 'default', {...}) firing on the Consent Initialization trigger before any other tags.
- Configure the CMP to call gtag('consent', 'update', {...}) with 'granted' values only when the user accepts the relevant categories.
- For GA4, enable modelled conversions in Google Ads by linking the GA4 property and ensuring the Google tag's consent_mode parameter is visible — check Admin > Data Collection > Consent mode is showing 'Active'.
- Validate in GTM Preview by accepting consent, then rejecting — inspect the dataLayer panel for consent events and confirm update commands carry the correct granted/denied values; cross-check in GA4 Admin > Data Collection that consent signal percentages are above 0%.
HIGH Duplicate dataLayer installations causing GTM container to load multiple times
Multiple GTM container loads mean every Custom Event trigger fires multiple times per user interaction, corrupting event counts and making trigger-based tag firing unpredictable.
How to fix
- Search all JavaScript files, CMS plugins (e.g. WooCommerce Google Tag Manager, MonsterInsights), and page builder outputs for window.dataLayer = window.dataLayer || [] initialisation calls — ensure this line appears only once, before the GTM snippet.
- In GTM, add a Custom HTML tag that fires on All Pages - Once Per Page and includes a guard: if (window._gtmLoaded) return; window._gtmLoaded = true; — this prevents duplicate container execution if the snippet has been embedded more than once temporarily.
- Audit WordPress plugins or Shopify app settings that inject GTM snippets independently (e.g. PixelYourSite, WP Google Tag Manager) and disable any that duplicate the container already loaded via your primary GTM snippet.
- Validate by opening the Network tab in DevTools, filtering for gtm.js, and confirming only one request fires on page load with status 200; in GTM Preview the container summary should show a single page load event.
LOW Add 'event' key to all dataLayer.push() calls
GTM Custom Event triggers match on the event key; pushes without it are invisible to GTM, meaning any tag relying on those pushes will never fire and conversion or engagement data will be silently lost.
How to fix
- Audit all dataLayer.push() calls in the site codebase using a global search for dataLayer.push( — identify every instance missing an event property.
- Add a descriptive event name string to each push following the GA4 snake_case convention, e.g. dataLayer.push({ event: 'form_start', form_id: 'contact' }).
- In GTM, create or update Custom Event triggers to match the new event names exactly — use the Trigger type 'Custom Event' with the Event Name field matching your chosen string.
- Where pushes are generated by third-party plugins (e.g. WooCommerce, Gravity Forms hooks), use the plugin's built-in GTM/dataLayer event naming settings rather than patching output manually.
- Validate in GTM Preview by performing the tracked action and confirming the named event appears in the dataLayer panel on the left-hand summary; then publish and verify the corresponding GA4 event appears in DebugView within seconds.
Consent matrix (trackers fired by state)
| URL | default | accept_all | reject_all | CMP |
|---|---|---|---|---|
| https://searchflex.com/ | 14 | 18 | 14 | cookieyes |
Issues (8 types across 26 occurrences)
| Severity | Category | Issue | Affected | Recommendation |
|---|---|---|---|---|
| critical | pii | PII (credit_card) sent to Meta Pixel Detected credit_card in params ['post_body'] of https://www.facebook.com/tr/ |
1 URLShow listhttps://searchflex.com/ |
Hash, redact, or remove PII before sending. Use Enhanced Conversions / CAPI with hashed values where required. |
| high | data_quality | Duplicate GA4 install Found 3 instances of GA4 on the same page; may double-count events. |
1 URLShow listhttps://searchflex.com/ |
Audit GTM containers + hard-coded snippets and keep a single GA4 install. |
| high | data_quality | Duplicate gtm install Found 3 instances of gtm on the same page; may double-count events. |
1 URLShow listhttps://searchflex.com/ |
Audit GTM containers + hard-coded snippets and keep a single gtm install. |
| high | data_quality | Duplicate Meta Pixel install Found 3 instances of Meta Pixel on the same page; may double-count events. |
1 URLShow listhttps://searchflex.com/ |
Audit GTM containers + hard-coded snippets and keep a single Meta Pixel install. |
| high | pii | PII (phone) sent to GA4 Detected phone in params ['_p', 'cid', 'gtm', 'sid', 'uafvl'] of https://region1.google-analytics.com/g/collect?v=2&tid=G-MEEH4ZY34T>m=45Pe64r1v9205095977z89205091 |
1 URLShow listhttps://searchflex.com/ |
Hash, redact, or remove PII before sending. Use Enhanced Conversions / CAPI with hashed values where required. |
| high | pii | PII (phone) sent to Meta Pixel Detected phone in params ['fbp', 'id', 'it', 'plt', 'ts'] of https://www.facebook.com/tr/?id=2322181838224260&ev=PageView&dl=https%3A%2F%2Fsearchflex.com%2F&rl=& |
1 URLShow listhttps://searchflex.com/ |
Hash, redact, or remove PII before sending. Use Enhanced Conversions / CAPI with hashed values where required. |
| high | consent | Tags fire after Reject All Vendors firing despite Reject All: GA4, Meta Pixel. This breaches GDPR/PECR and is incompatible with Consent Mode v2 'denied' signals. |
1 URLShow listhttps://searchflex.com/ |
Add consent-aware GTM triggers (Consent Mode v2 'ad_storage' / 'analytics_storage' = denied) and verify tags wait for an Update signal before firing. |
| low | data_quality | Most dataLayer pushes lack 'event' key Pushes without an event name can't be picked up by GTM Custom Event triggers. |
1 URLShow listhttps://searchflex.com/ |
None |