Como construir um sistema de rastreamento de atribuição de campanha


As equipes de marketing realizam campanhas em uma dúzia de canais e querem saber quais deles realmente geraram uma venda. Essa pergunta parece simples e acaba sendo um verdadeiro problema de engenharia: capturar a origem de um visitante, manter essas informações vivas em uma sessão de várias páginas e anexá-las corretamente a uma conversão que pode acontecer dias depois. Este é um passo a passo prático para construir esse sistema do zero.

Capturando parâmetros UTM no pouso

Cada plataforma de anúncios anexa parâmetros UTM aos seus links, utm_source, utm_medium, utm_campaigne alguns extras opcionais. A primeira tarefa é lê-los no URL no momento em que um visitante chega.

javascript

function captureUtmParams() {
  const params = new URLSearchParams(window.location.search);
  const utmKeys = ('utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content');
  const captured = {};

  utmKeys.forEach((key) => {
    const value = params.get(key);
    if (value) captured(key) = value;
  });

  return Object.keys(captured).length > 0 ? captured : null;
}

Isso só importa se for executado em todas as páginas de destino, não apenas em uma página inicial designada, já que um anúncio pago pode apontar para qualquer URL do site, dependendo da campanha.

Decidindo onde armazená-lo

Os parâmetros precisam sobreviver à navegação para outras páginas e, idealmente, sobreviver à saída e retorno do visitante antes da conversão. Isso exclui uma variável JavaScript na memória e levanta uma escolha real entre um cookie e localStorage.

Resumo do SitePoint de Bibliotecas JavaScript para trabalhar com armazenamento local cobre as compensações entre os dois com mais profundidade, mas a versão resumida para este caso de uso: um cookie pode ser lido no lado do servidor em cada solicitação sem JavaScript extra, o que é importante se a atribuição precisar estar disponível no momento em que uma solicitação de back-end chega, enquanto localStorage funciona apenas no lado do cliente, mas não é enviado com todas as solicitações, mantendo o tamanho da carga baixo. Muitas configurações de atribuição usam um cookie para o identificador de nível de sessão e localStorage para os dados de campanha mais ricos.

javascript

function storeAttribution(utmData) {
  const payload = {
    ...utmData,
    landing_page: window.location.pathname,
    timestamp: Date.now(),
  };

  
  if (!localStorage.getItem('first_touch_attribution')) {
    localStorage.setItem('first_touch_attribution', JSON.stringify(payload));
  }

  
  localStorage.setItem('last_touch_attribution', JSON.stringify(payload));
}

Armazenar os dados do primeiro e do último toque desde o início evita um erro comum: escolher um modelo de atribuição antecipadamente e descobrir meses depois que o outro teria respondido a uma pergunta que realmente interessa à equipe de marketing. Guia do SitePoint para Manipulação de cookies jQuery é uma referência útil se a atribuição também precisar ser legível no servidor por meio de um cookie, uma vez que a expiração e o comportamento no mesmo site que ela cobre afetam diretamente o tempo de sobrevivência dos dados de atribuição.

Definindo uma janela de expiração razoável

Os dados de atribuição que nunca expiram eventualmente atribuem uma conversão a uma visita de um ano atrás, o que raramente é útil. Uma janela contínua de 30 dias é um padrão comum, longa o suficiente para cobrir a maioria dos ciclos de consideração e curta o suficiente para que dados obsoletos não dominem.

javascript

function isAttributionExpired(payload, maxAgeDays = 30) {
  const ageMs = Date.now() - payload.timestamp;
  return ageMs > maxAgeDays * 24 * 60 * 60 * 1000;
}

function getValidAttribution(key) {
  const stored = localStorage.getItem(key);
  if (!stored) return null;

  const payload = JSON.parse(stored);
  if (isAttributionExpired(payload)) {
    localStorage.removeItem(key);
    return null;
  }
  return payload;
}

Verificar a expiração no momento da leitura, em vez de tentar limpar proativamente o armazenamento, mantém isso simples: uma entrada expirada é tratada como se nunca tivesse existido, sem a necessidade de um processo de limpeza separado.

Anexando atribuição a uma conversão

Os dados de atribuição só são úteis quando estão vinculados a um evento de conversão real, uma compra, uma inscrição, um envio de formulário. Esse é um endpoint de back-end que aceita a atribuição armazenada juntamente com os detalhes da conversão.

píton

from flask import Flask, request, jsonify
from datetime import datetime, timezone

app = Flask(__name__)

