codymaster 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/README.md +285 -0
- package/adapters/antigravity.js +15 -0
- package/adapters/claude-code.js +17 -0
- package/adapters/cursor.js +16 -0
- package/commands/bootstrap.md +49 -0
- package/commands/build.md +48 -0
- package/commands/content.md +48 -0
- package/commands/continuity.md +60 -0
- package/commands/debug.md +51 -0
- package/commands/demo.md +96 -0
- package/commands/deploy.md +51 -0
- package/commands/plan.md +42 -0
- package/commands/review.md +55 -0
- package/commands/track.md +46 -0
- package/commands/ux.md +46 -0
- package/dist/agent-dispatch.js +161 -0
- package/dist/chains/builtin.js +85 -0
- package/dist/continuity.js +385 -0
- package/dist/dashboard.js +926 -0
- package/dist/data.js +122 -0
- package/dist/index.js +2434 -0
- package/dist/judge.js +252 -0
- package/dist/parallel-dispatch.js +359 -0
- package/dist/parallel-quality.js +172 -0
- package/dist/skill-chain.js +258 -0
- package/install.sh +513 -0
- package/package.json +79 -0
- package/skills/.content-factory-state.json +132 -0
- package/skills/.git 2/logs/refs/heads/main +1 -0
- package/skills/.git 2/logs/refs/remotes/origin/main +1 -0
- package/skills/.git 2/objects/02/fb0956734b5f8ba3f918b7defd04a89cfe0076 +0 -0
- package/skills/.git 2/objects/08/1e129d75dc6feac6c02037272e6bd1a04e3324 +0 -0
- package/skills/.git 2/objects/0c/5393416f3c5e01c9a655a802bff0dd52f76f0a +0 -0
- package/skills/.git 2/objects/10/0b9be46978a946a77188f68be725098a122001 +0 -0
- package/skills/.git 2/objects/10/cf041167fc9843610eb3d90259ef3396315fdc +0 -0
- package/skills/.git 2/objects/12/5e19538dd6e1338ffe74f6c4c165b00435bf48 +0 -0
- package/skills/.git 2/objects/16/a9b9d0088d5c1347628b45a2620b479d8ad57c +0 -0
- package/skills/.git 2/objects/17/8c2a9ef93c33ae4eec9d58e82321f9229843a1 +0 -0
- package/skills/.git 2/objects/25/397ae41d09104d763bdcac2695209d85cdea89 +0 -0
- package/skills/.git 2/objects/2f/a836b7947f2d458e1f639788bf4bb0983a3305 +0 -0
- package/skills/.git 2/objects/3a/baaaf0a1c0909c0828335791557125fba911e0 +0 -0
- package/skills/.git 2/objects/42/2924221b81f5ce3c4e4daac9a64a24f9b01f9a +0 -0
- package/skills/.git 2/objects/42/ec0ce707447dc11446a34c9995fb8533801731 +0 -0
- package/skills/.git 2/objects/46/e43ce92866d56ce74b1d750db307cfe6154a15 +0 -0
- package/skills/.git 2/objects/48/5e41b633c63f55b8277bcc59f44f67681f671a +0 -0
- package/skills/.git 2/objects/49/49c596a3a89fa240642acd95dd3258e261eb09 +0 -0
- package/skills/.git 2/objects/50/9d42d8412ef8eaf7f7e138476bac2e4d10ce60 +0 -0
- package/skills/.git 2/objects/55/0c8c389d981b463ef849aeb792d8be3ccb6ec8 +0 -0
- package/skills/.git 2/objects/5d/82d3b18410cdda3ace3677436f0cb599dbe2d2 +0 -0
- package/skills/.git 2/objects/60/0617c58e871a38b33bf29e282d132bb3c381ad +0 -0
- package/skills/.git 2/objects/6a/8369a99c687b7245c92ffaf0e0f0dab9014504 +0 -0
- package/skills/.git 2/objects/79/bea435d40ab531c1aaf6be0432c6a5b7aaed21 +0 -0
- package/skills/.git 2/objects/7e/5ebd79251c2f14e4aceb86c74b6b6daae6b500 +0 -0
- package/skills/.git 2/objects/81/98a822a60178d6d5023ddb3e222cddf048742e +0 -0
- package/skills/.git 2/objects/86/0a0e1943dfe53411d2e499a1f16f46a96ef758 +0 -0
- package/skills/.git 2/objects/86/971fb55fdc081fdbae52376f0f13e57a4e9b04 +0 -0
- package/skills/.git 2/objects/88/b89dd609a0a03f8d4fe8bfde20d5b8fc1d326d +0 -0
- package/skills/.git 2/objects/90/8737edb6b7809e32cc01590b4e08ba42a9d40d +0 -0
- package/skills/.git 2/objects/93/d5a8a9a7d4fb7f11491cb596a6880528725118 +0 -0
- package/skills/.git 2/objects/98/46a2ab81d0c3b3eb00ef88fc56989aa7e9f316 +0 -0
- package/skills/.git 2/objects/9b/d8dd1e49cf274eaf9c555f3ab39dce7af5715e +0 -0
- package/skills/.git 2/objects/a1/13329fb0cec96ae78b222d33a24c3b5bc7fa1f +0 -0
- package/skills/.git 2/objects/a9/e6effe626e8a3aea3a8fc3364b492191c6e7d0 +0 -0
- package/skills/.git 2/objects/ad/6de7e48d9782cca9353d1ff0aa1aab7fe1df85 +0 -0
- package/skills/.git 2/objects/af/54ae316f771ff692e299ffcd8bf2f06b413b59 +0 -0
- package/skills/.git 2/objects/b0/4cb8b0b00dad633e731c1472161419e738d674 +0 -0
- package/skills/.git 2/objects/b3/094abb0b9ed46419b269e4a4e36a459690e3b0 +0 -0
- package/skills/.git 2/objects/b9/435c5d4baac2cfc5c83009ddd27b46b60db5f1 +0 -0
- package/skills/.git 2/objects/ba/5da17dbaec5ec2dcfdfd126aead518d1171d5c +0 -0
- package/skills/.git 2/objects/c0/bf58703aa258ba5dd63083bebaec8f223d844c +0 -0
- package/skills/.git 2/objects/c4/701a34edf1fc1bad58ccc57bd03f9426acb59a +0 -0
- package/skills/.git 2/objects/c7/5ccce9a4e5cc74d9b3174550cf6d993ca43638 +0 -0
- package/skills/.git 2/objects/c7/710d59b5a35b0f1f0a0399386643a0bd94c929 +0 -0
- package/skills/.git 2/objects/d1/fe58237112e953e5fec52da22cf38e08be3df9 +5 -0
- package/skills/.git 2/objects/d2/2bbe9fd2f74c95bc5583e803f5e435f1e2cd86 +0 -0
- package/skills/.git 2/objects/d7/e72852ea2bff74581dbf247d400120086229f4 +0 -0
- package/skills/.git 2/objects/d8/d4c3b5553e4fd72807e1d4b49ef07d9ef3ac35 +0 -0
- package/skills/.git 2/objects/dc/75050c2876f6a02ae2a53a3c886f395b622977 +0 -0
- package/skills/.git 2/objects/ee/e8546f95acec500187c08a28a8b9ee02db0dec +0 -0
- package/skills/.git 2/objects/ef/263c059208b416c2146434f10cb2b9fabcba16 +0 -0
- package/skills/.git 2/objects/f3/ae597e84d9a59b88acd21c99bde2eaf686d785 +0 -0
- package/skills/.git 2/objects/f3/f6f5673c821d3d8e76fa267a9e882e7a5387ea +0 -0
- package/skills/.git 2/objects/f9/6e6d0ad02624dd11d5848594d056caef7a5e8b +0 -0
- package/skills/.git 2/objects/ff/278988fc1edf0db3abcf18de795f4cc0b4f3e1 +0 -0
- package/skills/.git 2/refs/heads/main +1 -0
- package/skills/.git 2/refs/remotes/origin/main +1 -0
- package/skills/.pytest_cache 2/v/cache/nodeids +76 -0
- package/skills/.pytest_cache 2/v/cache/stepwise +1 -0
- package/skills/_shared/helpers.md +123 -0
- package/skills/_shared/outputs-convention.md +24 -0
- package/skills/cm-ads-tracker/SKILL.md +109 -0
- package/skills/cm-ads-tracker/evals/evals.json +55 -0
- package/skills/cm-ads-tracker/references/gtm-architecture.md +321 -0
- package/skills/cm-ads-tracker/references/industry-events.md +294 -0
- package/skills/cm-ads-tracker/references/platforms-api.md +238 -0
- package/skills/cm-ads-tracker/templates/capi-payload.md +79 -0
- package/skills/cm-ads-tracker/templates/datalayer-push.js +104 -0
- package/skills/cm-ads-tracker/templates/gtm-variables.js +56 -0
- package/skills/cm-brainstorm-idea/SKILL.md +423 -0
- package/skills/cm-code-review/SKILL.md +151 -0
- package/skills/cm-content-factory/SKILL.md +416 -0
- package/skills/cm-continuity/SKILL.md +399 -0
- package/skills/cm-dashboard/SKILL.md +533 -0
- package/skills/cm-dashboard/ui/app.js +1270 -0
- package/skills/cm-dashboard/ui/index.html +206 -0
- package/skills/cm-dashboard/ui/style.css +440 -0
- package/skills/cm-debugging/SKILL.md +412 -0
- package/skills/cm-deep-search/SKILL.md +242 -0
- package/skills/cm-design-system/SKILL.md +97 -0
- package/skills/cm-design-system/resources/halo-modern.md +40 -0
- package/skills/cm-design-system/resources/lunaris-advanced.md +40 -0
- package/skills/cm-design-system/resources/nitro-enterprise.md +39 -0
- package/skills/cm-design-system/resources/shadcn-default.md +37 -0
- package/skills/cm-dockit/README.md +100 -0
- package/skills/cm-dockit/SKILL.md +302 -0
- package/skills/cm-dockit/index.html +443 -0
- package/skills/cm-dockit/package-lock.json +1850 -0
- package/skills/cm-dockit/package.json +14 -0
- package/skills/cm-dockit/prompts/analysis.md +34 -0
- package/skills/cm-dockit/prompts/api-reference.md +24 -0
- package/skills/cm-dockit/prompts/architecture.md +21 -0
- package/skills/cm-dockit/prompts/data-flow.md +20 -0
- package/skills/cm-dockit/prompts/database.md +21 -0
- package/skills/cm-dockit/prompts/deployment.md +22 -0
- package/skills/cm-dockit/prompts/flows.md +21 -0
- package/skills/cm-dockit/prompts/jtbd.md +20 -0
- package/skills/cm-dockit/prompts/personas.md +24 -0
- package/skills/cm-dockit/prompts/sop-modules.md +40 -0
- package/skills/cm-dockit/scripts/doc-gen.sh +121 -0
- package/skills/cm-dockit/scripts/dockit-dashboard.sh +142 -0
- package/skills/cm-dockit/scripts/dockit-runner.sh +607 -0
- package/skills/cm-dockit/scripts/dockit-task.sh +166 -0
- package/skills/cm-dockit/skills/analyze-codebase.md +174 -0
- package/skills/cm-dockit/skills/api-reference.md +237 -0
- package/skills/cm-dockit/skills/changelog-guide.md +195 -0
- package/skills/cm-dockit/skills/content-guidelines.md +190 -0
- package/skills/cm-dockit/skills/sop-guide.md +184 -0
- package/skills/cm-dockit/skills/tech-docs.md +287 -0
- package/skills/cm-dockit/templates/markdown/structure.md +60 -0
- package/skills/cm-dockit/templates/vitepress-premium/.vitepress/config.mts +110 -0
- package/skills/cm-dockit/templates/vitepress-premium/.vitepress/theme/custom.css +189 -0
- package/skills/cm-dockit/templates/vitepress-premium/.vitepress/theme/index.ts +4 -0
- package/skills/cm-dockit/templates/vitepress-premium/package.json +19 -0
- package/skills/cm-dockit/templates/vitepress-premium/tests/frontend.test.ts +45 -0
- package/skills/cm-dockit/tests/runner.test.ts +66 -0
- package/skills/cm-dockit/workflows/export-markdown.md +82 -0
- package/skills/cm-dockit/workflows/generate-docs.md +68 -0
- package/skills/cm-dockit/workflows/setup-vitepress.md +181 -0
- package/skills/cm-example/SKILL.md +26 -0
- package/skills/cm-execution/SKILL.md +268 -0
- package/skills/cm-git-worktrees/SKILL.md +164 -0
- package/skills/cm-how-it-work/SKILL.md +189 -0
- package/skills/cm-identity-guard/SKILL.md +412 -0
- package/skills/cm-jtbd/SKILL.md +98 -0
- package/skills/cm-planning/SKILL.md +130 -0
- package/skills/cm-project-bootstrap/SKILL.md +161 -0
- package/skills/cm-project-bootstrap/templates/AGENTS.md +42 -0
- package/skills/cm-project-bootstrap/templates/frontend-safety.test.js +51 -0
- package/skills/cm-project-bootstrap/templates/i18n-sync.test.js +38 -0
- package/skills/cm-project-bootstrap/templates/pr-template.md +12 -0
- package/skills/cm-project-bootstrap/templates/project-identity.json +29 -0
- package/skills/cm-project-bootstrap/templates/vitest.config.js +10 -0
- package/skills/cm-quality-gate/SKILL.md +218 -0
- package/skills/cm-readit/SKILL.md +289 -0
- package/skills/cm-readit/audio-player.md +206 -0
- package/skills/cm-readit/examples/blog-reader.js +352 -0
- package/skills/cm-readit/examples/voice-cro.js +390 -0
- package/skills/cm-readit/tts-engine.md +262 -0
- package/skills/cm-readit/ui-patterns.md +362 -0
- package/skills/cm-readit/voice-cro.md +223 -0
- package/skills/cm-safe-deploy/SKILL.md +120 -0
- package/skills/cm-safe-deploy/templates/deploy.sh +89 -0
- package/skills/cm-safe-i18n/SKILL.md +473 -0
- package/skills/cm-secret-shield/SKILL.md +580 -0
- package/skills/cm-skill-chain/SKILL.md +78 -0
- package/skills/cm-skill-index/SKILL.md +318 -0
- package/skills/cm-skill-mastery/SKILL.md +169 -0
- package/skills/cm-start/SKILL.md +65 -0
- package/skills/cm-status/SKILL.md +12 -0
- package/skills/cm-tdd/SKILL.md +370 -0
- package/skills/cm-terminal/SKILL.md +177 -0
- package/skills/cm-test-gate/SKILL.md +242 -0
- package/skills/cm-ui-preview/SKILL.md +291 -0
- package/skills/cm-ux-master/DESIGN_STANDARD_TEMPLATE.md +54 -0
- package/skills/cm-ux-master/SKILL.md +114 -0
- package/skills/cro-methodology/SKILL.md +98 -0
- package/skills/cro-methodology/references/COPYWRITING.md +178 -0
- package/skills/cro-methodology/references/OBJECTIONS.md +135 -0
- package/skills/cro-methodology/references/PERSUASION.md +158 -0
- package/skills/cro-methodology/references/RESEARCH.md +220 -0
- package/skills/cro-methodology/references/funnel-analysis.md +365 -0
- package/skills/cro-methodology/references/testing-methodology.md +330 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# Platform Server-Side APIs Reference
|
|
2
|
+
|
|
3
|
+
## Why Server-Side APIs Matter
|
|
4
|
+
|
|
5
|
+
Browser-side pixels face increasing signal loss due to:
|
|
6
|
+
- Ad blockers (15-40% of users block tracking scripts)
|
|
7
|
+
- iOS 14+ and browser privacy restrictions (Safari ITP, Firefox ETP)
|
|
8
|
+
- Cookie deprecation timeline
|
|
9
|
+
|
|
10
|
+
Server-side APIs (CAPI, Events API) send events directly from your server to the platform — bypassing browser restrictions entirely. Combined with browser pixels and deduplication via event_id, this gives you the best possible signal quality.
|
|
11
|
+
|
|
12
|
+
Typical uplift from adding server-side APIs:
|
|
13
|
+
- Meta CAPI: +10-20% more matched conversions
|
|
14
|
+
- TikTok Events API: +8-15% uplift
|
|
15
|
+
- Google Enhanced Conversions: +15-25% conversion recovery
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 1. Meta Conversions API (CAPI)
|
|
20
|
+
|
|
21
|
+
### Setup Methods (choose one)
|
|
22
|
+
|
|
23
|
+
**Option A: Via Server-Side GTM (recommended for non-developers)**
|
|
24
|
+
- Set up GTM Server-Side container (hosted on Google Cloud or Stape.io)
|
|
25
|
+
- Route website events through server GTM → server GTM sends to Meta CAPI
|
|
26
|
+
- No backend code changes needed
|
|
27
|
+
|
|
28
|
+
**Option B: Direct API Integration (for developers)**
|
|
29
|
+
- Endpoint: https://graph.facebook.com/v18.0/{pixel_id}/events
|
|
30
|
+
- Authentication: System User Access Token from Meta Business Manager
|
|
31
|
+
- Server sends HTTP POST for each conversion event
|
|
32
|
+
|
|
33
|
+
### Required Fields for Every CAPI Event
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
{
|
|
37
|
+
"data": [{
|
|
38
|
+
"event_name": "Purchase", // Standard Meta event name
|
|
39
|
+
"event_time": 1703123456, // Unix timestamp (server time)
|
|
40
|
+
"event_id": "uuid-generated-at-conversion", // CRITICAL for dedup
|
|
41
|
+
"action_source": "website", // Required
|
|
42
|
+
"event_source_url": "https://yoursite.com/thank-you",
|
|
43
|
+
"user_data": {
|
|
44
|
+
"em": ["sha256_of_lowercase_email"], // Hashed email
|
|
45
|
+
"ph": ["sha256_of_digitsonly_phone"], // Hashed phone
|
|
46
|
+
"client_ip_address": "123.456.789.0", // Server-detected IP
|
|
47
|
+
"client_user_agent": "Mozilla/5.0...", // From request headers
|
|
48
|
+
"fbp": "_fb.1.1234567890.abcdefg", // _fbp cookie value
|
|
49
|
+
"fbc": "fb.1.1234567890.AbCdEfGhIj" // _fbc cookie value (from fbclid)
|
|
50
|
+
},
|
|
51
|
+
"custom_data": {
|
|
52
|
+
"value": 500000,
|
|
53
|
+
"currency": "VND",
|
|
54
|
+
"content_ids": ["PROD-123"],
|
|
55
|
+
"content_type": "product",
|
|
56
|
+
"contents": [{"id": "PROD-123", "quantity": 1, "item_price": 500000}],
|
|
57
|
+
"num_items": 1,
|
|
58
|
+
"order_id": "ORDER-20240101-001"
|
|
59
|
+
}
|
|
60
|
+
}],
|
|
61
|
+
"access_token": "EAAxxxxxxxxxxxx"
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Deduplication Logic
|
|
66
|
+
|
|
67
|
+
When your browser pixel AND CAPI both fire for the same conversion:
|
|
68
|
+
- Both include identical `event_id` value
|
|
69
|
+
- Meta's system receives both events within 48-hour window
|
|
70
|
+
- Meta matches them by event_id and counts as ONE conversion
|
|
71
|
+
- You see "Matched events" count in Events Manager
|
|
72
|
+
|
|
73
|
+
The `event_id` MUST be:
|
|
74
|
+
- Generated ONCE per conversion (not per request)
|
|
75
|
+
- Identical in both browser dataLayer.push() and CAPI payload
|
|
76
|
+
- Unique across all conversions (use UUID v4)
|
|
77
|
+
|
|
78
|
+
### How to Get CAPI Access Token
|
|
79
|
+
|
|
80
|
+
1. Go to Meta Business Manager → Events Manager
|
|
81
|
+
2. Select your Pixel → Settings
|
|
82
|
+
3. Scroll to "Conversions API"
|
|
83
|
+
4. Click "Generate Access Token" (or use System User token from Business Settings)
|
|
84
|
+
5. Copy token — treat it as a secret (never expose in browser-side code)
|
|
85
|
+
|
|
86
|
+
### Testing CAPI Events
|
|
87
|
+
|
|
88
|
+
Use Meta's Test Events tool in Events Manager → Test Events tab.
|
|
89
|
+
Set test_event_code in payload during development:
|
|
90
|
+
Add "test_event_code": "TEST12345" to the payload root (not inside data array).
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 2. TikTok Events API
|
|
95
|
+
|
|
96
|
+
### Setup Methods
|
|
97
|
+
|
|
98
|
+
**Option A: Via Server-Side GTM with TikTok template**
|
|
99
|
+
- Use community TikTok Events API GTM server-side template
|
|
100
|
+
- Route events through server GTM
|
|
101
|
+
|
|
102
|
+
**Option B: Direct API Integration**
|
|
103
|
+
- Endpoint: https://business-api.tiktok.com/open_api/v1.3/event/track/
|
|
104
|
+
- Authentication: Access Token from TikTok Events Manager
|
|
105
|
+
|
|
106
|
+
### Required Fields for Every Events API Event
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
{
|
|
110
|
+
"pixel_code": "CXXXXXXXXXX",
|
|
111
|
+
"event": "CompletePayment", // TikTok standard event name
|
|
112
|
+
"event_id": "uuid-generated-at-conversion", // For dedup with pixel
|
|
113
|
+
"timestamp": "2024-01-15T10:30:00+07:00",
|
|
114
|
+
"context": {
|
|
115
|
+
"page": {
|
|
116
|
+
"url": "https://yoursite.com/thank-you",
|
|
117
|
+
"referrer": "https://yoursite.com/checkout"
|
|
118
|
+
},
|
|
119
|
+
"user": {
|
|
120
|
+
"email": "sha256_of_lowercase_email",
|
|
121
|
+
"phone_number": "sha256_of_digits_only_phone"
|
|
122
|
+
},
|
|
123
|
+
"ip": "123.456.789.0",
|
|
124
|
+
"user_agent": "Mozilla/5.0..."
|
|
125
|
+
},
|
|
126
|
+
"properties": {
|
|
127
|
+
"value": 500000,
|
|
128
|
+
"currency": "VND",
|
|
129
|
+
"content_ids": ["PROD-123"],
|
|
130
|
+
"content_type": "product",
|
|
131
|
+
"contents": [
|
|
132
|
+
{
|
|
133
|
+
"content_id": "PROD-123",
|
|
134
|
+
"content_name": "Product Name",
|
|
135
|
+
"content_type": "product",
|
|
136
|
+
"quantity": 1,
|
|
137
|
+
"price": 500000
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Authentication header: "Access-Token: [your access token]"
|
|
145
|
+
Content-Type: application/json
|
|
146
|
+
|
|
147
|
+
### Getting TikTok Events API Access Token
|
|
148
|
+
|
|
149
|
+
1. TikTok Ads Manager → Assets → Events
|
|
150
|
+
2. Select your Pixel → Set Up Web Events → Events API
|
|
151
|
+
3. Generate Access Token
|
|
152
|
+
4. Store securely server-side
|
|
153
|
+
|
|
154
|
+
### TikTok Deduplication
|
|
155
|
+
|
|
156
|
+
Works identically to Meta: same event_id sent from both pixel and Events API.
|
|
157
|
+
TikTok matches within 48-hour window.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 3. Google Enhanced Conversions
|
|
162
|
+
|
|
163
|
+
### How It Works
|
|
164
|
+
|
|
165
|
+
Unlike Meta CAPI and TikTok Events API (which are standalone APIs), Google Enhanced Conversions supplements your existing Google Ads conversion tag with hashed user data.
|
|
166
|
+
|
|
167
|
+
The existing GTM Google Ads tag is enhanced with a user_data object containing:
|
|
168
|
+
- email_address (raw — Google hashes it)
|
|
169
|
+
- phone_number (raw — with country code prefix e.g. "+84912345678")
|
|
170
|
+
- address.first_name, address.last_name, address.country, address.postal_code
|
|
171
|
+
|
|
172
|
+
IMPORTANT: Google hashes the data itself (unlike Meta/TikTok where you pre-hash).
|
|
173
|
+
Do NOT SHA256 hash for Enhanced Conversions — pass raw data.
|
|
174
|
+
|
|
175
|
+
### Setup in GTM
|
|
176
|
+
|
|
177
|
+
In your existing Google Ads Conversion Tracking tag:
|
|
178
|
+
1. Scroll to "Enhanced conversions"
|
|
179
|
+
2. Enable "Include user-provided data from your website"
|
|
180
|
+
3. Under "User-provided data variable", create a new variable:
|
|
181
|
+
- Type: User-Provided Data
|
|
182
|
+
- Enter email variable: [DataLayer variable for email]
|
|
183
|
+
- Enter phone variable: [DataLayer variable for phone]
|
|
184
|
+
|
|
185
|
+
The DataLayer push should include raw (unhashed) email and phone:
|
|
186
|
+
email: "customer@email.com"
|
|
187
|
+
phone: "+84912345678"
|
|
188
|
+
|
|
189
|
+
Or if privacy is a concern: pre-hash with SHA256 and mark as "sha256_email_address" in the enhanced conversions config.
|
|
190
|
+
|
|
191
|
+
### Google Tag API (Server-Side Enhanced Conversions)
|
|
192
|
+
|
|
193
|
+
For server-side Enhanced Conversions via the Google Ads API:
|
|
194
|
+
- Use the Google Ads API ConversionUploadService
|
|
195
|
+
- Send click conversion with hashed user identifiers
|
|
196
|
+
- Match window: same as your conversion window setting
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## 4. Attribution Accuracy Benchmark
|
|
201
|
+
|
|
202
|
+
After implementing pixel + server-side API for all platforms, expect:
|
|
203
|
+
|
|
204
|
+
| Scenario | Pixel Only | Pixel + CAPI/Events API |
|
|
205
|
+
|---|---|---|
|
|
206
|
+
| iOS 14+ users | 30-50% signal loss | Full signal recovery |
|
|
207
|
+
| Ad blocker users | 0% tracking | 80-90% recovery |
|
|
208
|
+
| Overall conversion match rate | 60-70% | 85-95% |
|
|
209
|
+
| ROAS accuracy | Understated by 20-40% | Near-accurate |
|
|
210
|
+
|
|
211
|
+
### Validating Server-Side Setup
|
|
212
|
+
|
|
213
|
+
**Meta:** Events Manager → Pixel → Overview → Check "Event match quality" score
|
|
214
|
+
- Score 6-7: Good
|
|
215
|
+
- Score 8+: Excellent
|
|
216
|
+
- Below 5: Missing user_data fields (em, ph, fbp, fbc)
|
|
217
|
+
|
|
218
|
+
**TikTok:** Ads Manager → Assets → Events → Pixel → Data Details
|
|
219
|
+
- Check "Match rate" percentage
|
|
220
|
+
- Target: 60%+ match rate
|
|
221
|
+
|
|
222
|
+
**Google:** Google Ads → Conversions → View column "Enhanced conv." count
|
|
223
|
+
- Compare with standard conversion count
|
|
224
|
+
- Uplift of 15-25% is typical and expected
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## 5. Priority Implementation Order
|
|
229
|
+
|
|
230
|
+
If budget/time is limited, implement in this order:
|
|
231
|
+
|
|
232
|
+
1. Browser pixels via GTM (Phase B) — covers 60-70% of users
|
|
233
|
+
2. First-touch cookie + UTM tracking — attribution clarity
|
|
234
|
+
3. Meta CAPI — highest ROI platform, biggest uplift from server-side
|
|
235
|
+
4. Google Enhanced Conversions — easy to add, 15-25% uplift
|
|
236
|
+
5. TikTok Events API — add once other platforms are stable
|
|
237
|
+
|
|
238
|
+
Never implement CAPI without also keeping the browser pixel — you need both for deduplication to work. If you only have CAPI, you lose browser-generated signals like fbp cookie.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Facebook/Meta CAPI Server-Side Template
|
|
2
|
+
|
|
3
|
+
## Required Payload Fields
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"data": [{
|
|
8
|
+
"event_name": "Purchase",
|
|
9
|
+
"event_time": 1700000000,
|
|
10
|
+
"event_id": "uuid-same-as-pixel-event-id",
|
|
11
|
+
"action_source": "website",
|
|
12
|
+
"event_source_url": "https://example.com/thank-you",
|
|
13
|
+
"user_data": {
|
|
14
|
+
"em": ["sha256_hashed_email"],
|
|
15
|
+
"ph": ["sha256_hashed_phone_digits_only"],
|
|
16
|
+
"client_ip_address": "1.2.3.4",
|
|
17
|
+
"client_user_agent": "Mozilla/5.0...",
|
|
18
|
+
"fbp": "_fbp cookie value",
|
|
19
|
+
"fbc": "fb.1.timestamp.fbclid_value"
|
|
20
|
+
},
|
|
21
|
+
"custom_data": {
|
|
22
|
+
"value": 299000,
|
|
23
|
+
"currency": "VND",
|
|
24
|
+
"order_id": "ORD-12345",
|
|
25
|
+
"content_ids": ["prod_001", "prod_002"],
|
|
26
|
+
"content_type": "product",
|
|
27
|
+
"num_items": 2
|
|
28
|
+
}
|
|
29
|
+
}]
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## API Endpoint
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
POST https://graph.facebook.com/v21.0/{PIXEL_ID}/events?access_token={CAPI_ACCESS_TOKEN}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Deduplication
|
|
40
|
+
|
|
41
|
+
Both browser Pixel and CAPI send the SAME `event_id`. Meta matches within 48h and counts once.
|
|
42
|
+
|
|
43
|
+
## Enhanced Matching Priority (hash with SHA256)
|
|
44
|
+
|
|
45
|
+
1. `em` — email (lowercase, trim whitespace)
|
|
46
|
+
2. `ph` — phone (digits only, include country code)
|
|
47
|
+
3. `fn` — first name (lowercase)
|
|
48
|
+
4. `ln` — last name (lowercase)
|
|
49
|
+
5. `fbp` — Facebook browser cookie
|
|
50
|
+
6. `fbc` — Facebook click ID cookie
|
|
51
|
+
|
|
52
|
+
## TikTok Events API Equivalent
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
POST https://business-api.tiktok.com/open_api/v1.3/event/track/
|
|
56
|
+
Headers: Access-Token: {TIKTOK_ACCESS_TOKEN}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"pixel_code": "TIKTOK_PIXEL_ID",
|
|
62
|
+
"event": "CompletePayment",
|
|
63
|
+
"event_id": "same-uuid-as-pixel",
|
|
64
|
+
"timestamp": "2025-01-15T10:30:00+07:00",
|
|
65
|
+
"context": {
|
|
66
|
+
"user_agent": "Mozilla/5.0...",
|
|
67
|
+
"ip": "1.2.3.4"
|
|
68
|
+
},
|
|
69
|
+
"properties": {
|
|
70
|
+
"value": 299000,
|
|
71
|
+
"currency": "VND",
|
|
72
|
+
"content_id": "prod_001",
|
|
73
|
+
"content_type": "product",
|
|
74
|
+
"contents": [
|
|
75
|
+
{"content_id": "prod_001", "content_name": "Product A", "quantity": 1, "price": 299000}
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// DataLayer Push Templates — CM Ads Tracker v2
|
|
2
|
+
// Copy and customize these for your project.
|
|
3
|
+
// Developer writes ONE push per event. GTM does the rest.
|
|
4
|
+
|
|
5
|
+
// ═══════════════════════════════════════════
|
|
6
|
+
// PURCHASE (E-commerce, Courses, SaaS)
|
|
7
|
+
// ═══════════════════════════════════════════
|
|
8
|
+
dataLayer.push({
|
|
9
|
+
event: 'cro_purchase',
|
|
10
|
+
event_id: '[UUID generated server-side — same value sent to CAPI]',
|
|
11
|
+
transaction_id: '[order_id]',
|
|
12
|
+
value: 0, // numeric order total — NOT string
|
|
13
|
+
currency: 'VND', // ISO 4217 code
|
|
14
|
+
content_type: 'product',
|
|
15
|
+
content_ids: ['product_id_1', 'product_id_2'],
|
|
16
|
+
contents: [
|
|
17
|
+
{ content_id: 'id', content_name: 'name', content_type: 'product', quantity: 1, price: 0 }
|
|
18
|
+
],
|
|
19
|
+
num_items: 1,
|
|
20
|
+
email_hashed: '[SHA256(lowercase(email))]',
|
|
21
|
+
phone_hashed: '[SHA256(digits-only phone)]'
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// ═══════════════════════════════════════════
|
|
25
|
+
// LEAD / FORM SUBMIT (Lead Gen, B2B, Education)
|
|
26
|
+
// ═══════════════════════════════════════════
|
|
27
|
+
dataLayer.push({
|
|
28
|
+
event: 'cro_lead',
|
|
29
|
+
event_id: '[UUID]',
|
|
30
|
+
lead_id: '[unique lead identifier]',
|
|
31
|
+
content_name: '[form_name or page_name]',
|
|
32
|
+
value: 0, // lead_value_if_known — optional
|
|
33
|
+
currency: 'VND',
|
|
34
|
+
email_hashed: '[SHA256(lowercase(email))]',
|
|
35
|
+
phone_hashed: '[SHA256(digits-only phone)]'
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// ═══════════════════════════════════════════
|
|
39
|
+
// VIEW CONTENT (Product/Service page)
|
|
40
|
+
// ═══════════════════════════════════════════
|
|
41
|
+
dataLayer.push({
|
|
42
|
+
event: 'cro_view_content',
|
|
43
|
+
event_id: '[UUID]',
|
|
44
|
+
content_ids: ['product_id'],
|
|
45
|
+
content_type: 'product',
|
|
46
|
+
content_name: '[Product Name]',
|
|
47
|
+
value: 0,
|
|
48
|
+
currency: 'VND'
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// ═══════════════════════════════════════════
|
|
52
|
+
// ADD TO CART
|
|
53
|
+
// ═══════════════════════════════════════════
|
|
54
|
+
dataLayer.push({
|
|
55
|
+
event: 'cro_add_to_cart',
|
|
56
|
+
event_id: '[UUID]',
|
|
57
|
+
content_ids: ['product_id'],
|
|
58
|
+
content_type: 'product',
|
|
59
|
+
content_name: '[Product Name]',
|
|
60
|
+
value: 0,
|
|
61
|
+
currency: 'VND',
|
|
62
|
+
quantity: 1
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// ═══════════════════════════════════════════
|
|
66
|
+
// INITIATE CHECKOUT
|
|
67
|
+
// ═══════════════════════════════════════════
|
|
68
|
+
dataLayer.push({
|
|
69
|
+
event: 'cro_initiate_checkout',
|
|
70
|
+
event_id: '[UUID]',
|
|
71
|
+
value: 0,
|
|
72
|
+
currency: 'VND',
|
|
73
|
+
num_items: 1,
|
|
74
|
+
content_ids: ['product_id_1']
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// ═══════════════════════════════════════════
|
|
78
|
+
// REGISTRATION / SIGNUP
|
|
79
|
+
// ═══════════════════════════════════════════
|
|
80
|
+
dataLayer.push({
|
|
81
|
+
event: 'cro_registration',
|
|
82
|
+
event_id: '[UUID]',
|
|
83
|
+
status: 'complete',
|
|
84
|
+
email_hashed: '[SHA256]',
|
|
85
|
+
phone_hashed: '[SHA256]'
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// ═══════════════════════════════════════════
|
|
89
|
+
// PHONE CALL CLICK
|
|
90
|
+
// ═══════════════════════════════════════════
|
|
91
|
+
dataLayer.push({
|
|
92
|
+
event: 'cro_phone_call',
|
|
93
|
+
event_id: '[UUID]',
|
|
94
|
+
phone_number: '[phone number clicked]'
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// ═══════════════════════════════════════════
|
|
98
|
+
// SEARCH
|
|
99
|
+
// ═══════════════════════════════════════════
|
|
100
|
+
dataLayer.push({
|
|
101
|
+
event: 'cro_search',
|
|
102
|
+
event_id: '[UUID]',
|
|
103
|
+
search_string: '[user search query]'
|
|
104
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// GTM Variables — Full Configuration Reference
|
|
2
|
+
// Create ALL of these in GTM > Variables > User-Defined Variables
|
|
3
|
+
|
|
4
|
+
// ═══════ DataLayer Variables ═══════
|
|
5
|
+
// Variable Name | Type | DataLayer Variable Name
|
|
6
|
+
// DL - event_id | Data Layer Variable | event_id
|
|
7
|
+
// DL - order_id | Data Layer Variable | transaction_id
|
|
8
|
+
// DL - order_value | Data Layer Variable | value
|
|
9
|
+
// DL - currency | Data Layer Variable | currency
|
|
10
|
+
// DL - content_ids | Data Layer Variable | content_ids
|
|
11
|
+
// DL - content_type | Data Layer Variable | content_type
|
|
12
|
+
// DL - content_name | Data Layer Variable | content_name
|
|
13
|
+
// DL - email_hashed | Data Layer Variable | email_hashed
|
|
14
|
+
// DL - phone_hashed | Data Layer Variable | phone_hashed
|
|
15
|
+
|
|
16
|
+
// ═══════ First-Touch Cookie Variables ═══════
|
|
17
|
+
// Variable Name | Type | Cookie / Key
|
|
18
|
+
// FTC - source | 1st-Party Cookie | Cookie: _ftc, key: src
|
|
19
|
+
// FTC - medium | 1st-Party Cookie | Cookie: _ftc, key: med
|
|
20
|
+
// FTC - campaign | 1st-Party Cookie | Cookie: _ftc, key: cmp
|
|
21
|
+
|
|
22
|
+
// ═══════ URL Parameters ═══════
|
|
23
|
+
// Variable Name | Type | Query Parameter
|
|
24
|
+
// URL - utm_source | URL | utm_source
|
|
25
|
+
// URL - utm_medium | URL | utm_medium
|
|
26
|
+
// URL - utm_campaign | URL | utm_campaign
|
|
27
|
+
// URL - fbclid | URL | fbclid
|
|
28
|
+
// URL - ttclid | URL | ttclid
|
|
29
|
+
// URL - gclid | URL | gclid
|
|
30
|
+
|
|
31
|
+
// ═══════ First-Touch Cookie Capture (Custom HTML Tag) ═══════
|
|
32
|
+
// Trigger: All Pages
|
|
33
|
+
// Fire once: Only if _ftc cookie does NOT exist
|
|
34
|
+
<script>
|
|
35
|
+
(function(){
|
|
36
|
+
if (document.cookie.indexOf('_ftc=') !== -1) return;
|
|
37
|
+
var params = new URLSearchParams(window.location.search);
|
|
38
|
+
var ftc = {
|
|
39
|
+
src: params.get('utm_source') || '',
|
|
40
|
+
med: params.get('utm_medium') || '',
|
|
41
|
+
cmp: params.get('utm_campaign') || '',
|
|
42
|
+
cnt: params.get('utm_content') || '',
|
|
43
|
+
trm: params.get('utm_term') || '',
|
|
44
|
+
fbclid: params.get('fbclid') || '',
|
|
45
|
+
ttclid: params.get('ttclid') || '',
|
|
46
|
+
gclid: params.get('gclid') || '',
|
|
47
|
+
ref: document.referrer ? new URL(document.referrer).hostname : '',
|
|
48
|
+
ts: new Date().toISOString()
|
|
49
|
+
};
|
|
50
|
+
var expiry = new Date();
|
|
51
|
+
expiry.setDate(expiry.getDate() + 90);
|
|
52
|
+
document.cookie = '_ftc=' + encodeURIComponent(JSON.stringify(ftc))
|
|
53
|
+
+ ';expires=' + expiry.toUTCString()
|
|
54
|
+
+ ';path=/;SameSite=Lax';
|
|
55
|
+
})();
|
|
56
|
+
</script>
|