Configuração · Imobiliárias
Uma tag no Gerenciador de Tags e um campo no CRM, cerca de 20 minutos. Ao final, cada lead seu carrega um identificador da sessão, e nós cruzamos esse identificador com quem usou o Meu Decorado.
O seu site passa a dar a cada visitante um identificador anônimo: uma sequência aleatória, sem nome, e-mail nem telefone. Ele chega ao Meu Decorado e ao lead dos seus formulários, e é isso que liga um ao outro.
Como a conta fecha: o identificador viaja com o lead até o seu CRM e também com os eventos do decorado, que chegam até nós. Nós cruzamos os dois lados e dizemos quais leads seus passaram pelo decorado.
Isto entrega atribuição no seu CRM, não um funil no seu GA4. O decorado de imobiliária não publica passos de funil para a página em volta, em endereço nenhum. Se você quiser o funil no GA4, fale com a gente: depende de mudança do nosso lado.
Dê acesso de editor no Gerenciador de Tags. Nós configuramos e testamos, e a publicação continua com você: acesso de editor não publica.
Aqui não é preciso cadastrar domínio do nosso lado. Esse passo existe no formato de incorporadora, que funciona de outro jeito.
Preencha abaixo e o código da Etapa 2 se ajusta sozinho, pronto para copiar. Só quem escolher "Outro" em como o site registra o aceite precisa trocar uma linha dentro do código, e a página indica qual.
O que você preencher fica salvo neste navegador, para não se perder ao voltar. Se for configurar outro site, limpe antes.
Nova tag de HTML personalizado, gatilho Inicialização, todas as páginas, consentimento nenhum adicional. A checagem está dentro do código, porque a do Gerenciador de Tags só vale no carregamento e perderia quem aceita depois.
<!--
Arquiteto de Bolso · Meu Decorado — identificador de jornada (abclid)
Cria o identificador no SEU domínio depois do aceite de cookies, entrega-o ao
Meu Decorado quando ele pergunta, e põe o mesmo valor num campo oculto
"abclid" nos formulários de LEAD, para chegar ao CRM junto com o lead.
-->
<script>
(function () {
if (window.__upikAbclid) return; // a tag disparou duas vezes: não duplica listener
// ---------------------------------------------------------------
// Os dados do seu site, preenchidos pelo formulário da Etapa 1.
// ---------------------------------------------------------------
// Os formulários de LEAD do seu site.
var FORMULARIOS = 'PREENCHA O FORMULÁRIO ACIMA';
// O botão "Aceitar" do seu aviso de cookies. "" se não houver um estável.
var BOTAO_ACEITAR = '';
// true só se a pessoa aceitou analytics AGORA. Fechada por padrão: enquanto
// esta regra devolver false, nenhum cookie é gravado.
function consentiu() {
try {
return false;
} catch (e) {
return false; // storage bloqueado conta como "não consentiu"
}
}
// A chave onde o seu banner guarda o aceite, para o aceite dado em OUTRA aba
// valer também nesta. Cookiebot e OneTrust usam cookie e não emitem o sinal.
var CHAVE_CONSENTIMENTO = '';
// Preenchido só se os formulários estiverem em outro subdomínio. Depois de
// instalado, não mude sem apagar o cookie antigo: passariam a existir dois
// cookies de mesmo nome e o errado pode ser lido.
var DOMINIO = '';
// ---------------------------------------------------------------
// Daqui para baixo é igual para todos os sites.
// ---------------------------------------------------------------
var ORIGEM_DECORADO = "https://match-b2b.arquitetodebolso.com.br";
var COOKIE = "upik_abclid";
var NOVENTA_DIAS = 60 * 60 * 24 * 90;
var CAMPO = "abclid";
var FORMATO = /^abc_[0-9a-f]{32}$/;
var LEITOR = new RegExp("(?:^|;\\s*)" + COOKIE + "=(abc_[0-9a-f]{32})(?:;|$)");
// Seletor vazio ou malformado faz `querySelectorAll` e `closest` LANÇAREM.
// Como isto roda em todo clique da página, a exceção apareceria em cada
// clique do site inteiro. Protegido: um seletor errado custa a medição, e não
// o funcionamento do site.
function buscar(seletor) {
if (!seletor) return [];
try {
return document.querySelectorAll(seletor);
} catch (e) {
return [];
}
}
function maisProximo(elemento, seletor) {
if (!seletor || !elemento || !elemento.closest) return null;
try {
return elemento.closest(seletor);
} catch (e) {
return null;
}
}
function lerCookie() {
var m = document.cookie.match(LEITOR);
return m ? m[1] : "";
}
function gravarCookie(valor, validade) {
document.cookie = COOKIE + "=" + valor + ";path=/;max-age=" + validade +
(DOMINIO ? ";domain=" + DOMINIO : "") +
";SameSite=Lax" + (location.protocol === "https:" ? ";Secure" : "");
}
// Apaga nas DUAS formas, com e sem `domain`: o cookie só é removido pelo par
// (domínio, caminho) com que foi gravado. Se o domínio mudou depois da
// instalação, apagar só um deixaria o outro ressuscitar o identificador.
function apagarCookie() {
document.cookie = COOKIE + "=;path=/;max-age=0;SameSite=Lax";
if (DOMINIO) {
document.cookie = COOKIE + "=;path=/;max-age=0;domain=" + DOMINIO + ";SameSite=Lax";
}
}
function novoAbclid() {
var c = window.crypto || window.msCrypto;
if (!c || !c.getRandomValues) return ""; // sem gerador seguro, não inventa um
var bytes = new Uint8Array(16);
c.getRandomValues(bytes);
var hex = "";
for (var i = 0; i < bytes.length; i++) {
hex += (bytes[i] < 16 ? "0" : "") + bytes[i].toString(16);
}
return "abc_" + hex;
}
// Cópia desta página: se o navegador bloquear o cookie, o valor ainda vale
// até o fim dela, e é o MESMO para o decorado e para o formulário.
var memoria = "";
var renovado = false;
function atual() {
if (!consentiu()) {
// Sem aceite, nem o de uma visita anterior vale: o aceite pode ter sumido
// com o cookie ainda lá. Apaga, em vez de deixá-lo pronto para voltar.
var tinha = memoria || lerCookie();
memoria = "";
renovado = false;
if (lerCookie()) apagarCookie();
// Limpa também o que já tiver sido posto nos formulários: revogar não
// dispara clique nenhum, e sem isto o campo oculto sairia com o valor
// velho se o tema enviar por `form.submit()` ou por um botão de fora.
if (tinha) limparCampos();
return "";
}
var valor = lerCookie() || memoria || novoAbclid();
if (!valor) return "";
memoria = valor;
if (!renovado || lerCookie() !== valor) {
gravarCookie(valor, NOVENTA_DIAS);
renovado = true;
}
return valor;
}
window.__upikAbclid = { atual: atual };
function mensagem(valor) {
return { type: "upik:parent-journey", v: 1, abclid: valor };
}
function ehIframeDaPagina(janela) {
var iframes = document.getElementsByTagName("iframe");
for (var i = 0; i < iframes.length; i++) {
if (iframes[i].contentWindow === janela) return true;
}
return false;
}
// O decorado pergunta ("upik:viewer-ready") e a página responde. Só para a
// origem do decorado, e só para um iframe desta página.
window.addEventListener("message", function (e) {
if (e.origin !== ORIGEM_DECORADO) return;
var d = e.data;
if (!d || d.type !== "upik:viewer-ready" || d.v !== 1) return;
if (!e.source || !ehIframeDaPagina(e.source)) return;
var valor = atual();
if (!FORMATO.test(valor)) return; // sem consentimento: não responde nada
e.source.postMessage(mensagem(valor), ORIGEM_DECORADO);
});
// Para quando a página fica pronta DEPOIS de o decorado parar de perguntar, ou
// quando a pessoa aceita os cookies no meio da visita.
var ultimoEntregue = "";
function entregarAosDecorados() {
var valor = atual();
if (!FORMATO.test(valor)) return;
// Não repete a mesma entrega: vários caminhos chamam esta função. Um iframe
// que apareça depois continua coberto, porque ele pergunta ao carregar.
if (valor === ultimoEntregue) return;
ultimoEntregue = valor;
var iframes = document.getElementsByTagName("iframe");
for (var i = 0; i < iframes.length; i++) {
var src = iframes[i].getAttribute("src") || "";
if (src.indexOf(ORIGEM_DECORADO + "/") !== 0) continue;
try {
iframes[i].contentWindow.postMessage(mensagem(valor), ORIGEM_DECORADO);
} catch (err) {
// iframe ainda sem janela: ele vai perguntar quando carregar
}
}
}
// O campo oculto nos formulários de lead.
function preencher(form) {
var valor = atual();
var campo = form.querySelector('input[name="' + CAMPO + '"]');
if (!valor) {
if (campo) campo.value = "";
return;
}
if (!campo) {
campo = document.createElement("input");
campo.type = "hidden";
campo.name = CAMPO;
form.appendChild(campo);
}
campo.value = valor;
}
function preencherTodos() {
var forms = buscar(FORMULARIOS);
for (var i = 0; i < forms.length; i++) preencher(forms[i]);
}
// Esvazia os campos sem consultar `atual()`, porque é chamada de dentro dele,
// no caminho da revogação.
function limparCampos() {
var forms = buscar(FORMULARIOS);
for (var i = 0; i < forms.length; i++) {
var campo = forms[i].querySelector('input[name="' + CAMPO + '"]');
if (campo) campo.value = "";
}
}
// Muitos temas não disparam um submit nativo: um handler de clique valida e
// envia por ajax, serializando os campos. Por isso o campo é atualizado no
// CLIQUE, em fase de captura, antes do handler do botão.
function aoInteragir(e) {
var form = maisProximo(e.target, FORMULARIOS);
if (form) preencher(form);
}
document.addEventListener("click", aoInteragir, true);
document.addEventListener("submit", aoInteragir, true);
// A pessoa clicou em "Aceitar": quando o clique chega aqui, no documento, o
// handler do próprio botão já gravou o consentimento.
if (BOTAO_ACEITAR) {
document.addEventListener("click", function (e) {
if (maisProximo(e.target, BOTAO_ACEITAR)) {
preencherTodos();
entregarAosDecorados();
}
});
}
// O aceite dado em OUTRA aba. Mudança de cookie não emite `storage`, então
// para Cookiebot e OneTrust este caminho não existe. O filtro pela chave
// evita disparar à toa a cada escrita de qualquer outro script do site.
if (CHAVE_CONSENTIMENTO) {
window.addEventListener("storage", function (e) {
if (e.key !== CHAVE_CONSENTIMENTO) return;
preencherTodos();
entregarAosDecorados();
});
}
// Rede de segurança para o aceite TARDIO, e o único caminho que não depende
// de configuração: o decorado só pergunta nos primeiros segundos. Cobre o
// site sem seletor de botão e a ferramenta que grava o consentimento depois
// do clique. Os três minutos contam do carregamento, não do aceite.
var vigia = setInterval(function () {
// Só age COM aceite: sem esta guarda, um `false` passageiro (ferramenta de
// consentimento ainda carregando) apagaria cookie e campos a cada segundo.
// A revogação continua valendo pelos eventos: banner, outra aba e o envio.
if (!consentiu()) return;
if (!FORMATO.test(atual())) return;
// Encerra ANTES do trabalho: exceção em callback de `setInterval` não
// cancela o intervalo, e o trabalho que falhasse se repetiria por 3 minutos.
clearInterval(vigia);
preencherTodos();
entregarAosDecorados();
}, 1000);
setTimeout(function () { clearInterval(vigia); }, 180000);
// A tag roda na Inicialização, antes de os formulários existirem.
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", preencherTodos);
} else {
preencherTodos();
}
// A entrega espontânea espera os iframes carregarem. Se o decorado ainda não
// estiver ouvindo, ele pergunta de novo (1, 3 e 7 s).
if (document.readyState === "complete") {
entregarAosDecorados();
} else {
if (document.readyState === "interactive") entregarAosDecorados();
window.addEventListener("load", entregarAosDecorados);
}
})();
</script>A tag acrescenta um campo oculto abclid nos formulários de lead, e ele já vai no envio. Falta o sistema que recebe o formulário repassá-lo ao CRM, o que costuma ser ajuste do fornecedor do site.
O que pedir a ele: gravar o campo abclid num campo do lead no CRM, normalmente um campo personalizado, em todos os formulários de lead.
Se o seu grupo também usa o Meu Decorado no formato de incorporadora, avise a gente antes de seguir: os dois formatos pedem um campo de mesmo nome e precisam ser separados, senão um sobrescreve o outro.
Sem esta etapa, o identificador fica no navegador e nenhum lead se liga ao decorado. A tag sozinha não produz resultado visível no CRM.
No modo de visualização do Gerenciador de Tags, numa página de imóvel em produção. Sem ele a tag ainda não existe para o navegador, e ele não afeta quem está navegando. Os comandos vão no console.
document.cookie.includes("upik_abclid") deve dar falsetrue, e window.__upikAbclid.atual() mostra um valor começando com abc_. Não recarregue: é o aceite no meio da visita que exercita o seletor do botãoabclid com esse valor, e ele é filho do <form>, não de uma caixa em volta. Se estiver fora, o envio não o levaabclid. É o teste que pega um seletor largo demaisSem o botão de aceitar configurado, a tag ainda tenta entregar o identificador por cerca de três minutos após a página carregar. Quem aceita depois disso só é coberto na página seguinte. Para conferir nesse caso, aceite os cookies e recarregue.
sandbox sem allow-same-origin, o identificador não chega até ele. Nenhum dos dois casos gera erro visível.