@app.route('/api/conversions', methods=('POST'))
def record_conversion():
    data = request.json
    conversion = {
        'conversion_id': data.get('conversion_id'),
        'value': data.get('value', 0),
        'first_touch': data.get('first_touch_attribution'),
        'last_touch': data.get('last_touch_attribution'),
        'recorded_at': datetime.now(timezone.utc).isoformat(),
    }

    if not conversion('first_touch') and not conversion('last_touch'):
        conversion('attribution_status') = 'unattributed'
    else:
        conversion('attribution_status') = 'attributed'

    save_conversion(conversion)
    return jsonify({'status': 'recorded'}), 201

Marcar explicitamente uma conversão como unattributed em vez de abandoná-lo silenciosamente, é importante para a precisão do relatório posteriormente. Um visitante que limpou seus cookies, usou uma janela de navegação privada ou converteu em um dispositivo diferente não terá dados de atribuição, e essa é uma lacuna real e mensurável que vale a pena revelar em vez de ocultar.

Calculando o retorno do investimento em publicidade

Depois que as conversões chegam com atribuição anexada, conectá-las aos gastos da campanha produz o número que as equipes de marketing realmente desejam.

píton

def calculate_campaign_roas(campaign_name, spend, conversions):
    campaign_conversions = (
        c for c in conversions
        if c.get('last_touch', {}).get('utm_campaign') == campaign_name
    )
    total_value = sum(c('value') for c in campaign_conversions)

    if spend == 0:
        return None  

    return {
        'campaign': campaign_name,
        'spend': spend,
        'conversions': len(campaign_conversions),
        'revenue': total_value,
        'roas': round(total_value / spend, 2),
    }

A proteção contra a divisão por zero aqui não é uma formalidade de programação defensiva, campanhas com zero gasto registrado são um estado de entrada de dados genuinamente comum (uma nova campanha ainda não sincronizada com os dados de faturamento da plataforma de anúncios), e uma implementação ingênua lançará exatamente o registro que alguém provavelmente verificará primeiro.

Onde o lado comprador se encaixa

Tudo acima está relacionado à medição do ciclo de vida da campanha: capturar, armazenar e atribuir tráfego depois que um anúncio já foi colocado. As decisões sobre para onde esses gastos realmente vão, quais plataformas, quais públicos, como os orçamentos mudam entre as campanhas, são uma disciplina separada geralmente chamada de compra de mídia, administrada internamente ou por uma agência como a Cresça-me. Um sistema de rastreamento como o acima é o que torna o trabalho de compra mensurável após o fato, mas não substitui as decisões estratégicas que determinam o que é comprado em primeiro lugar.

Perguntas frequentes

Devo usar a atribuição de primeiro ou último toque?

Ambos, se o armazenamento permitir. O primeiro toque mostra o que inicialmente trouxe um visitante para o seu funil; o último toque mostra o que finalmente os convenceu a converter. Armazenar ambos desde o início evita ter que reconstruir o histórico mais tarde, quando alguém solicitar o modelo que você não implementou.

Por que usar cookies e localStorage para dados de atribuição?

Um cookie está disponível no servidor em cada solicitação sem JavaScript extra, útil quando a atribuição precisa ser lida no momento em que uma solicitação de back-end chega. localStorage mantém dados mais ricos do lado do cliente sem aumentar a carga útil de cada solicitação. Usar ambos abrange mais cenários do que qualquer um deles sozinho.

Por quanto tempo os dados de atribuição devem ser mantidos antes de expirarem?

Um padrão comum é uma janela contínua de 30 dias, longa o suficiente para cobrir períodos de consideração típicos, sem permitir que visitas muito antigas dominem os relatórios atuais. A janela certa varia de acordo com a duração real do seu ciclo de vendas específico.

O que acontece com as conversões sem dados de atribuição?

Eles devem ser registrados e marcados explicitamente como não atribuídos, em vez de descartados. Um visitante que limpou cookies, usou navegação privada ou converteu em um dispositivo diferente produz uma lacuna real na cobertura da atribuição, e ocultar essa lacuna faz com que o relatório pareça mais completo do que realmente é.

Resumo

Um sistema de atribuição de campanha se resume a três etapas deliberadas: capturar dados UTM de forma confiável em cada página de destino, armazená-los de uma forma que sobreviva ao comportamento real de navegação do visitante com uma expiração sensata e anexá-los honestamente às conversões, incluindo aquelas em que a atribuição está realmente faltando. Nenhuma dessas etapas é complicada isoladamente, mas ignorar a lógica de expiração, escolher apenas um modelo de atribuição ou descartar silenciosamente as conversões não atribuídas produzem relatórios que parecem limpos, embora estejam silenciosamente errados.



Source link