SEO Técnico & Data Science

SEO Split Testing com Python e CausalImpact: Como Validar Mudanças Técnicas com Controle Sintético Antes do Rollout

SEO Técnico & Data Science
SEO Split Testing com Python
Cayo Galotti Especialista Google

Alterar o layout de uma página de produto, injetar dados estruturados em milhares de URLs ou reescrever a lógica de links internos costuma gerar debates tensos entre times de SEO e engenharia de produto. O motivo é simples. Uma modificação que melhora a renderização ou reduz o tempo de carregamento pode, ao mesmo tempo, degradar a interpretação semântica do Googlebot e derrubar o tráfego orgânico semanas depois.

A maioria das empresas opera no escuro. Elas realizam o deploy geral de uma alteração e comparam o tráfego dos trinta dias posteriores com os trinta dias anteriores. Se o tráfego sobe, atribuem o mérito à alteração. Se o tráfego cai, culpam atualizações de algoritmo ou flutuações de demanda. Essa abordagem ignora o conceito elementar de inferência causal.

Para validar alterações técnicas com rigor científico em sites com milhares de URLs, a metodologia padrão de grandes e-commerces e marketplaces é o SEO split testing pareado com modelos de controle sintético. Usando Python e a biblioteca CausalImpact, desenvolvida por pesquisadores do Google em 2015, isolamos o ruído externo e mensuramos o impacto real de uma mudança antes de aplicar o rollout em todo o domínio.

Por que o teste A/B tradicional de CRO falha no SEO orgânico

Em testes de taxa de conversão, ferramentas como Optimizely, VWO ou scripts no navegador dividem usuários por meio de cookies ou sessões. Metade dos visitantes recebe a versão original A e a outra metade recebe a variante B na mesma URL.

No tráfego orgânico, essa abordagem quebra por dois motivos estruturais:

Primeiro, o Googlebot não navega como um usuário comum. Ele não mantém sessões de cookies consistentes nem avalia variações de tela por amostragem de sessão. Se o servidor entregar versões diferentes de uma mesma URL com base em cabeçalhos dinâmicos ou scripts de cliente, o bot indexará apenas o que receber no momento do rastreamento. Pior, isso pode configurar cloaking nas diretrizes do Google, gerando penalidades algorítmicas ou manuais.

Segundo, o ranqueamento é atribuído à URL, não ao visitante. Não é possível testar se uma nova tag de título ou uma nova estrutura de headings melhora o posicionamento dividindo o público daquela URL. O experimento precisa dividir o conjunto de URLs do site em dois grupos: um grupo de teste, que recebe a alteração técnica, e um grupo de controle, que permanece inalterado.

A limitação do modelo antes e depois e a necessidade de controle sintético

A forma mais rudimentar de avaliação é o comparativo pré e pós intervenção. Uma equipe altera a renderização de páginas de categoria no dia 10 e analisa se os cliques aumentaram no dia 25.

Essa análise sofre com múltiplos fatores de confusão:

  1. Sazonalidade semanal: fins de semana apresentam volume de buscas diferente de dias úteis.
  2. Sazonalidade de mercado: datas comemorativas e campanhas promocionais alteram a demanda do setor.
  3. Volatilidade de algoritmo: o Google lança atualizações centrais que alteram posicionamentos na web independentemente de qualquer mudança no código do site.
  4. Movimentação da concorrência: concorrentes diretos podem ganhar ou perder links e posições no mesmo intervalo.

Se o grupo de teste crescer 8% após a mudança, mas o mercado inteiro tiver crescido 12% por conta de uma data sazonal, a mudança causou na verdade um prejuízo de 4%. O modelo antes e depois não enxerga essa diferença.

É aqui que entra o controle sintético. Em vez de confiar em uma comparação direta ou em uma média simples de um grupo de controle arbitrário, criamos uma réplica virtual do grupo de teste. Essa réplica é construída por uma combinação ponderada de séries temporais não tratadas, projetando exatamente o que teria acontecido com as páginas de teste se nenhuma intervenção técnica tivesse ocorrido.

Como o CausalImpact modela o contrafactual com séries temporais bayesianas

O CausalImpact utiliza modelos de séries temporais estruturais bayesianas, conhecidos pela sigla BSTS.

O objetivo central é estimar o contrafactual. O contrafactual é a resposta para a pergunta: quantos cliques o grupo de teste teria recebido no período pós-intervenção se não tivéssemos feito a alteração?

O modelo opera em duas etapas:

