Docs
Referência

Regras de tag

Uma regra de tag faz uma interação no site virar um evento. Ela vive sob /track, pertence a um servidor de rastreamento identificado pelo Host da requisição e é gerenciada com um token de conta que tenha a feature WebTracking; envelope e códigos seguem convenções e erros.

Uma regra tem um trigger, que diz quando ela dispara, e extractors, que dizem quais parâmetros o evento leva. O trigger é uma árvore de nós.

Nota

Regra e destino são metades diferentes da medição. A regra captura no navegador; o destino envia ao Meta, GA4, TikTok. Medir uma conversão de ponta a ponta precisa das duas.

Endpoints

MétodoCaminhoO que fazAcesso
POST/track/rulesCria uma regra. 409 se o nome já existe naquele servidor.Standard + WebTracking
GET/track/rulesLista as regras do servidor, em ordem de criação. Inclui as pausadas.ReadOnly + WebTracking
PUT/track/rules/{rule_name}Cria ou substitui a regra daquele nome.Standard + WebTracking
DELETE/track/rules/{rule_name}Exclui uma regra pelo nome.Standard + WebTracking
POST/track/versionsPublica o rascunho.Standard + WebTracking
GET/track/versionsLista as publicações, da mais nova para a mais antiga.ReadOnly + WebTracking
GET/track/versions/{publish_id}Devolve uma publicação com as regras dela.ReadOnly + WebTracking
POST/track/versions/{publish_id}/republishPublica de novo uma publicação anterior (volta de versão).Standard + WebTracking
GET/track/tagEntrega ao tag do navegador as regras habilitadas da publicação em vigor.Público

Nota

GET /track/tag e POST /track/collect formam o par público do navegador, ambos resolvidos pelo Host e sem token. Quem os chama é o tag do navegador: /track/tag recebe as regras, /track/collect recebe os eventos que o tag dispara. Você gerencia as regras pelas quatro rotas de /track/rules.

A feature WebTracking não vem por padrão (uma conta nova recebe só Chat). Sem ela, mesmo com token válido, as quatro rotas de /track/rules respondem 403 em texto puro com o corpo Feature disabled: WebTracking; níveis e features em autenticação.

PUT é a forma de alterar uma regra. Não existe PATCH: o corpo do PUT é a definição completa e substitui a anterior.

As quatro rotas de /track/rules editam um rascunho. O site só recebe as regras depois de um POST /track/versions; ver Rascunho e publicação.

Identificação do servidor

O servidor alvo sai do Host/TLS da requisição; não existe parâmetro de servidor.

  • A chamada vai ao domínio do próprio servidor de rastreamento, resolvido do Host da requisição e do nome do servidor TLS (SNI). A URL base destas rotas é https://<server_name>, por exemplo https://track.exemplo.com.br/track/rules, e não a base do resto da API. Chamar /track/rules num domínio que não é servidor da conta dá 404.
  • Se Host e nome do servidor TLS vierem e divergirem, a resposta é 400 em texto puro, corpo literal Host header does not match TLS server name.
  • Nas rotas de /track/rules, o servidor ainda precisa pertencer à conta do token; sem servidor para aquele Host e conta, 404 (Error 404: server not found). O público GET /track/tag resolve o servidor só pelo Host, sem cláusula de conta, com o mesmo 404 quando não há servidor.

Corpo de uma regra

CampoTipoObrigatórioDescrição
rule_namestringSim, no POSTNome da regra, texto livre de 1 a 64 caracteres (contados como caracteres, não bytes). Não pode ter espaço no início nem no fim, caractere de controle, /, %, ? ou #, nem ser só pontos (., ..). Espaços, acentos e maiúsculas valem, como em Clique no botão de compra. Único por servidor e chave do PUT e do DELETE. Também é a chave de deduplicação de um Once com per Session ou User: renomear a regra zera a dedup dela.
event_namestringSimNome do evento que a regra envia, ^[a-z][a-z0-9_]{0,39}$ (snake_case, dentro do limite de 40 caracteres do GA4).
triggerobjetoSimQuando a regra dispara. É uma árvore; ver abaixo.
extractorsobjetoNãoParâmetros do evento, mapeados por nome do parâmetro (^[a-z][a-z0-9_]{0,39}$) para uma expressão. Omitido, nenhum.
enabledbooleanNãoPadrão true. Uma regra pausada continua em GET /track/rules e não vai para GET /track/tag.
conversionbooleanNãoPadrão false. Marca os eventos da regra como conversões nos relatórios de rastreamento; parameters.value, quando numérico, é o valor da conversão. Devolvido em GET /track/rules, não entregue em GET /track/tag.

