@funnel10x/tracking 1.3.0 → 1.4.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 CHANGED
@@ -40,6 +40,15 @@ O que faz numa página:
40
40
  **interruptor de consentimento** do `site.json`, e a guarda das
41
41
  pré-visualizações.
42
42
 
43
+ **Quem lê isto do lado do admin** (Fase A3 do plano da atribuição): a fonte
44
+ PostHog da ingestão guarda o `tracking_version`, a `page_version`, o `ab_test`
45
+ e o `fingerprint` de cada evento, e o email e o telefone do `contact_captured`
46
+ só em hash. O histórico de um funil, que chegou ao PostHog antes deste snippet
47
+ com o URL inteiro, é aparado lá pela mesma allow-list do `src/clean.js`: um
48
+ parâmetro que entre na `ALLOWED_PARAMS` entra também na entrada `posthog` da
49
+ `ingest/pii.json` e na `supabase/verify/atr3.sql` do admin, no mesmo PR (um
50
+ teste do admin prova que as três listas são a mesma).
51
+
43
52
  O posthog-js e o FingerprintJS vão dentro do ficheiro, pela versão que este
44
53
  pacote fixa, e não se resolvem no site. O que fica de fora são as extensões que
45
54
  o posthog-js carrega quando o projeto as liga (o gravador de sessão, os dead
@@ -63,7 +72,7 @@ init({
63
72
  apiHost: '/_t',
64
73
  consent: site.consent,
65
74
  pageVersion: 3,
66
- test: '/pt/f1/lp#2',
75
+ test: '/pt/acq_f1/webinar/lp#2',
67
76
  })
68
77
  ```
69
78
 
@@ -120,15 +129,16 @@ os hosts do checkout.
120
129
  checkoutHosts: []
121
130
  }
122
131
  </script>
123
- <script src="https://cdn.jsdelivr.net/npm/@funnel10x/tracking@1.3.0/dist/tag.js" integrity="sha384-…" crossorigin="anonymous"></script>
132
+ <script src="https://cdn.jsdelivr.net/npm/@funnel10x/tracking@1.4.0/dist/tag.js" integrity="sha384-…" crossorigin="anonymous"></script>
124
133
  ```
125
134
 
126
135
  Uma versão nova é uma tag nova, nunca `@1` nem `@latest`: o GTM de cada site
127
136
  diz que versão corre, e o `tracking_version` de cada evento confirma-o.
128
137
 
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
138
+ **O proxy gerido do PostHog, opcional.** Sem build não há o `/_t`, e com o
139
+ `apiHost` vazio os envios vão para o `us.i.posthog.com`: funciona, mas a
140
+ EasyPrivacy bloqueia-o, e a visita de quem tem um bloqueador não chega ao
141
+ PostHog. O PostHog tem um proxy
132
142
  gerido, um subdomínio da account (um CNAME para o PostHog, nas definições da
133
143
  organização, *Managed reverse proxy*) que recebe os envios e os passa ao
134
144
  PostHog. Com ele, o `apiHost` da tag é esse subdomínio: na IR,
@@ -178,6 +188,7 @@ O que os forms, o iframe e os links do checkout levam:
178
188
  | os click ids | `fbclid`, `gclid`, `gbraid`, `wbraid`, `gad_source`, `gad_campaignid`, `msclkid`, `ctwa_clid` | sim, do URL | não |
179
189
  | 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
190
  | `lp` | a página de entrada que o URL declara | sim, do URL | não |
191
+ | `narrative` | o slug da narrativa declarado pela página (desde a 1.4.0) | sim, do URL | `narrative`, com o query key igual ao nome, se a location o tiver |
181
192
 
182
193
  - **Num form da página**, um campo que já existe com o nome recebe o valor se
183
194
  for escondido ou estiver vazio; os que faltam acrescentam-se escondidos, só
@@ -234,10 +245,18 @@ nomes sem prefixo da 1.0.0 à 1.2.0 (`ad_id`, `adset_id`, `campaign_id`,
234
245
  `adgroup_id`) saíram: nenhum anúncio os usou. Nenhum URL das três accounts
235
246
  trazia já um parâmetro `a_` (medido no mesmo dia).
236
247
 
248
+ **O texto de cada anúncio sai do gerador de links** da Marketing Ops (o módulo
249
+ URL Parameters, Fase M48 do plano da Marketing), que o compõe a partir da regra
250
+ da fonte na Traffic Sources, do funil e do stage: é aí que se gera, e os dois
251
+ modelos de baixo são a forma do que ele dá. O `utm_campaign` deixou de ser o nome
252
+ da campanha (que chega pelo `a_campaign_id`) e é o funil e o stage,
253
+ `<funil>_<stage>[_<temperatura>]`; o nome do ad set e o `utm_id` saíram, porque
254
+ os ids `a_` já os dizem.
255
+
237
256
  **Meta**, nos *URL parameters* de cada anúncio:
238
257
 
239
258
  ```
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}}
259
+ utm_source=meta&utm_medium=paid_social&utm_campaign=acq_f1_webinar_cold&utm_content={{ad.name}}&utm_placement={{placement}}&a_campaign_id={{campaign.id}}&a_adset_id={{adset.id}}&a_ad_id={{ad.id}}
241
260
  ```
242
261
 
243
262
  O nome do anúncio acaba no código do asset (decisão 10 do plano), e é por isso
@@ -245,13 +264,14 @@ que vai no `utm_content`. O `utm_source` é `meta`, como na Traffic Sources e no
245
264
  anúncios das três accounts (45.819 pageviews com `fbclid` em 90 dias, medidos a
246
265
  2026-10-08); até à 1.2.0 este modelo dizia `facebook`, que nenhum usava.
247
266
 
248
- **Google**, no *Final URL suffix* da conta, com o auto-tagging ligado (o
249
- `gclid`) e dois parâmetros personalizados: `campaign` em cada campanha (o nome
250
- dela) e `asset` em cada anúncio (o código do asset, que num anúncio de pesquisa,
251
- num responsive display ou na Performance Max não chega pelo nome):
267
+ **Google**, no *Final URL suffix* da campanha (ou do ad group, ou do anúncio:
268
+ o `utm_campaign` é o do funil e do stage, e por isso não vai ao nível da conta),
269
+ com o auto-tagging ligado (o `gclid`) e um parâmetro personalizado, `asset`, em
270
+ cada anúncio (o código do asset, que num anúncio de pesquisa, num responsive
271
+ display ou na Performance Max não chega pelo nome):
252
272
 
253
273
  ```
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}
274
+ utm_source=google&utm_medium=cpc&utm_campaign=acq_f1_webinar&utm_term={keyword}&utm_content={_asset}&a_campaign_id={campaignid}&a_adset_id={adgroupid}&a_ad_id={creative}
255
275
  ```
256
276
 
257
277
  ## Os links orgânicos
@@ -262,7 +282,9 @@ tabela **Traffic Sources** do admin, que é nomenclatura partilhada por todas as
262
282
  accounts. Sem elas a visita chega sem origem, e o referrer de um browser in-app
263
283
  ou de um cliente de email vem quase sempre vazio, o que a conta como *direct*.
264
284
  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).