Na primeira etapa, durante o período de pré-intervenção, o algoritmo analisa a relação temporal entre o grupo de teste e múltiplas séries de controle que não sofrerão alterações. O modelo aprende como o grupo de teste se comporta em função dessas variáveis de controle, capturando tendências de longo prazo, sazonalidade semanal e choques temporários.

Na segunda etapa, no período pós-intervenção, a mudança técnica entra em produção exclusivamente no grupo de teste. O modelo continua recebendo os dados reais das variáveis de controle e usa os pesos aprendidos na primeira fase para prever o comportamento contrafactual do grupo de teste.

A diferença entre a série observada real do grupo de teste e a série contrafactual projetada representa o efeito causal da intervenção. Por ser um modelo bayesiano calculado via amostragem MCMC de Gibbs, ele não fornece apenas uma estimativa pontual, mas uma distribuição de probabilidade completa com intervalos de credibilidade de 95%.

Assim como aplicamos modelagem estatística avançada em marketing de atribuição, tema que detalhei no artigo sobre Marketing Mix Modeling com Python e Meridian, o uso de métodos bayesianos em SEO elimina impressões subjetivas e traz precisão matemática para decisões de engenharia.

Desenho experimental e divisão de páginas em grupos homogêneos

O sucesso de um split test em SEO depende da qualidade do agrupamento de páginas. Se a divisão for mal estruturada, o modelo produzirá resultados com variância excessiva ou viés sistemático.

Seleção de templates e premissa SUTVA

Para que a inferência causal seja válida, o experimento precisa respeitar a premissa de valor de tratamento de unidade estável, conhecida pela sigla SUTVA. Isso significa que a aplicação da mudança nas páginas do grupo de teste não pode afetar indiretamente o desempenho das páginas do grupo de controle.

Se você alterar os links internos das páginas de teste apontando massivamente para as páginas de controle, você viola a SUTVA. O grupo de controle receberá um influxo artificial de link equity que alterará seu ranqueamento, invalidando a linha de base.

Por isso, os melhores candidatos para SEO split testing são templates repetitivos com alto volume de URLs independentes:

  • Páginas de detalhe de produto em grandes e-commerces.
  • Páginas de categoria ou listagens de produtos.
  • Artigos editoriais em portais de notícias.
  • Páginas de perfis profissionais ou diretórios locais.

Para evitar vazamentos de link equity e entender a distribuição interna de autoridade antes de desenhar o teste, vale auditar a estrutura do site, conforme explorado na análise de PageRank interno com Python e NetworkX.

Amostragem estratificada e teste de cointegração pré-intervenção

Não divida as URLs por amostragem aleatória pura. Se páginas com cem mil cliques mensais caírem todas no grupo de teste por acaso, o desbalanceamento inicial tornará a modelagem ruidosa.

O processo recomendado envolve três passos:

  1. Estratificação por quartis de tráfego: agrupe as URLs em faixas de cliques dos últimos 90 dias.
  2. Agrupamento por profundidade de diretório e categoria: garanta que departamentos do site estejam proporcionalmente representados no teste e no controle.
  3. Teste de correlação no pré-período: colete sessenta dias de dados históricos dos dois grupos e verifique se o coeficiente de correlação de Pearson entre as séries diárias é superior a 0,90.

Deploy do split de templates na borda da CDN

Como o split testing de SEO exige que as URLs permaneçam idênticas em seus caminhos canônicos, a melhor camada para alternar a exibição de código entre grupo de teste e grupo de controle é a borda da CDN.

Trabalhar na camada de borda evita alterar a base de código do monólito da empresa e permite reversão imediata em caso de impacto negativo. Conforme discutido no guia prático de Edge SEO com Cloudflare Workers, podemos inspecionar a URL solicitada pelo Googlebot ou pelo usuário, verificar em um mapa de chave e valor se aquela URL pertence ao grupo de teste e injetar a modificação de HTML via HTMLRewriter.

Abaixo está um exemplo conceitual de lógica em Cloudflare Workers para direcionar páginas do teste para um cabeçalho ou transformação específica sem alterar o arquivo de origem:

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    
    // Verificar se a rota pertence ao grupo de teste via KV storage
    const experimentGroup = await env.SEO_EXPERIMENTS_KV.get(url.pathname);
    
    const response = await fetch(request);
    
    if (experimentGroup === 'variant_b') {
      // Injeta ou modifica elementos no HTML da variante B
      return new HTMLRewriter()
        .on('h1', {
          element(el) {
            el.setAttribute('data-test-group', 'variant_b');
          }
        })
        .transform(response);
    }
    
    return response;
  }
};