No PUT, o corpo não tem rule_name: o nome vem do caminho {rule_name} e passa pela mesma validação. No PUT e no DELETE, um nome com espaço ou acento vai percent-encoded nesse segmento da URL. A substituição é completa: enabled e conversion omitidos voltam aos padrões, extractors omitido vira vazio, e nada do corpo anterior é preservado.

O tag do navegador acrescenta a todo evento três parâmetros base: href, page_title e page_referrer (este só quando document.referrer não é vazio). Uma chave de mesmo nome em extractors sobrescreve o valor base naquele evento.

trigger

Cada nó do trigger tem um campo type; campos desconhecidos são recusados. Sete tipos são fontes: disparam sozinhos e ficam nas folhas da árvore.

typeQuando disparaEntrega
ElementEventUm evento DOM em todo elemento que casa com o seletor, inclusive elementos inseridos depois da instrumentação. Campos: selector, event.elemento e evento
PageReadyUma vez, quando o DOM está pronto; retroativamente se já estiver. Sem campos.nada
WindowEventUm evento DOM em window, como scroll ou resize. Campo: event.evento, sem elemento
TimerA cada interval_ms milissegundos (1000 a 3600000). Navegadores estrangulam timers em abas de fundo.nada
ScrollDepthUma vez por limiar por carregamento. Campo: thresholds (1 a 10 valores de 1 a 100, estritamente crescentes).evento tgsr:scroll_depth com detail.threshold_pct
TimeEngagedUma vez por limiar por carregamento, contando só os segundos visíveis. Campo: thresholds_s (1 a 10 valores de 1 a 3600, estritamente crescentes).evento tgsr:time_engaged com detail.threshold_s e detail.engaged_ms
ElementVisibleUma vez por elemento por carregamento, quando um elemento que casa com selector cruza a viewport em pelo menos ratio (IntersectionObserver). ratio acima de 0 e até 1, padrão 0.5.elemento, sem evento

Três tipos são envelopes: cada um carrega um inner, que é outro trigger.

typeO que fazCampos
OnPageSó deixa o inner disparar quando location.href casa com regex. Reavaliado na navegação de SPA.regex, inner
OnceDeduplica o inner ao primeiro disparo por escopo per.per, inner
SideEffectRoda JavaScript, o corpo de (element, event) => pass, a cada disparo do inner, antes de capturar e enviar; retornar false engole aquele disparo.source, inner

O per de Once é um de:

  • Page: por carregamento de página, em memória.
  • Element: por elemento casado. Exige um inner que entregue elemento (que termine em ElementEvent ou ElementVisible); caso contrário, o servidor recusa com 400.
  • Session: por sessão de aba, em sessionStorage, com chave no nome da regra.
  • User: por perfil do navegador, em localStorage, com chave no nome da regra.

Aviso

A ordem dos envelopes muda o resultado. Once por fora, OnPage no meio, SideEffect junto da folha. Um OnPage por fora de um Once gasta o disparo único antes do filtro de URL: com per Session ou User, a regra pode nunca mais enviar naquele navegador. A API aceita as duas ordens.

Exemplo: o clique no botão de compra, só no checkout, uma vez por sessão.

json
{
  "type": "Once",
  "per": "Session",
  "inner": {
    "type": "OnPage",
    "regex": "/checkout(/|$)",
    "inner": {
      "type": "ElementEvent",
      "selector": "button.buy",
      "event": "click"
    }
  }
}

extractors

extractors é um objeto: a chave é o nome do parâmetro do evento, o valor é uma expressão. Uma expressão é uma de duas coisas:

  • um nó, um objeto com type;
  • uma cadeia, um array de expressões avaliadas da esquerda para a direita, cada passo consumindo a saída do anterior.

