Track
Dispositivos
Origens de tráfego
Rastreamento — jornada do visitante
| Hora (São Paulo) |
Identidade | Página rastreada |
Visitante | IP / Localização |
Dispositivo / Conexão |
Tempo / Scroll |
Vídeo | Pixels | CTAs | UTM | Afiliado | Eventos |
|---|
| Lead | Identificado em | Página rastreada |
Visitas | Engajamento total | Dispositivo | Local |
|---|
| Afiliado | Loja | Visitantes | Visitas | Leads | Engajamento médio |
Vendas | Receita | Conversão | Última visita |
|---|
soufit.com e loja.soufit.com são a mesma aplicação
Laravel, servida em dois subdomínios — os arquivos
storefront.js e webhook-tracking.js são idênticos byte
a byte nos dois, e cada um tem o próprio checkout no mesmo domínio.
Como o cookie de identidade vale em
.soufit.com, o mesmo
visitante atravessa os dois. Isso é ótimo para a jornada e perigoso para a
comissão: a UTM do visitante é de primeiro toque, então quem já tinha
entrado pelo orgânico e só depois clicou no link do afiliado teria a venda
creditada ao orgânico.
Por isso o afiliado é guardado em campo próprio, com último clique e janela configurável em Integrações — a regra padrão do mercado. Ele nunca toca na UTM.
| Enviado em | Contato | Assunto | Abriu? | Aberturas | Última abertura | Origem | No painel |
|---|
Checkout próprio — intenção de compra e venda
| Quando | Identidade | Página rastreada |
Etapa | Produto | Valor | Pedido | Origem | Veio de |
|---|
t.js no site (o visitante clicando), o webhook do checkout
e o postback do gateway. Os três são propositalmente redundantes: se o
checkout cair depois de aprovar o pagamento, a Pagar.me ou a Appmax ainda avisam.
A coluna Veio de mostra qual caminho entregou cada linha.
Configure os três em Integrações. Enquanto nenhum estiver ligado, esta aba fica vazia — não é erro.
| Abandonou em | Quem | Página rastreada |
Parou em | Produto | Valor perdido |
Origem | Recuperável |
|---|
add_to_cart ou checkout e
não tem nenhuma purchase depois disso. Quem comprou sai da
lista automaticamente — não é preciso marcar nada.
Quem aparece como recuperável já deixou e-mail: é a lista que vai para a campanha de carrinho abandonado no Mautic. Quem está sem contato só pode ser alcançado por remarketing pago.
| Chegou em | Origem | Evento | Pedido | Resultado | Motivo |
|---|
Linha nenhuma significa que nada chegou: o webhook ainda não foi configurado do outro lado, ou está apontando para o endereço errado.
Shopify — loja soufitmoderno.com
| Quando | Pedido | Cliente | Produto | Valor | Pagamento | Entrega | Origem | No painel |
|---|
Quem aparece como no painel também tem jornada de navegação rastreada aqui — o botão abre as duas metades na mesma linha do tempo. Para que isso aconteça com mais gente, o webhook da Shopify precisa estar ligado (Integrações): é ele que liga a venda ao visitante anônimo que navegou antes.
| Abandonou em | Quem | Produto | Itens | Valor perdido | Origem | Recuperável |
|---|
Exige o escopo
read_checkouts no app privado. Se esta aba der erro
de permissão, é esse escopo que está faltando.
| Produto | Status | Preço | Variantes | Imagens | Estoque | Criado em |
|---|
Yampi — loja e checkout
| Quando | Pedido | Cliente | Produto | Valor | Status | Pagamento | Rastreio | No painel |
|---|
Duas armadilhas da API já tratadas: as consultas da Yampi têm cache de 30 minutos por padrão (o painel pede
skipCache em toda chamada, senão você veria venda de meia hora
atrás achando que é a de agora), e cliente, itens, status e data
só vêm se pedidos explicitamente — sem isso a tabela viria só com números.
| Abandonou em | Quem | Produto | Itens | Valor perdido |
Tentativas de pagamento | Origem | Recuperável |
|---|
O botão Recuperar abre a
purchase_url da Yampi, que devolve
a pessoa ao carrinho já montado. É esse link que vai para a campanha de resgate.
| Produto | Status | Preço | Variantes | Imagens | Estoque | SKU |
|---|
Pagar.me — o gateway
| Quando | Código | Cliente | Produto | Valor | Método | Status | Motivo da recusa |
|---|
| Chegou em | Origem | Evento | Pedido | Resultado | Motivo |
|---|
Vale conferir as duas: transação que aparece na API e não aparece aqui significa postback mal configurado do lado do gateway.
Integrações
O que for salvo aqui é embutido no t.js servido ao site.
Mudança entra em vigor em até 5 minutos, sem o gestor do site tocar em nada.
📧 Mautic e-mail e automação
Traz para o painel o que acontece depois do e-mail: envios, aberturas, campanhas e pontuação. Leitura apenas — o painel não altera nada no Mautic.
t.js injeta o mtc.js sozinho, só depois do aceite de cookies.
O gestor do site não precisa colar nada a mais.API enabled: Yes e Enable HTTP basic auth: Yes.
Os campos de token (60 / 14) são do OAuth2 e não afetam esta integração.
🛒 Comércio — de onde vêm as vendas
Duas plataformas vendendo em paralelo, com arquiteturas incompatíveis. Cada uma entra no painel pelo caminho que a plataforma permite: o checkout próprio empurra por webhook; a Shopify é consultada pela API. O resultado aparece separado na aba Checkout.
🧾 Checkout próprio Laravel · webhook
O checkout em checkout.soufit.com avisa este painel
a cada etapa. É o caminho principal da venda do site atual: chega antes do
gateway e traz o visitor_id, que é o que liga a compra à navegação
que veio antes dela.
—
.env do checkout. Nunca na URL —
URL fica gravada em log de servidor.O que o desenvolvedor precisa enviar
POST em JSON, com o cabeçalho
X-Soufit-Signature: sha256=<hmac_sha256(corpo, segredo)>.
{
"evento": "purchase",
"pedido": "12345",
"status": "paid",
"gateway": "pagarme",
"total": 299.80,
"email": "cliente@email.com",
"nome": "Maria Silva",
"telefone": "11999998888",
"visitor_id": "o valor do cookie sft_vid, se existir",
"itens": [{ "sku": "WHEY-900", "nome": "Whey 900g", "preco": 299.80, "qtd": 1 }],
"utm": { "utm_source": "facebook", "utm_campaign": "black" },
"url": "https://checkout.soufit.com/obrigado/12345",
"ocorrido_em": "2026-10-28T15:04:05-03:00"
}
Etapas aceitas: product_view, add_to_cart,
checkout, purchase, refund.
O campo que mais importa é o visitor_id — é o valor do
cookie sft_vid que o t.js já grava no navegador.
Repassá-lo faz a venda se juntar a toda a navegação anterior, inclusive à
que aconteceu antes de a pessoa se identificar. Sem ele, a venda entra
ligada só pelo e-mail.
Em PHP: hash_hmac('sha256', $corpo, $segredo), com
$corpo sendo o JSON exatamente como foi enviado.
Reenvio do mesmo pedido não duplica a venda: a chave
pedido + etapa é única. Pode repetir sem medo.
🛍️ Shopify loja soufitmoderno.com
Plataforma fechada: não há como instalar código de servidor nem ler o banco dela. Só existem dois caminhos, e o painel usa os dois — Admin API para o histórico (aparece inteiro assim que o token é colado) e webhook para o tempo real, que é o que permite costurar a venda com a navegação já gravada aqui.
—
Como obter o token e o que ele precisa poder ler
No admin da Shopify: Configurações → Apps e canais de vendas → Desenvolver apps → Criar app. Em Configuration → Admin API scopes, marcar:
read_orders vendas (aba Vendas) read_checkouts carrinhos abandonados (aba Abandonos) read_products catálogo (aba Produtos) read_customers nome e contato do comprador
Depois Install app e copiar o Admin API access token
(começa com shpat_). Ele só aparece uma vez — se perder,
precisa gerar outro.
⚠️ read_orders só alcança os
últimos 60 dias. Para o histórico completo é preciso solicitar
read_all_orders à Shopify, com justificativa.
Para o tempo real: Configurações → Notificações → Webhooks, e cadastrar
o endereço acima nos eventos orders/paid,
orders/create, checkouts/create,
checkouts/update e refunds/create.
🛒 Yampi loja e checkout
Plataforma brasileira de loja e checkout. Entra pelos dois caminhos: API para o histórico (aparece inteiro assim que as credenciais são salvas) e webhook para o tempo real, que é o que liga a venda à navegação já gravada aqui.
api.dooki.com.br/v2/alias/orders—
Onde pegar as credenciais e o que cadastrar
No painel da Yampi: Configurações → Credenciais de API. Copie o
User-Token e a User-Secret-Key — são dois valores
diferentes, e os dois são obrigatórios.
Para o tempo real, cadastre o endereço acima em Configurações → Webhooks, nestes eventos:
order.paid venda confirmada order.created pedido criado (ainda não pago) order.status.updated mudou de status (pago, estornado, cancelado) transaction.payment.refused pagamento recusado cart.reminder carrinho abandonado
⚠️ A Yampi desativa o webhook sozinha após 30 falhas seguidas, e exige resposta em até 5 segundos. Se as vendas pararem de chegar em tempo real, conferir primeiro se o webhook continua ativo lá.
Duas armadilhas da API já tratadas aqui: as consultas GET
da Yampi têm cache de 30 minutos por padrão — o painel manda
skipCache=true em toda chamada, senão você veria venda de meia
hora atrás achando que é a de agora. E quase nada vem por padrão: cliente,
itens, status e data só aparecem com include, que o painel já envia.
💳 Pagar.me gateway · postback
Rede de segurança do checkout próprio: se o checkout cair depois de o pagamento ser aprovado, o gateway ainda avisa e a venda não se perde.
—
pk_ que está no
HTML do checkout não serve aqui — aquela só tokeniza cartão.order.paid, charge.paid,
charge.refunded.
Valores chegam em centavos e são convertidos aqui.
🏦 Appmax gateway · postback
O checkout atual usa dois gateways em paralelo. Deixar a Appmax de fora esconderia metade das vendas — a varredura de 28/10/2026 achou 19 menções a Appmax contra 5 a Pagar.me no código do checkout.
—
X-Appmax-Token.OrderApproved, OrderPaid,
OrderPaidByPix, OrderIntegrated,
OrderRefund, ChargebackDispute.
Falta confirmar com o desenvolvedor qual critério manda uma venda para Pagar.me e qual manda para Appmax — sem isso não dá para saber se uma ausência no painel é erro de integração ou roteamento normal.
🤝 Afiliados loja.soufit.com
loja.soufit.com é o mesmo Laravel de
soufit.com em outro subdomínio. Como o cookie de identidade vale em
.soufit.com, o mesmo visitante atravessa os dois — e a UTM dele é de
primeiro toque. Sem um campo separado, a venda do afiliado seria creditada
a quem trouxe a pessoa da primeira vez.
loja.soufit.com/?ref=MARIA99https://loja.soufit.com/?ref=TESTE numa aba anônima, aceite o banner
se aparecer, e veja a linha surgir em Track › Afiliados. No console do
navegador, soufit.afiliado() devolve o valor reconhecido.
🎬 VTurb vídeo
Player de VSL. Usa shadow DOM fechado, então o rastreamento
é feito pela API de eventos do smartplayer — não por DOM.
📘 Meta Pixel anúncios
Apenas registra quais pixels existem na página. O painel não dispara eventos para a Meta.
meta-tracking.js com trackSingle e deduplicação de CAPI
(eventID). Um segundo disparo duplicaria eventos e quebraria a atribuição.
📊 Google Analytics analytics
Registra a presença do GA4 para cruzar com os dados do painel.
🔗 UTM e atribuição origem
📌 Pinterest anúncios
🎵 TikTok anúncios
🌐 Site e coleta
📋 Script para o gestor do site
Uma linha, imediatamente antes do </head>.
Não muda quando as integrações mudam.
Onde o script já está instalado
Lista os domínios de onde chegaram eventos de verdade. Se aparece aqui, está no ar. Se não aparece, ainda não foi publicado — ou ninguém visitou desde a publicação.
LGPD
Consentimento, transparência e direitos do titular.
O que for salvo aqui é embutido no t.js servido ao site e entra
em vigor em até 5 minutos, sem o gestor do site tocar em nada.
⚖️ Banner de consentimento LGPD obrigatório em produção
Ligando isto, o t.js desenha uma barra no rodapé do site.
Nada é enviado antes do aceite — os eventos ficam numa fila. Em "Recusar",
a fila é descartada e o visitante não é rastreado. A escolha fica guardada no navegador.
soufit.com na lista
não faz o banner aparecer em lp.soufit.com.🔒 Trava de coleta
Use só se o site tiver banner próprio (Cookiebot, OneTrust
ou feito pelo time). Com isto ligado, nada é coletado até o site chamar
soufit.consent(true) no código dele — e nenhum banner é desenhado.
soufit.consent(true).Direitos do titular — LGPD Art. 18
Use para atender pedidos recebidos em privacidade@soufit.com.