Durante o experimento, acompanhar a frequência com que os rastreadores visitam os dois grupos é fundamental. Usar técnicas de análise de logs de servidor para SEO garante que o Googlebot esteja consumindo o grupo de teste e o grupo de controle na mesma proporção, eliminando o risco de rastreamento assimétrico.

Coleta e agregação de dados via Search Console API e BigQuery

A métrica primária de um teste de SEO deve ser impressões ou cliques orgânicos diários por URL. Não utilize dados agregados de sessões do Analytics para o cálculo inicial, pois eles misturam tráfego de marcas e parâmetros de campanha.

A forma mais escalável de consolidar esses dados é conectar a API oficial do Search Console a um repositório centralizado, técnica documentada no artigo sobre Search Console API com Python e BigQuery. Com isso, superamos as limitações de mil linhas da interface nativa e exportamos o histórico diário de cada URL.

A consulta SQL típica para estruturar a tabela de modelagem agrupa os cliques diários do grupo de teste e das variáveis de controle:

SELECT
  data_consulta,
  SUM(CASE WHEN grupo = 'teste' THEN cliques ELSE 0 END) AS y,
  SUM(CASE WHEN grupo = 'controle_1' THEN cliques ELSE 0 END) AS x1,
  SUM(CASE WHEN grupo = 'controle_2' THEN cliques ELSE 0 END) AS x2,
  SUM(CASE WHEN grupo = 'controle_3' THEN cliques ELSE 0 END) AS x3
FROM
  `meu-projeto-bigquery.seo_analytics.experimento_templates`
WHERE
  data_consulta BETWEEN '2026-06-01' AND '2026-09-15'
GROUP BY
  data_consulta
ORDER BY
  data_consulta ASC;

A coluna y representa a resposta real observada no grupo tratado. As colunas x1, x2 e x3 representam variáveis de controle não tratadas, como outros clusters de categorias semelhantes que não sofreram alterações. O modelo usará essas covariáveis para montar o contrafactual sintético. Se você também exporta eventos brutos de navegação para análise de receita orgânica pós-clique, cruzar essa base com a extração de GA4 no BigQuery permite quantificar se a alteração técnica aumentou o faturamento além dos cliques.

Implementação do modelo com Python e pycausalimpact

Com a tabela extraída e salva em formato CSV ou consumida diretamente do BigQuery via pandas, podemos rodar a inferência com Python. Usaremos o pacote pycausalimpact, que implementa o algoritmo bayesiano do Google para o ecossistema científico do Python.

Preparação do DataFrame e definição das janelas temporais

O primeiro passo é garantir que o índice do DataFrame seja a coluna temporal e que a primeira coluna seja a variável dependente y do grupo de teste. As colunas subsequentes devem ser exclusivamente as covariáveis de controle.

import pandas as pd
import numpy as np
from causalimpact import CausalImpact
import matplotlib.pyplot as plt

# 1. Carregar os dados consolidados
df = pd.read_csv('dados_experimento_seo.csv')
df['data_consulta'] = pd.to_datetime(df['data_consulta'])
df = df.set_index('data_consulta')

# Ordenar cronologicamente
df = df.sort_index()

# 2. Definir os intervalos de pre e pos intervencao
# O deploy ocorreu em 01 de Agosto de 2026
pre_period = ['2026-06-01', '2026-07-31']
post_period = ['2026-08-01', '2026-09-15']

print('Inicio pre-periodo:', pre_period[0], 'Fim:', pre_period[1])
print('Inicio pos-periodo:', post_period[0], 'Fim:', post_period[1])

Execução do modelo bayesiano e diagnóstico de convergência

Agora instanciamos o modelo CausalImpact. O algoritmo ajusta um modelo de espaço de estados bayesiano sobre a série y no período de pré-intervenção usando as variáveis x como regressores dinâmicos:

# 3. Inicializar e treinar o modelo CausalImpact
ci = CausalImpact(df, pre_period, post_period)

# 4. Exibir o resumo numerico e o relatorio textual
print(ci.summary())
print(ci.summary(output='report'))

# 5. Gerar os graficos de diagnostico
ci.plot()
plt.tight_layout()
plt.savefig('grafico_causal_impact_seo.png', dpi=300)
plt.show()