285
+ Ops (o módulo URL Parameters, Fase M48 do plano da Marketing) monta-os a partir
286
+ dela, junta-os a um URL que já tenha parâmetros sem duplicar nenhum, e guarda
287
+ cada link com o sítio onde foi posto.
266
288
 
267
289
  ## O checklist de um funil
268
290
 
@@ -277,7 +299,9 @@ Antes de ligar o tráfego:
277
299
  snippet já é o PostHog, e com outro na página não arranca (avisa na
278
300
  consola, e o `window.f10xTracking.mode` fica `conflict`). Com a mesma chave
279
301
  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.
302
+ outro deixou no cookie reescreve-se limpo. **O `apiHost` da tag nova é o
303
+ `api_host` que a antiga tinha** (o proxy, se ela o usava): vazio, perdia
304
+ quem hoje chega por ele.
281
305
  3. **O consentimento**: o `consent` do `site.json` escrito, e o banner a chamar
282
306
  `grant()` e `deny()`; num site de fora, a tag no GTM com a condição do
283
307
  consentimento se o site tiver banner, e no head só se não tiver.
@@ -289,8 +313,8 @@ Antes de ligar o tráfego:
289
313
  5. **Os links de email e de SMS** levam `contact_id={{contact.id}}`.
290
314
  6. **O checkout**: o host em `checkoutHosts` (o Stripe já lá está), e num