Qualquer passo pode haltar, ou seja, parar sem produzir valor. A cadeia para e o parâmetro é omitido do evento. É o comportamento normal: um atributo ausente não é erro.

Os nós, por família:

Leem o elemento:

typeProduzHalta quando
Attr (name)getAttribute(name) do elementoo atributo não existe
TexttextContent aparadoo texto é vazio
Valueo .value do controle
Hostnameo hostname de um <a>/<area>, para link externo
Field (name)o .value do campo daquele nome no formulário carregado

Leem o contexto:

typeProduzHalta quando
EventProp (key)uma propriedade do evento DOM; caminho com pontos percorrido segmento a segmento, como detail.threshold_pct
Location (part)href, pathname, host, hostname, search, hash ou origin
UrlParam (name)um parâmetro de queryo parâmetro não existe
DocumentProp (key)title, referrer, readyState, visibilityState, characterSet ou contentType
WindowProp (key)scrollX, scrollY, innerWidth, innerHeight, outerWidth, outerHeight ou devicePixelRatio
Constant (value)um valor fixo: string, número ou boolean. Útil como último ramo de um Or

Andam pelo DOM:

typeProduzHalta quando
Closest (selector)o elemento que casa com o seletor, subindo a partir do atualnão casa
Find (selector)querySelector(selector) a partir do elementonão casa
ParentparentElementa raiz está solta

Filtram:

typeO que faz
WhenMatches (regex)mantém o valor se a forma em string casa com o regex, senão halta
WhenEquals (value)mantém o valor se for estritamente igual, senão halta

Transformam:

typeO que faz
Trimapara o valor
Lowercasepassa o valor para minúsculo
ToNumberconverte para número; NaN halta
RegexCapture (regex, group)entrega um grupo de captura (0 a 9, padrão 1); sem casamento, halta
Truncate (max_len)corta em no máximo max_len caracteres (1 a 500)
Slugtira marcas de combinação, minúsculo, colapsa não alfanuméricos em _, apara _; vazio halta
UrlDecodedecodeURIComponent; escape malformado halta
HashSHA-256 da forma em string, em hexadecimal minúsculo, calculado pelo tag: o valor nunca sai do navegador em claro. Normalize antes (Trim, Lowercase) para o hash casar entre eventos e com as plataformas. O servidor não hasheia nada: parâmetro sem Hash é gravado como enviado

Combinam:

typeO que faz
Or (branches)de 2 a 8 expressões tentadas em ordem contra o valor de entrada; vence a primeira que produzir valor; se todas haltarem, halta
Script (source)JavaScript, o corpo de (value, state) => result, rodado pelo tag via new Function; undefined halta

Aviso

Existe um sistema de tipos implícito que o servidor não valida. Os nós que leem DOM (Attr, Text, Closest e afins) exigem um elemento; os que transformam exigem um valor. Uma cadeia como [{"type":"Location","part":"href"},{"type":"Attr","name":"id"}] passa pela API e estoura no navegador. Um extractor que estoura descarta o evento inteiro, não só aquele parâmetro. A ordem certa: comece no elemento, ande pelo DOM, leia um valor, depois transforme.

Aviso

Um Script ou um SideEffect com erro de sintaxe passa pela API. O servidor só limita o tamanho e recusa fonte vazia; ele não interpreta o JavaScript. O erro aparece no navegador, na instrumentação, e o tag pula aquela regra.

Exemplo: o id do produto, com um caminho alternativo, e o preço convertido para número.

json
{
  "product_id": {
    "type": "Or",
    "branches": [
      [
        { "type": "Closest", "selector": "[data-product]" },
        { "type": "Attr", "name": "data-product" }
      ],
      { "type": "UrlParam", "name": "sku" }
    ]
  },
  "price": [
    { "type": "Find", "selector": ".price" },
    { "type": "Text" },
    { "type": "ToNumber" }
  ]
}

Limites

Validados na escrita; estourar é 400 no envelope.

