@funnel10x/tracking 1.2.0 → 1.3.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/README.md +105 -34
- package/dist/gtm.html +3 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +7 -7
- package/dist/tag.js +7 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,8 +7,9 @@ no npm como pacote público, pela versão.
|
|
|
7
7
|
|
|
8
8
|
O que faz numa página:
|
|
9
9
|
|
|
10
|
-
- **o PostHog** (o posthog-js, embutido
|
|
11
|
-
|
|
10
|
+
- **o PostHog** (o posthog-js, embutido: o snippet **é** o PostHog, e numa
|
|
11
|
+
página que já tenha outro não arranca, ver o checklist), com os ids de
|
|
12
|
+
anúncio como parâmetros de campanha, e **cada evento limpo antes de sair**: o URL fica com o host, o
|
|
12
13
|
caminho e só os parâmetros de campanha da allow-list (`src/clean.js`), no
|
|
13
14
|
evento, no perfil (`$set`, `$set_once`), no cookie do PostHog, nos heatmaps
|
|
14
15
|
e na gravação de sessão (onde os pedidos de rede se gravam sem o corpo). O
|
|
@@ -108,22 +109,44 @@ Num funil do GHL ou num site em Webflow, onde não há build, o mesmo pacote
|
|
|
108
109
|
carrega-se por uma tag Custom HTML do GTM (em All Pages), **pela versão fixa**
|
|
109
110
|
no URL do jsDelivr e com o hash do ficheiro no `integrity`. A tag de cada versão
|
|
110
111
|
publicada está no próprio pacote, em `dist/gtm.html`, e cola-se tal como está:
|
|
111
|
-
só se trocam a chave
|
|
112
|
+
só se trocam a chave, o `apiHost` (se a account tiver o proxy gerido, abaixo) e
|
|
113
|
+
os hosts do checkout.
|
|
112
114
|
|
|
113
115
|
```html
|
|
114
116
|
<script>
|
|
115
117
|
window.f10xTracking = {
|
|
116
118
|
key: '{{PostHog project key}}',
|
|
119
|
+
apiHost: '',
|
|
117
120
|
checkoutHosts: []
|
|
118
121
|
}
|
|
119
122
|
</script>
|
|
120
|
-
<script src="https://cdn.jsdelivr.net/npm/@funnel10x/tracking@1.
|
|
123
|
+
<script src="https://cdn.jsdelivr.net/npm/@funnel10x/tracking@1.3.0/dist/tag.js" integrity="sha384-…" crossorigin="anonymous"></script>
|
|
121
124
|
```
|
|
122
125
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
126
|
+
Uma versão nova é uma tag nova, nunca `@1` nem `@latest`: o GTM de cada site
|
|
127
|
+
diz que versão corre, e o `tracking_version` de cada evento confirma-o.
|
|
128
|
+
|
|
129
|
+
**O proxy gerido do PostHog.** Sem build não há o `/_t`, e com o `apiHost`
|
|
130
|
+
vazio os envios vão para o `us.i.posthog.com`, que a EasyPrivacy bloqueia: a
|
|
131
|
+
visita de quem tem um bloqueador não chega ao PostHog. O PostHog tem um proxy
|
|
132
|
+
gerido, um subdomínio da account (um CNAME para o PostHog, nas definições da
|
|
133
|
+
organização, *Managed reverse proxy*) que recebe os envios e os passa ao
|
|
134
|
+
PostHog. Com ele, o `apiHost` da tag é esse subdomínio: na IR,
|
|
135
|
+
`https://p.infinityresponse.com`, e na IMO Circle, `https://p.imocircle.com`
|
|
136
|
+
(os dois válidos, lidos no PostHog a 2026-10-08; o Piko ainda não tem). As listas que bloqueiam pelo nome do domínio deixam de o apanhar;
|
|
137
|
+
o uBlock Origin no Firefox, que lê o CNAME, apanha na mesma, e quanto se
|
|
138
|
+
recupera não se mede, porque o que é bloqueado não chega para se contar. O
|
|
139
|
+
subdomínio é de outra origem que a página, e por isso o browser só lhe manda a
|
|
140
|
+
origem no `Referer`, e não o URL com a query string.
|
|
141
|
+
|
|
142
|
+
**O consentimento.** Sem `site.json` o snippet não tem interruptor, e quem
|
|
143
|
+
decide se ele corre é o sítio onde a tag está. No GTM, corre como as condições
|
|
144
|
+
de consentimento da tag deixarem (o banner ligado ao GTM); no *Head tracking
|
|
145
|
+
code* do GHL, ou no campo de código de outra plataforma, corre sempre, também
|
|
146
|
+
para quem recusou. Por isso, **num site com banner, a tag fica no GTM, com a
|
|
147
|
+
condição do consentimento de analytics; num site sem banner, pode ir para o
|
|
148
|
+
head**, o que a livra de um GTM bloqueado (a EasyPrivacy bloqueia o
|
|
149
|
+
`googletagmanager.com`). É uma regra de onde se põe a tag, e não código.
|
|
127
150
|
|
|
128
151
|
**Numa página de um funil do GHL, o form é nativo** (sem `<form>`, cada campo
|
|
129
152
|
com o query key em `data-q`), e **um campo escondido só se enche pelo URL com
|
|
@@ -145,24 +168,28 @@ ao form o que veio no URL dele.
|
|
|
145
168
|
|
|
146
169
|
O que os forms, o iframe e os links do checkout levam:
|
|
147
170
|
|
|
148
|
-
| campo | o que é | sem consentimento |
|
|
149
|
-
| --- | --- | --- |
|
|
150
|
-
| `ph_anon_id` | o id do dispositivo no PostHog (o anónimo de origem) | não |
|
|
151
|
-
| `ph_distinct_id` | o distinct id agora (o id do contacto, depois do identify) | não |
|
|
152
|
-
| `ph_session_id` | a sessão do PostHog | não |
|
|
153
|
-
| `contact_id` | o id do contacto que veio num link desta sessão | não |
|
|
154
|
-
| as UTMs | `utm_source`, `utm_medium`, `utm_campaign`, `utm_content`, `utm_term`, `utm_id`, `utm_placement` | sim, do URL |
|
|
155
|
-
| os click ids | `fbclid`, `gclid`, `gbraid`, `wbraid`, `gad_source`, `gad_campaignid`, `msclkid`, `ctwa_clid` | sim, do URL |
|
|
156
|
-
| os ids de anúncio | `
|
|
157
|
-
| `lp` | a página de entrada que o URL declara | sim, do URL |
|
|
171
|
+
| campo | o que é | sem consentimento | campo custom no GHL |
|
|
172
|
+
| --- | --- | --- | --- |
|
|
173
|
+
| `ph_anon_id` | o id do dispositivo no PostHog (o anónimo de origem) | não | opcional: só se enche quando o id chega no URL |
|
|
174
|
+
| `ph_distinct_id` | o distinct id agora (o id do contacto, depois do identify) | não | não |
|
|
175
|
+
| `ph_session_id` | a sessão do PostHog | não | não |
|
|
176
|
+
| `contact_id` | o id do contacto que veio num link desta sessão | não | não |
|
|
177
|
+
| as UTMs | `utm_source`, `utm_medium`, `utm_campaign`, `utm_content`, `utm_term`, `utm_id`, `utm_placement` | sim, do URL | só `utm_source`, `utm_medium` e `utm_campaign`, nas locations de um site `direct` com consentimento |
|
|
178
|
+
| os click ids | `fbclid`, `gclid`, `gbraid`, `wbraid`, `gad_source`, `gad_campaignid`, `msclkid`, `ctwa_clid` | sim, do URL | não |
|
|
179
|
+
| os ids de anúncio | `a_campaign_id`, `a_adset_id`, `a_ad_id` (a convenção, abaixo), e os da HYROS `h_ad_id`, `fbc_id` | sim, do URL | só `a_ad_id`, como as UTMs |
|
|
180
|
+
| `lp` | a página de entrada que o URL declara | sim, do URL | não |
|
|
158
181
|
|
|
159
182
|
- **Num form da página**, um campo que já existe com o nome recebe o valor se
|
|
160
183
|
for escondido ou estiver vazio; os que faltam acrescentam-se escondidos, só
|
|
161
184
|
num form de lead (com um campo de email ou de telefone) e nunca num com
|
|
162
185
|
`data-f10x-skip`. Voltam a preencher-se no envio, com os valores desse
|
|
163
186
|
momento.
|
|
164
|
-
- **Num form do GHL
|
|
165
|
-
|
|
187
|
+
- **Num form do GHL** não há campos a pôr: a ponte para o contacto é o email
|
|
188
|
+
que a pessoa envia (o `contact_captured`), e o click id do contacto é a
|
|
189
|
+
atribuição nativa do GHL, que a A5 lê. Os quatro campos de atribuição da
|
|
190
|
+
tabela só existem nas locations que recebam leads de um site `direct` com
|
|
191
|
+
`consent: true`: quem recusa não tem PostHog, e um contacto criado pelo
|
|
192
|
+
webhook não tem atribuição nativa (plano, A2 revista a 2026-10-07).
|
|
166
193
|
- **Nos links do checkout** (os do Stripe e os hosts em `checkoutHosts`), os ids
|
|
167
194
|
sobrepõem-se ao que o link traga, e os parâmetros do anúncio só entram se o
|
|
168
195
|
link não tiver os seus. Num Payment Link do Stripe vai também o
|
|
@@ -175,6 +202,8 @@ O que os forms, o iframe e os links do checkout levam:
|
|
|
175
202
|
|
|
176
203
|
`init(options)` (ou a tag) devolve, e põe em `window.f10xTracking`:
|
|
177
204
|
|
|
205
|
+
- `mode`: `tag` ou `direct`; `frame` num iframe, `preview` numa
|
|
206
|
+
pré-visualização, e `conflict` quando a página já tem outro PostHog;
|
|
178
207
|
- `fields()`: os valores de cima, agora;
|
|
179
208
|
- `grant()`, `deny()`, `consent()`: o interruptor de um site `direct`;
|
|
180
209
|
- `onReady(fn)`: quando o PostHog estiver a medir;
|
|
@@ -184,14 +213,37 @@ O que os forms, o iframe e os links do checkout levam:
|
|
|
184
213
|
|
|
185
214
|
## Os modelos de parâmetros de URL
|
|
186
215
|
|
|
216
|
+
**Os nomes vão nas UTMs, os ids em três parâmetros nossos**, com o prefixo
|
|
217
|
+
`a_` (de *attribution*), como a HYROS tem o `h_`, e desde a 1.3.0. Um nome é
|
|
218
|
+
editável no gestor de anúncios e um rename não dá erro nenhum; o id nasce com
|
|
219
|
+
o anúncio. Os três querem dizer o mesmo em todas as plataformas, e a plataforma
|
|
220
|
+
diz-se no `utm_source`:
|
|
221
|
+
|
|
222
|
+
| nível | parâmetro | Meta | Google |
|
|
223
|
+
| --- | --- | --- | --- |
|
|
224
|
+
| a campanha | `a_campaign_id` | `{{campaign.id}}` | `{campaignid}` |
|
|
225
|
+
| o conjunto (o ad set da Meta, o ad group da Google) | `a_adset_id` | `{{adset.id}}` | `{adgroupid}` |
|
|
226
|
+
| o anúncio | `a_ad_id` | `{{ad.id}}` | `{creative}` |
|
|
227
|
+
|
|
228
|
+
Na HYROS, o `h_ad_id` é o anúncio em todas, mas o nível de cima muda de nome e
|
|
229
|
+
de nível com a plataforma: o `fbc_id` é o ad set na Meta, o `gc_id` é a
|
|
230
|
+
campanha na Google; na Meta a campanha não vai, e na Google o ad group também
|
|
231
|
+
não. O `h_ad_id` e o `fbc_id` continuam aceites, pelos anúncios da IMO Circle
|
|
232
|
+
que ainda os trazem (4.324 pageviews desde abril, medidos a 2026-10-08). Os
|
|
233
|
+
nomes sem prefixo da 1.0.0 à 1.2.0 (`ad_id`, `adset_id`, `campaign_id`,
|
|
234
|
+
`adgroup_id`) saíram: nenhum anúncio os usou. Nenhum URL das três accounts
|
|
235
|
+
trazia já um parâmetro `a_` (medido no mesmo dia).
|
|
236
|
+
|
|
187
237
|
**Meta**, nos *URL parameters* de cada anúncio:
|
|
188
238
|
|
|
189
239
|
```
|
|
190
|
-
utm_source=
|
|
240
|
+
utm_source=meta&utm_medium=paid_social&utm_campaign={{campaign.name}}&utm_term={{adset.name}}&utm_content={{ad.name}}&utm_id={{campaign.id}}&utm_placement={{placement}}&a_campaign_id={{campaign.id}}&a_adset_id={{adset.id}}&a_ad_id={{ad.id}}
|
|
191
241
|
```
|
|
192
242
|
|
|
193
243
|
O nome do anúncio acaba no código do asset (decisão 10 do plano), e é por isso
|
|
194
|
-
que vai no `utm_content`.
|
|
244
|
+
que vai no `utm_content`. O `utm_source` é `meta`, como na Traffic Sources e nos
|
|
245
|
+
anúncios das três accounts (45.819 pageviews com `fbclid` em 90 dias, medidos a
|
|
246
|
+
2026-10-08); até à 1.2.0 este modelo dizia `facebook`, que nenhum usava.
|
|
195
247
|
|
|
196
248
|
**Google**, no *Final URL suffix* da conta, com o auto-tagging ligado (o
|
|
197
249
|
`gclid`) e dois parâmetros personalizados: `campaign` em cada campanha (o nome
|
|
@@ -199,9 +251,19 @@ dela) e `asset` em cada anúncio (o código do asset, que num anúncio de pesqui
|
|
|
199
251
|
num responsive display ou na Performance Max não chega pelo nome):
|
|
200
252
|
|
|
201
253
|
```
|
|
202
|
-
utm_source=google&utm_medium=cpc&utm_campaign={_campaign}&utm_term={keyword}&utm_content={_asset}&
|
|
254
|
+
utm_source=google&utm_medium=cpc&utm_campaign={_campaign}&utm_term={keyword}&utm_content={_asset}&a_campaign_id={campaignid}&a_adset_id={adgroupid}&a_ad_id={creative}
|
|
203
255
|
```
|
|
204
256
|
|
|
257
|
+
## Os links orgânicos
|
|
258
|
+
|
|
259
|
+
Um link que não é anúncio (a bio do Instagram, a descrição de um vídeo, um
|
|
260
|
+
email, o WhatsApp, um parceiro) leva as UTMs da fonte dele, pelas regras da
|
|
261
|
+
tabela **Traffic Sources** do admin, que é nomenclatura partilhada por todas as
|
|
262
|
+
accounts. Sem elas a visita chega sem origem, e o referrer de um browser in-app
|
|
263
|
+
ou de um cliente de email vem quase sempre vazio, o que a conta como *direct*.
|
|
264
|
+
Este README não copia a tabela, que é a fonte; o gerador de links da Marketing
|
|
265
|
+
Ops, que os monta a partir dela, está no plano da Marketing (Fase M48).
|
|
266
|
+
|
|
205
267
|
## O checklist de um funil
|
|
206
268
|
|
|
207
269
|
Antes de ligar o tráfego:
|
|
@@ -209,18 +271,27 @@ Antes de ligar o tráfego:
|
|
|
209
271
|
1. **O snippet carrega pela versão**: num repo `direct`, a versão exacta no
|
|
210
272
|
`package.json`, a chave na variável de ambiente e os rewrites do `/_t` no
|
|
211
273
|
`vercel.json`; num site de fora, a tag do `dist/gtm.html` da versão, com a
|
|
212
|
-
chave da account,
|
|
213
|
-
2. **
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
274
|
+
chave da account e, se ela tiver o proxy gerido, o `apiHost`.
|
|
275
|
+
2. **Nenhum outro PostHog na página**: a tag ou o snippet do PostHog que o site
|
|
276
|
+
já tenha (no GTM, no head, no código do site) sai quando este entra. Este
|
|
277
|
+
snippet já é o PostHog, e com outro na página não arranca (avisa na
|
|
278
|
+
consola, e o `window.f10xTracking.mode` fica `conflict`). Com a mesma chave
|
|
279
|
+
não se perde nada: quem volta mantém o id anónimo, e o URL inicial que o
|
|
280
|
+
outro deixou no cookie reescreve-se limpo.
|
|
281
|
+
3. **O consentimento**: o `consent` do `site.json` escrito, e o banner a chamar
|
|
282
|
+
`grant()` e `deny()`; num site de fora, a tag no GTM com a condição do
|
|
283
|
+
consentimento se o site tiver banner, e no head só se não tiver.
|
|
284
|
+
4. **Os forms**: um envio de teste, escrito à mão numa página aberta com
|
|
285
|
+
`?utm_source=teste`, deixa no PostHog um `contact_captured` com o email,
|
|
286
|
+
no momento do envio, e o contacto no GHL; um email escrito e não enviado não
|
|
287
|
+
deixa nada. Num site `direct` com consentimento, a location tem os quatro
|
|
288
|
+
campos de atribuição da tabela, com o *query key* igual ao nome.
|
|
289
|
+
5. **Os links de email e de SMS** levam `contact_id={{contact.id}}`.
|
|
290
|
+
6. **O checkout**: o host em `checkoutHosts` (o Stripe já lá está), e num
|
|
221
291
|
checkout em código os `fields()` na metadata.
|
|
222
|
-
|
|
223
|
-
|
|
292
|
+
7. **Os anúncios**: os parâmetros de cima na Meta e na Google, e os links
|
|
293
|
+
orgânicos com as UTMs da Traffic Sources.
|
|
294
|
+
8. **A prova**: um pageview aberto com `?email=teste@example.com&utm_source=teste`
|
|
224
295
|
chega ao PostHog (Activity, no projeto da account) com a `utm_source` e sem
|
|
225
296
|
o `email`, no evento e no perfil, e com o `tracking_version` da versão.
|
|
226
297
|
|
package/dist/gtm.html
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
<!-- @funnel10x/tracking@1.
|
|
1
|
+
<!-- @funnel10x/tracking@1.3.0: a tag do GTM (Custom HTML, em All Pages). Só se mudam a chave e, se a account tiver o proxy gerido do PostHog, o apiHost; uma versão nova é um ficheiro novo. -->
|
|
2
2
|
<script>
|
|
3
3
|
window.f10xTracking = {
|
|
4
4
|
key: '{{PostHog project key}}',
|
|
5
|
+
apiHost: '',
|
|
5
6
|
checkoutHosts: []
|
|
6
7
|
}
|
|
7
8
|
</script>
|
|
8
|
-
<script src="https://cdn.jsdelivr.net/npm/@funnel10x/tracking@1.
|
|
9
|
+
<script src="https://cdn.jsdelivr.net/npm/@funnel10x/tracking@1.3.0/dist/tag.js" integrity="sha384-BFUxhoktzA6AWF2yGaTdVq+krqyK0WqpmJfPAP3ga7hqHXxJu+WXr2lLbx6CH6G0" crossorigin="anonymous"></script>
|
package/dist/index.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export interface TrackingOptions {
|
|
|
21
21
|
|
|
22
22
|
export interface Tracking {
|
|
23
23
|
version: string
|
|
24
|
-
mode: 'direct' | 'tag' | 'preview' | 'frame'
|
|
24
|
+
mode: 'direct' | 'tag' | 'preview' | 'frame' | 'conflict'
|
|
25
25
|
consent(): 'granted' | 'denied' | null
|
|
26
26
|
grant(): void
|
|
27
27
|
deny(): void
|