O método plot gera três gráficos empilhados que contam toda a história do teste:

  1. Gráfico original: mostra a série temporal real do grupo de teste em linha sólida e a previsão contrafactual do modelo em linha tracejada, acompanhada da faixa de intervalo de credibilidade de 95%.
  2. Gráfico pontual: exibe a diferença diária entre o valor observado e o contrafactual. Se a alteração teve efeito positivo, a maioria dos pontos pós-intervenção ficará acima de zero.
  3. Gráfico cumulativo: soma o efeito diário ao longo do tempo. Uma linha ascendente constante confirma ganho sustentado de tráfego, enquanto uma linha oscilando em torno de zero indica ausência de efeito estatístico.

Interpretação dos resultados: efeito pontual, cumulativo e probabilidade posterior

O relatório textual do CausalImpact gera uma síntese que responde às dúvidas do time técnico. Vejamos a estrutura típica desse retorno:

Posterior Inference: CausalImpact
                          Average        Cumulative
Actual                    14850          683100
Prediction standard dev   13420 +/- 310  617320 +/- 14260
Credibility Interval 95%  12810 a 14030  589260 a 645380

Absolute effect           1430 +/- 310   65780 +/- 14260
Credibility Interval 95%  820 a 2040     37720 a 93840

Relative effect           10.6%          10.6%
Credibility Interval 95%  6.1% a 15.2%   6.1% a 15.2%

Posterior tail area probability p: 0.0012
Posterior prob of a causal effect: 99.88%

Os números acima revelam conclusões fundamentais:

  • O grupo de teste recebeu média de 14.850 cliques diários no período pós-intervenção.
  • O contrafactual estimou que, sem a modificação técnica, o grupo teria recebido 13.420 cliques diários.
  • O efeito absoluto foi um ganho médio de 1.430 cliques por dia, acumulando 65.780 cliques adicionais ao longo de 46 dias de teste.
  • O intervalo de credibilidade de 95% para o efeito relativo vai de 6,1% a 15,2%. Como o zero não está contido nesse intervalo, o resultado é estatisticamente consistente.
  • O valor p bayesiano de 0,0012 significa que a probabilidade de esse resultado ter ocorrido por puro ruído aleatório é de apenas 0,12%. A probabilidade posterior de existência de efeito causal real é de 99,88%.

Erros frequentes em testes de hipóteses para SEO

Mesmo com bibliotecas robustas, falhas metodológicas podem induzir conclusões erradas. Listamos as principais armadilhas observadas em auditorias técnicas:

  1. Janela de teste curta demais: o Googlebot leva dias ou semanas para rastrear, processar e reindexar milhares de páginas modificadas. Avaliar um teste com menos de 21 dias de pós-período mede apenas o atraso no rastreamento, não o impacto consolidado de busca.
  2. Contaminação por alterações simultâneas: aplicar mudanças de links no rodapé global ou alterar a taxonomia do menu principal durante o teste quebra a estabilidade do grupo de controle.
  3. Poucas covariáveis de controle: usar apenas uma série de controle sintético reduz a capacidade do modelo de isolar anomalias. Tenha entre três e dez séries não correlacionadas entre si, mas correlacionadas com o teste.
  4. Ignorar o rastreamento em nível de servidor: se a mudança técnica tornar as páginas do grupo de teste lentas e o tempo de resposta do servidor subir, o Googlebot pode reduzir a taxa de rastreamento antes mesmo de avaliar o conteúdo novo.

Framework de decisão para rollout ou rollback

Com o relatório gerado, a tomada de decisão segue um critério objetivo e replicável para qualquer alteração no site:

Cenário de SaídaProbabilidade Causal PosteriorIntervalo de Credibilidade de 95%Ação Recomendada
Vitória ClaraMaior que 95%Ambos os limites estritamente positivosRollout imediato para 100% das páginas do template
Inconclusivo NeutroEntre 20% e 95%Contém o zero dentro do intervaloManter o teste por mais duas semanas ou descartar por falta de impacto comercial
Derrota ClaraMaior que 95% negativoAmbos os limites estritamente negativosRollback imediato no código da CDN ou aplicação e arquivamento da hipótese
Impacto Nulo com Ganho de PerformanceMenor que 50%Intervalo estreito centrado em zeroRollout aprovado se a mudança reduziu custos de infraestrutura ou tempo de renderização

Esse protocolo blinda o time de SEO contra decisões baseadas em palpites. Se a engenharia propõe trocar a renderização estática por hidratação complexa no navegador, o split test com CausalImpact revelará em números inequívocos se a perda de visibilidade orgânica compensa os supostos ganhos de desenvolvimento.

Se sua operação gerencia dezenas de milhares de URLs e precisa estruturar testes estatísticos rigorosos para validar migrações, novos templates ou mudanças profundas de arquitetura técnica, conheça nossos serviços especializados de consultoria em SEO.