LimiteValor
Regras por servidor200
Bytes por regra (JSON serializado de trigger + extractors)16 KiB
Profundidade do trigger (folha incluída)8 níveis
Parâmetros em extractors32
Nós por expressão32
Profundidade por expressão8 níveis
Ramos de um Or2 a 8
Seletor CSS512 bytes, não vazio, sem caracteres de controle
Regex256 bytes
source de Script e SideEffect8 KiB
Nome de atributo, campo ou parâmetro de query (Attr, Field, UrlParam)128 bytes
Nome de evento DOM^[a-zA-Z][a-zA-Z0-9_:-]{0,63}$
key de EventPropaté 64 caracteres, segmentos separados por ponto

O teto de 200 é checado excluindo a própria regra: um PUT sobre uma regra que já existe passa mesmo com o servidor no teto.

Os regex de OnPage, WhenMatches e RegexCapture seguem um dialeto que é subconjunto estrito do JavaScript: sem lookaround e sem backreference. Um padrão que funciona no navegador pode ser recusado aqui.

O servidor não interpreta CSS: um seletor sintaticamente inválido passa pela API e só falha no navegador.

Rascunho e publicação

POST, PUT e DELETE em /track/rules mudam o rascunho do servidor. O GET /track/tag entrega ao navegador a publicação em vigor, que só muda com uma publicação nova.

GET /track/rules devolve o rascunho e o compara com o que está no ar:

  • cada regra traz publish_state: new (não está na publicação em vigor), published (igual à publicada) ou modified;
  • deleted_rules lista as regras publicadas que o rascunho não tem mais; a próxima publicação as tira do site;
  • etag é um hash opaco do conteúdo do rascunho;
  • live_publish_id é a publicação em vigor, ou null se o servidor nunca publicou.

POST /track/versions publica o rascunho. Corpo: name (obrigatório, de 1 a 100 caracteres) e description (opcional, até 1000). Mande o etag lido em GET /track/rules no cabeçalho If-Match: assim vai ao ar exatamente o que foi revisado. A resposta é { "publish_id": "<id>", "published": true }; quando o rascunho já é igual à publicação em vigor, nada é criado e a resposta traz published: false com o publish_id em vigor.

  • 412: o rascunho mudou depois da leitura (If-Match não confere). Leia e revise de novo.
  • 409: outra publicação entrou no ar ao mesmo tempo. Publique de novo.

GET /track/versions responde { "live_publish_id": ..., "publishes": [ ... ] }, da mais nova para a mais antiga (a primeira é a que está no ar). Cada item tem publish_id, name, description, published_at (UTC, ISO 8601 sem fuso), published_by (e-mail de quem publicou; null quando foi o sistema, como na instalação das regras padrão), restored_from (a publicação de origem, numa volta de versão) e rule_count. GET /track/versions/{publish_id} traz os mesmos campos e rules, as regras como foram publicadas, na ordem em que o tag as instrumenta; publicação inexistente dá 404 (Error 404: publish not found).

POST /track/versions/{publish_id}/republish põe no ar de novo uma publicação anterior, com o mesmo corpo name/description. Não usa If-Match e não altera o rascunho.

No painel do app, a publicação fica no botão "Publicar" de Rastreamento › Regras; o histórico e a volta de versão existem só pela API e pelo MCP.

Cache do GET /track/tag

  • ETag fraco (W/"<publish_id>") com o id da publicação em vigor (W/"0" quando o servidor nunca publicou).
  • Cache-Control: max-age=60.
  • Um If-None-Match igual ao ETag responde 304, sem corpo, com ETag e Cache-Control.

Uma publicação nova pode levar até um minuto para chegar aos navegadores que já carregaram a configuração.

GET /track/tag?draft=true entrega as regras habilitadas do rascunho, com Cache-Control: no-store. É o que a aba de inspeção do painel (Visualizar) usa para rodar as regras antes de publicar.

Ordem das regras

GET /track/rules e GET /track/tag devolvem as regras em ordem de criação (/track/tag, na ordem da publicação); /track/tag entrega só as habilitadas. É nessa ordem que o tag do navegador instrumenta as regras.

Regras padrão

Todo servidor de rastreamento nasce com 8 regras:

rule_nameDispara emParâmetros
page_viewPageReadynenhum
scroll_depthScrollDepth em 25, 50 e 90threshold_pct
time_engagedTimeEngaged em 10 e 60 sthreshold_s
outbound_linkclique em a[href^="http"]url, text
file_downloadclique em link para .pdf, .zip, .xlsx, .xls, .docx, .pptx, .csvurl, file_name
form_startprimeiro focusin em cada form (Once com per: Element)form_id (id ou name)
form_submitsubmit em formform_id
contact_clickclique em link de WhatsApp (wa.me, api.whatsapp.com, whatsapp:), tel: ou mailto:url, channel (whatsapp, phone, email)

Elas vêm habilitadas e sem conversion, podem ser editadas ou excluídas como qualquer regra e contam no teto de 200 (GET /track/rules num servidor recém-criado devolve 8 itens). A instalação roda a cada PUT /servers do servidor, mas só quando ele não tem nenhuma regra nem nenhuma publicação, e já publica as 8 regras; um servidor com regras ou com alguma publicação (mesmo vazia) fica como está. Uma falha na instalação não derruba a criação do servidor.

Respostas

Sucesso e erros de validação da própria rota usam o envelope padrão ({"Ok": ...} / {"Err": "..."}, Content-Type: application/json), com o status derivado do prefixo Error NNN: da mensagem; ver convenções e erros. Os corpos abaixo chegam dentro do envelope: no fio, GET /track/rules responde { "Ok": { "rules": [...] } }, o POST { "Ok": { "rule_name": "<nome>" } }, e assim por diante.

EndpointCorpo da resposta
POST /track/rules{ "rule_name": "<nome>" }
PUT /track/rules/{rule_name}{ "rule_name": "<nome>", "created": true | false }. true quando o PUT criou a regra, false quando substituiu.
GET /track/rules{ "rules": [ ... ], "deleted_rules": [ ... ], "etag": "...", "live_publish_id": ... }, cada regra com rule_name, event_name, enabled, conversion, trigger, extractors, created_at, updated_at, publish_state.
POST /track/versions e .../republish{ "publish_id": "<id>" | null, "published": true | false }.
DELETE /track/rules/{rule_name}{ "deleted": true | false }. false quando nada foi excluído.
GET /track/tag{ "rules": [ ... ] }, cada item com rule_name, event_name, trigger, extractors; só as habilitadas da publicação em vigor (ou do rascunho, com ?draft=true).

Erros no envelope:

  • 400: regra que não passa na validação (limite estourado, regex que não compila, seletor vazio, thresholds fora de ordem, Once com per: Element sem elemento). A mensagem nomeia o que falhou, por exemplo Error 400: trigger: ... ou Error 400: extractor '<nome>': ....
  • 400: nome inválido, corpo Error 400: invalid rule_name (want 1 to 64 characters, no leading or trailing whitespace, none of / % ? #, no control characters, not only dots).
  • 400: teto alcançado, corpo Error 400: rule limit of 200 per server reached.
  • 404: Error 404: server not found. Em /track/rules, para o Host e a conta do token; em GET /track/tag, só pelo Host.
  • 409: POST /track/rules com rule_name que já existe no servidor, corpo Error 409: rule '<nome>' already exists; PUT /track/rules/<nome> updates it. O POST não sobrescreve.

Erros em texto puro, fora do envelope (produzidos antes de a rota processar a requisição, sem {"Err": ...}). Não faça parse de {"Err": ...} em toda resposta não 2xx:

  • 400: Host header does not match TLS server name.
  • 401 (Not authorized, Bad format: ...) e 403 (Bad token, Insufficient privilege: ..., Feature disabled: WebTracking), da autenticação.
  • Rejeições de parse do corpo: um type desconhecido, um campo a mais, um valor fora das listas fechadas (part, key, per), um campo obrigatório ausente ou um Constant com objeto ou null falham antes da validação. Voltam em texto puro, tipicamente com 422; JSON malformado dá 400, e a falta de Content-Type: application/json dá 415.

Veja também

  • Servidores: o servidor de rastreamento dono das regras.
  • Destinos de rastreamento: a outra metade da medição, para onde o evento capturado é enviado.
  • Autenticação: os níveis Standard e ReadOnly e a feature WebTracking exigidos pelas rotas.