291
315
  checkout em código os `fields()` na metadata.
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.
316
+ 7. **Os anúncios**: o texto do gerador de links nos anúncios da Meta e da
317
+ Google, e os links orgânicos gerados por ele, com as UTMs da Traffic Sources.
294
318
  8. **A prova**: um pageview aberto com `?email=teste@example.com&utm_source=teste`
295
319
  chega ao PostHog (Activity, no projeto da account) com a `utm_source` e sem
296
320
  o `email`, no evento e no perfil, e com o `tracking_version` da versão.
@@ -309,10 +333,42 @@ admin, em `tests/api/tracking.test.mjs` (a limpeza, sem browser) e
309
333
 
310
334
  Uma versão nova: subir a `version` no `package.json` (semver: uma mudança no
311
335
  que os forms ou os eventos levam é minor, uma que parte uma integração é
312
- major), `npm run build`, PR, e depois do merge, da `main`:
336
+ major), `npm run build`, PR, e depois do merge, da `main`, nesta pasta:
337
+
338
+ ```bash
339
+ npm publish --dry-run
340
+ ```
313
341
 
314
342
  ```bash
315
343
  npm publish
316
344
  ```
317
345
 
346
+ O primeiro confere a versão e os ficheiros sem publicar nada. **O segundo é do
347
+ dono**: a conta do npm (`funnel10x-org`) tem 2FA, e o `npm publish` pede uma
348
+ autenticação no browser (*EOTP: This operation requires a one-time
349
+ password*) mesmo com a sessão iniciada (medido a 2026-10-08, na 1.3.0). Um
350
+ agente prepara a pasta na `main` e corre o primeiro, e o dono corre o segundo
351
+ no terminal dele.
352
+
353
+ Depois de publicar, o npm avisa que a versão *may take a few minutes to become
354
+ available*: espera-se, e só então se confirma. O `npm view` lê de uma cache e
355
+ mostrou a versão anterior durante esses minutos; o registo, lido directamente,
356
+ diz a verdade:
357
+
358
+ ```bash
359
+ curl -s https://registry.npmjs.org/@funnel10x%2ftracking | node -e "process.stdin.on('data',d=>b+=d);let b='';process.stdin.on('end',()=>console.log(JSON.parse(b)['dist-tags']))"
360
+ ```
361
+
362
+ E o `tag.js` que o jsDelivr serve tem de ter o hash do `integrity` da tag do
363
+ GTM, senão a tag não carrega em site nenhum. As duas linhas têm de dar o mesmo
364
+ `sha384-…`:
365
+
366
+ ```bash
367
+ echo "sha384-$(curl -sL "https://cdn.jsdelivr.net/npm/@funnel10x/tracking@$(node -p "require('./package.json').version")/dist/tag.js" | openssl dgst -sha384 -binary | openssl base64 -A)"
368
+ ```
369
+
370
+ ```bash
371
+ grep -o 'sha384-[^"]*' dist/gtm.html
372
+ ```
373
+
318
374
  O `dist/THIRD_PARTY_LICENSES.txt` leva as licenças do que vai embutido.
package/dist/gtm.html CHANGED
@@ -1,4 +1,4 @@
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. -->
1
+ <!-- @funnel10x/tracking@1.4.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}}',
@@ -6,4 +6,4 @@
6
6
  checkoutHosts: []
7
7
  }
8
8
  </script>
9
- <script src="https://cdn.jsdelivr.net/npm/@funnel10x/tracking@1.3.0/dist/tag.js" integrity="sha384-BFUxhoktzA6AWF2yGaTdVq+krqyK0WqpmJfPAP3ga7hqHXxJu+WXr2lLbx6CH6G0" crossorigin="anonymous"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/@funnel10x/tracking@1.4.0/dist/tag.js" integrity="sha384-UTBEFP06SUs6EqWR2bkYb7Rq6QEj2SWvMGpf1/3g4uhyNGYMzyucjjeHtYYoW/xD" crossorigin="anonymous"></script>