Tracking health
Preventive audit of conversion tracking across all configured ad platforms — Meta pixels + CAPI, Google Ads conversion actions, and final-URL tracking-parameter consistency on every platform — with a GA4 cross-check. Use when the user asks to check tracking, audit conversion measurement, verify pixels / tags, check that ads carry the right utm / tracking parameters for the campaign they are in, diagnose why conversions stopped or look wrong, sanity-check CV counting, or requests a 計測ヘルスチェック / タグ・計測監査 / パラメータ整合性チェック / 計測が壊れていないか確認. Reads STRATEGY.md and STATE.json, produces a per-platform tracking scorecard (OK / Watch / Broken per check) and a fix list ranked by revenue risk.From its SKILL.md
npx -y skills add logly/mureo --skill tracking-healthAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
SKILL.md
18.0 KB, as published. Nobody here has run it
Tracking Health
PREREQUISITE: Read
../_mureo-shared/SKILL.mdfor auth, security rules, output format, and Tool Selection (Read/Write on Code,mureo_strategy_*/mureo_state_*MCP on Desktop / Cowork).
Preventively audit conversion tracking across every configured platform. Measurement breakage is the costliest silent failure in ad ops — spend keeps flowing while the signal the algorithm optimizes toward is wrong or absent — so this skill hunts for it before it shows up as a mysterious CPA spike.
Prerequisites
- STRATEGY.md and STATE.json must exist in the current directory (run the
onboardskill first if not)
Steps
Before you start: Run the Diagnostic preamble from ../_mureo-shared/SKILL.md — load learning insights (mureo_learning_insights_get) and consult advisors (mureo_consult_advisor) before drawing conclusions.
-
Establish today: call
mureo_state_getfirst, on every host (including Claude Code, where you would otherwiseReadthe file) and takeserver_nowfrom its response — ISO 8601 with UTC offset, e.g.2026-07-28T10:12:33+09:00. Its date is the only source of the current date for this run: judging whether a pixel'slast_fired_timeis "recent" is a comparison against it, and theobservation_dueyou write in step 12 isserver_now's date + 7 days. Do not shell out (this skill must run in Bash-less headless hosts) and do not read the date off STATE.json —last_synced_at,reports.*.periodandaction_logtimestamps are history, never evidence of what day it is now. Never writeserver_nowinto STATE.json: it is a response field, and a persisted copy becomes tomorrow's stale "today". -
Load context: Read STRATEGY.md (especially each Goal's declared conversion definition, Persona, and Operation Mode) and STATE.json (the same
mureo_state_getresponse from step 0 on MCP hosts). Note what the operator considers a real conversion for each platform (a lead form submit, a purchase, a phone call) — the audit below is only meaningful relative to that intent. -
Discover available platforms: Identify all configured platforms from STATE.json
platformsand which data sources (GA4, Search Console) are accessible. Also enumerate installed plugin platforms (mcp__mureo__<plugin>_*tools) and any hosted official-MCP connector present in the session (e.g. TikTok'stt-ads-*tools, STATE.json keytiktok_ads); include them best-effort — see../_mureo-shared/SKILL.md→ Plugin platforms and Hosted-connector platforms. -
Meta Ads — pixel inventory + health (prefer mureo native):
- Inventory: call
meta_ads_pixels_listto enumerate every pixel in the account (id, name,last_fired_time). Zero pixels on an account running conversion campaigns is a Broken finding on its own. - Per-pixel health: for each pixel call
meta_ads_pixels_getand checklast_fired_timeis recent (a pixel that stopped firing = Broken). Callmeta_ads_pixels_stats(windowlast_30d, widen tolast_90dto catch slow degradations) and look for a sudden drop or a flatline in PageView / Lead / Purchase volume — a step-down that lines up with a site deploy is the classic pixel break. - Event coverage: call
meta_ads_pixels_eventsto list the distinct standard + custom events the pixel actually receives, with sample parameters. Flag when the event the operator's Goal depends on (e.g.Lead,Purchase) is absent or firing with missing parameters (novalue/currencyon a Purchase). - Per-campaign
result_indicatoraudit: callmeta_ads_insights_report(levelcampaign) and inspect each campaign'sresult_indicator. Flag any campaign optimized foractions:link_clickwhere the operator expects real leads / purchases (actions:offsite_conversion.fb_pixel_lead) — that campaign is buying clicks, not conversions, and its "results" number is not comparable to a lead-optimized campaign's. This CV-definition-mismatch detection is a mureo value-add; see daily-check step 4. - CAPI presence check: mureo ships no dedicated tool that reports a browser-vs-server event split, so treat this as best-effort. Use
meta_ads_pixels_eventsto see whether server-originated (Conversions API) events appear alongside browser events, and note in the scorecard when a high-value account is relying on the browser pixel alone (no CAPI) — a resilience risk as browser signal degrades. mureo can send server events (meta_ads_conversions_send/meta_ads_conversions_send_lead/meta_ads_conversions_send_purchase), but a definitive server/browser coverage split still requires Events Manager; say so rather than guessing. - If mureo's Meta Ads tools are unavailable (i.e.
MUREO_DISABLE_META_ADS=1aftermureo providers add meta-ads-official), fall back to the officialmeta-ads-officialhosted MCP for whatever pixel / insights surface it exposes, and note that theresult_indicatorCV-mismatch analysis is a mureo-specific value-add absent from the official MCP.
- Inventory: call
-
Google Ads — conversion actions + status (prefer mureo native):
- Inventory + status: call
google_ads_conversions_listto list every conversion action with itsstatus(ENABLED/HIDDEN/REMOVED) andcategory(PURCHASE,SIGNUP, …). For any action whose configuration you need to inspect further, callgoogle_ads_conversions_get. A campaign optimizing toward aREMOVED/HIDDENaction, or an account with no ENABLED conversion action, is a Broken finding. - Recent-data check: call
google_ads_conversions_performance(periodLAST_30_DAYS) — only rows with conversions > 0 are returned, so an ENABLED action that is absent from the report has recorded no recent conversions. Cross-reference itsfirst_date/last_date: an action that used to fire and went silent is a likely tag break; a brand-new action with no data yet is expected. Flag silent actions as Watch (or Broken if it is the primary action a live campaign depends on). - Primary / secondary counting sanity: Google Ads counts only primary actions into the "Conversions" column that bidding optimizes toward; secondary actions are observational. mureo's read tools do not expose the primary/secondary flag directly, so verify it in the Google Ads UI and flag the common misconfigurations: (a) a micro-conversion (e.g.
PageView) set as primary — inflates Conversions and misleads Smart Bidding; (b) the true macro-conversion set as secondary — starves bidding of the signal. Also flag double-counting risk when two actions plausibly fire on the same event. - If mureo's Google Ads tools are unavailable (
MUREO_DISABLE_GOOGLE_ADS=1aftermureo providers add google-ads-official), fall back to the officialgoogle-ads-officialMCP for the conversion-action listing / performance surface it exposes, and note that the recency and counting-sanity heuristics still apply.
- Inventory + status: call
-
Cross-check with GA4 (when available): mureo ships no native GA4 tools — GA4 is reached as a configured data source, so pull the site's conversion count from that source (do not reference a
ga4_*tool that does not exist). Compare each platform's ads-reported conversions against GA4's conversions for the same event and window. A divergence > 20 % is a flag — report the likely causes so the operator can triage:- Attribution window / model differences (platform click-through + view-through vs GA4 last-click).
- Consent Mode / cookie loss suppressing GA4 (or platform) tags for a slice of users.
- Tag coverage gaps — the pixel/tag missing on some conversion pages, or duplicated on others.
- Cross-device / logged-in attribution the platform can resolve but GA4 cannot. Present the discrepancy as a signal to investigate, not proof one number is wrong — the platforms genuinely count differently.
-
Search Console: N/A for conversion tracking — Search Console has no conversion signal. Skip it here (organic conversion behavior belongs in daily-check / weekly-report).
-
Plugin & hosted-connector platforms (best-effort): for a plugin platform (
plugin:<dist>:<provider>) or a hosted connector (tiktok_ads), report only the basic tracking status its own tools expose and emitanalytics_not_available_for_<platform>for the mureo-only deep checks (pixel health,result_indicator, conversion-action recency) — do not fabricate a tracking verdict from an integration's tool schemas. See../_mureo-shared/SKILL.md→ analytics-module parity and Hosted-connector platforms. The one exception is step 8's tracking-parameter consistency check: it is platform-neutral and analyses ad records you pass in rather than a per-platform analytics module, so it applies to a plugin or hosted platform exactly as it does to Google and Meta — whenever that platform's own tools can list ads with their destination URLs. -
Tracking-parameter consistency — every platform (
analysis_tracking_consistency_check): steps 3-7 ask whether the conversion signal arrives. This step asks whether the click that produced it lands in the right row of the analytics everyone downstream reads. An ad uploaded into campaign B carrying campaign A'sutm_campaignbreaks segment-level reporting while delivery, spend and conversions all look perfectly healthy — nothing appears broken, so nobody investigates.- Collect ad records for every platform you enumerated in step 2, into one platform-neutral list. Each record is
{ad_id, campaign_id, campaign_name, platform, final_urls, impressions}:- Google Ads:
google_ads_ads_listreturnsfinal_urls,campaign_idandcampaign_namedirectly. - Meta Ads:
meta_ads_ads_list— the link is increative.object_story_spec(link_data.link, or the call-to-action link onvideo_data/photo_data/template_data), andcreative.url_tagsis appended to it at delivery time, so pass the link withurl_tagsmerged onto its query string. - Plugin platforms: use the plugin's own ad-listing tool and its
final_urlfield; pass the canonicalplugin:<dist>:<provider>key asplatform(see../_mureo-shared/SKILL.md). - Bridged / hosted connectors: pass whatever destination URL the connector reports. The Amazon Ads bridge exposes no destination-URL field — pass those ads with
final_urls: []so they are reported as unchecked rather than clean. impressionsis what grades the finding: supply it per ad (a per-ad performance report over the audited window) so mureo can tell a served mis-tagged ad — a data-integrity incident needing a reporting caveat — from one that never served, a cheap fix. Omit it only when the platform cannot give it; omitted is not the same as0.
- Google Ads:
- Declared convention: if STRATEGY.md has a
## Tracking Conventionsection, pass that text asconvention_markdownverbatim. Do not interpret it yourself — mureo parses it. Without one, the zero-configuration checks still run. - Report what comes back, and only that. Findings carry
severity,delivery_state, the ad ids and the evidence (which parameters differ, which campaign the borrowed scheme belongs to, which landing page two schemes collided on). mureo deliberately does not say which of two schemes is correct — put both in front of the operator. Never add a finding of your own by eyeballing utm values: guessing an account's convention is the failure this check replaces. In particular, onlyutm_source/utm_medium/utm_campaignidentify a campaign;utm_contentandutm_termvary per creative and per keyword by design and are deliberately not compared, so do not report them as inconsistencies. ads_without_readable_urlis not a pass. List those ads explicitly as not checked on the platform they came from, and carry the tool'snotesinto the scorecard evidence.- Full list of what this check can and cannot detect:
docs/tracking-consistency.md.
- Collect ad records for every platform you enumerated in step 2, into one platform-neutral list. Each record is
-
Scorecard: present a per-platform tracking scorecard, one row per check, each rated OK / Watch / Broken:
Platform Check Status Evidence Meta Ads Pixel firing (last_fired_time) OK fired 2h ago Meta Ads Lead event present Broken no Lead events in 30d Meta Ads result_indicator vs Goal Watch 2 campaigns on link_click Meta Ads CAPI present Watch browser pixel only Meta Ads URL tracking consistency OK 0 findings / 34 ads Google Ads Primary conversion action ENABLED OK "Purchase" ENABLED Google Ads Recent conversion data Broken 0 conv in 30d for "Lead" Google Ads Primary/secondary counting Watch verify PageView not primary Google Ads Ads CV vs GA4 CV (±20%) Watch Ads 120 / GA4 78 (+54%) Google Ads URL tracking consistency Broken 16 ads carry campaign A's utm_campaign Amazon Ads URL tracking consistency n/a not checked — bridge exposes no URLRate the consistency row Broken when any finding has
delivery_state: served(reporting is already wrong), Watch when findings exist but nothing served, and OK only when the platform's ads were all readable and produced no findings. -
Fix list — ranked by revenue risk: turn every Broken / Watch into a concrete fix, ordered by how much spend is riding on the broken signal (a broken primary action on the highest-spend campaign is #1; a missing secondary action on a paused campaign is last). For each fix state: what is wrong, the concrete remediation, and the platform/UI or tool that performs it.
-
Approval gate for any state-mutating fix: most remediations here are operator actions (re-add a tag on the site, flip an action to primary in the Google Ads UI, install CAPI). Where a fix does mutate platform state through a mureo tool (e.g.
google_ads_conversions_updateto re-enable an action,google_ads_conversions_createto add one, sending backfill events viameta_ads_conversions_send), apply the Confirm Before Write Operations rule from../_mureo-shared/SKILL.md— show the current value and the proposed change and get explicit approval before the call. For an official/hosted-MCP write, also self-apply the STRATEGY.md## Guardrailsrules yourself (mureo's PolicyGate cannot see that call) — see../_mureo-shared/SKILL.md→ Hosted-connector platforms. A plugin / bridged write (including Amazon Ads) does reach the gate — exactly on the money tools mureo declares paths for (the 13 money-carrying Amazon tools), with the pattern scan still applied underneath as a floor, and best-effort on argument-key patterns alone for anything else — so still state the applicable cap. -
Record any change to
action_log: for each approved state-mutating fix, log toaction_log(viamureo_state_action_log_append) withmetrics_at_action(the pre-fix conversion counts / firing state you could read) and anobservation_due7 days out fromserver_now's date, so daily-check's evidence step confirms the fix actually restored the signal. A pure audit with no changes still logs a summary entry (findings + scorecard verdict), with noobservation_due. -
Persist the report summary (best-effort): Call
mureo_state_report_setwithreport="tracking"and a concisesummaryobject so the read-only dashboard can render this audit without re-running you. Follow this convention:generated_at: ISO 8601 timestamp of this run — useserver_nowperiod: the window audited (e.g."LAST_30_DAYS")totals: the account's headline figures, using the canonical metric vocabulary —spend,conversions,cpa,ctr,clicks,impressions. This is the block the dashboard renders as figures. Raw numbers only:773957, not"¥773,957";0.0466, not"4.66%"— one of those keys carrying a string is refused, because it sits where the view reads a figure and renders as nothing. A key outside the vocabulary may ride along: it is stored, just not shown as a headline number. Omittotalsentirely if this run gathered no account-level figures.kpis: the per-platform breakdown, not the headline row — tracking health counts (e.g.{"meta_ads": {"pixels_ok": 1, "broken": 1}}), the tracking-parameter consistency counts from step 8 ({"google_ads": {"tracking_findings": 3, "ads_unchecked": 0}}) and any ads-vs-GA4 divergenceflags: notable items (e.g.["meta_lead_event_missing", "google_primary_action_zero_conv", "tracking_parameter_mismatch"])narrative: the overall verdict (OK / Watch / Broken) and what you propose next, at most 400 characters — the tool refuses a longer one rather than truncating it (a sentence cut in half is worse than a long one). Do not restate the figures and do not list the findings here: numbers belong intotals, findings inflags.
Reflect the FINAL state, and persist this LAST — after every
action_logentry and any fix you applied this run. This is best-effort: ifmureo_state_report_setis unavailable (e.g. a pure file-mode host without the context MCP), skip it silently — the rest of this skill still works.