Filtro de Página

Instalar o Filtro de Página num domínio

Quem for aprovado vê a página real, quem for reprovado vê a isca, e os dois no mesmo endereço. Leva cerca de 30 minutos, mais o tempo do certificado.

Domínio público
O endereço que vai no anúncio, o que o visitante digita. Aponta para a nossa borda, não para a sua hospedagem. Ex.: promo.sualoja.com
Origem
Onde o site realmente está. Precisa ser um endereço diferente do público, e só a borda pode abrir. Ex.: origem.sualoja.com

A página real não é configurada em lugar nenhum — a borda busca na origem o mesmo caminho que o visitante pediu. Só a isca é um destino fixo, e é a única página que você aponta.

01

Criar o subdomínio da origem

Na sua hospedagem, crie um subdomínio origem apontando para a mesma pasta do site que já existe — não deixe criar pasta nova. Na Hostinger: Domínios → Subdomínios, marcando “Usar diretório public_html”.

Depois de criar, abra origem.seudominio.com no navegador. Tem que aparecer o seu site normalmente.

Cuidado com IPv6

Se a hospedagem criar o subdomínio como ALIAS ou CNAME, ele pode arrastar endereços IPv6 que não respondem. O sintoma engana: o site funciona, mas cada visita leva 20 segundos. Prefira um registro A apontando direto para o IP do seu plano.

02

Ajustar o WordPress

Só se o site for WordPress. Ele guarda o próprio endereço no banco e monta todos os links a partir dele — sem este ajuste a página abre pelo domínio público, mas o código-fonte entrega o endereço da origem.

No wp-config.php, logo acima da linha /* That's all, stop editing! */:

$guard_host = $_SERVER['HTTP_X_GUARD_HOST'] ?? '';
if ($guard_host && preg_match('/^[a-z0-9.-]+$/i', $guard_host)) {
    $_SERVER['HTTP_HOST'] = $guard_host;
    define('WP_HOME',    'https://' . $guard_host);
    define('WP_SITEURL', 'https://' . $guard_host);
    define('DISABLE_WP_CRON', true);
}
Este é o passo que mais custa caro

O DISABLE_WP_CRON não é opcional. Sem ele o WordPress chama a si mesmo através da borda a cada visita — a requisição sai da hospedagem, dá a volta pela nossa borda e volta, com o PHP esperando o ciclo inteiro. São 20 segundos por visita, e nada acusa erro: o site simplesmente fica lento demais para vender.

Repare que ele está dentro do if. Assim o cron só é desligado nas visitas que chegam pela borda, e as tarefas agendadas do seu site principal continuam rodando.

Se você usa Elementor ou outro construtor

Este ajuste conserta os links que o WordPress monta na hora (tema, plugins, menu). Mas o que você já inseriu pelo construtor — principalmente imagens — fica com o endereço da origem gravado no conteúdo, porque foi salvo quando você editava direto no domínio da origem. Este código não reescreve o que já está gravado.

Não precisa caçar essas URLs nem rodar "search-replace": a regra 0 do .htaccess (passo 5) deixa arquivo estático (imagem, css, js) passar sempre, então essas imagens carregam normal para o visitante — o HTML da oferta continua trancado. Se as imagens somem na aba anônima mas aparecem na logada, é sinal de que falta a regra 0 no seu lock.

03

Cadastrar o site no painel

No StegoAudio, aba Filtro de Página, crie um site novo:

CampoO que preencher
NomeSó para você identificar
Domínios públicospromo.seudominio.com
Onde o conteúdo real ficaorigem.seudominio.com
Página isca/paginaisca/ — só o caminho, com barra no começo
A barra no fim importa

O WordPress usa barra no final dos endereços. Escrevendo /paginaisca sem ela, a origem responde um redirecionamento a cada visita reprovada — e quando ele falha, o visitante recebe a página padrão em vez da sua isca.

04

Apontar o DNS

Depois de salvar, o painel mostra o bloco Domínios na borda com os registros a criar. Copie os valores daquela tela, naquele momento — eles mudam toda vez que o domínio é registrado de novo.

TipoNomeValorTTL
CNAMEpromoo endereço da borda que o painel mostra300
TXT_acme-challenge.promoum registro para cada valor que o painel listar300
Duas armadilhas, e as duas travam por horas

Crie exatamente os TXT que o painel listar — pode ser um, podem ser dois. Quando são dois, eles têm o mesmo nome e conteúdos diferentes, um para cada tipo de certificado: não é engano nem duplicata, e criando só um o certificado fica pendente para sempre, sem nenhuma mensagem de erro. O painel diz o número na frente, e numera cada registro.

O segundo pode aparecer depois do primeiro. Vale clicar em Atualizar estado quando terminar de criar, e conferir se a lista cresceu.

Use TTL 300 desde o começo. Os provedores sugerem 14400, que são 4 horas — e se você precisar corrigir um valor depois, o antigo fica preso nesse tempo em servidores do mundo inteiro. É o erro que mais custa tempo nesta instalação.

Se o nome promo já tiver registros A ou AAAA, apague antes: um CNAME não pode conviver com eles. Se o subdomínio existir na hospedagem, remova lá também, senão ela recria os registros.

O painel passa a mostrar ATIVO em poucos minutos. O certificado sai em seguida.

05

Trancar as páginas de oferta

Este passo é o que faz o filtro valer alguma coisa. Sem ele, qualquer um digita o endereço e vê a página real — e nada do resto importa.

Pegue o segredo do site no painel (botão de copiar, no cadastro) e coloque no .htaccess da pasta do site, antes da linha # BEGIN WordPress:

Primeiro: qual servidor a sua origem usa?

Esta página tem três blocos e eles não são intercambiáveis. Os dois primeiros vão num arquivo .htaccess e só funcionam em Apache/LiteSpeed. O terceiro vai na configuração do nginx e não funciona dentro de um .htaccess — colado lá ele não faz absolutamente nada, sem nenhuma mensagem de erro, e a oferta fica aberta.

Rode isto e veja o que aparece depois de server:

curl -sI https://origem.SEUDOMINIO.com/ | grep -i server

LiteSpeed, Apache ou hcdn → use um dos dois primeiros blocos (.htaccess). nginx → use o terceiro (configuração do nginx).

Apache/LiteSpeed: WordPress ou HTML puro?

O bloco abaixo é para origem em WordPress — ele traz as exceções de wp-login/wp-admin e do cookie de login. Sem elas você tranca a si mesmo pra fora do painel (403 no editor). Se sua origem é HTML puro (estático), sem WordPress, pule para o bloco "Se a origem é HTML puro" mais abaixo: a mesma trava, mas sem essas exceções (num site estático elas não existem). Usar a versão errada é o erro mais comum aqui.

RewriteEngine On

# 0. Arquivos estáticos passam sempre (imagem/css/js/fonte não são o segredo;
#    travá-los quebra as imagens da página pro visitante anônimo).
RewriteRule \.(jpe?g|png|gif|webp|avif|svg|ico|css|js|mjs|woff2?|ttf|otf|eot|mp4|webm|map)$ - [L]

# 1. Fora estáticos, só a borda (com o segredo) ou o admin logado passam —
#    em QUALQUER endereço (raiz, www, origem, apex).
RewriteCond %{REQUEST_URI} !^/(wp-login\.php|wp-admin) [NC]
RewriteCond %{HTTP_COOKIE} !wordpress_logged_in [NC]
RewriteCond %{HTTP:x-guard-auth} !^SEU_SEGREDO_AQUI$
RewriteRule ^ - [F,L]

# 2. Documento NUNCA cacheia (a CDN guardaria a resposta autorizada e serviria
#    a quem nao traz o segredo); estatico cacheia forte (senao vira 429).
<IfModule mod_headers.c>
  SetEnvIf Request_URI "\.(jpe?g|png|gif|webp|avif|svg|ico|css|js|mjs|woff2?|ttf|otf|eot|mp4|webm|map)$" ESTATICO=1
  Header always set Cache-Control "private, no-store" env=!ESTATICO
  Header always set Cache-Control "public, max-age=31536000, immutable" env=ESTATICO
</IfModule>

Há um lugar para trocar: o SEU_SEGREDO_AQUI pelo segredo do painel. Nenhum endereço para digitar, nenhuma lista de páginas para manter.

Por que a regra 1 tranca TUDO, e não só a oferta

Repare que ela não tem condição de endereço nem lista de páginas. É de propósito.

Se você trancasse só os nomes das páginas de oferta, teria que lembrar de acrescentar cada oferta nova na regra — e toda página esquecida nasce aberta, com o sitemap do WordPress entregando o nome de graça. Trancando tudo, a oferta some de todos os endereços (raiz, www, origem, apex, e qualquer página futura), sem manutenção. Só a borda, com o segredo, entra.

Por que existem as exceções (cookie e wp-admin)

A regra 1 tranca tudo. Sem as três exceções, você bloqueia a si mesmo: !wordpress_logged_indeixa passar quem já entrou (o editor carrega a página numa pré-visualização que não passa pela borda, e o Elementor travaria em "carregando"); !^/(wp-login|wp-admin) deixa a tela de login e o painel abrirem — sem ela você toma 403 antes mesmo de logar, já que aí ainda não existe cookie. Nenhuma abre brecha na oferta: o cookie só nasce depois do login com senha, e o wp-admin não é página de venda. E a regra 0 deixa as imagens passarem — sem ela, elas somem na aba anônima.

O teste bate na raiz da origem

O Testar antes de subir abre origem.seudominio.com/ (a raiz) sem o cabeçalho e espera 403. Como a regra 1 tranca tudo em qualquer endereço, a raiz já responde 403 e o teste passa — sem nada de especial a configurar.

Página nova já nasce protegida

Como a regra tranca tudo, qualquer oferta ou página de teste que você criar depois já entra trancada — sem precisar voltar aqui para acrescentar nome nenhum. Uma preocupação a menos.

O Cache-Control (regra 2) resolve a última parte: sem ele, um CDN no caminho pode guardar a resposta já aprovada e servir para todo mundo. O vazamento aconteceria antes da borda, então ela não teria como impedir.

Se a origem é HTML puro (estático), sem WordPress — .htaccess

Site estático na hospedagem, atrás da Cloudflare, sem WordPress? Use esta versão. Ela não tem as linhas de WordPress (não existe wp-admin nem cookie de login). A regra 2 continua — mas aqui ela precisa separar documento de estático (o motivo está no aviso abaixo). Troque só o SEU_SEGREDO_AQUI pelo segredo do painel:

RewriteEngine On

# 0. Estáticos passam a trava (não são o segredo)
RewriteRule \.(jpe?g|png|gif|webp|avif|svg|ico|css|js|mjs|woff2?|ttf|otf|eot|mp4|webm|map)$ - [L]

# 1. Trava: só a borda (com o segredo) entra; o resto leva 403
RewriteCond %{HTTP:x-guard-auth} !^SEU_SEGREDO_AQUI$
RewriteRule ^ - [F,L]

# 2. Cache: documento NUNCA, estático SEMPRE.
<IfModule mod_headers.c>
  SetEnvIf Request_URI "\.(jpe?g|png|gif|webp|avif|svg|ico|css|js|mjs|woff2?|ttf|otf|eot|mp4|webm|map)$" ESTATICO=1
  Header always set Cache-Control "private, no-store" env=!ESTATICO
  Header always set Cache-Control "public, max-age=31536000, immutable" env=ESTATICO
</IfModule>
Por que a regra 2 separa documento de estático

Documento (HTML) sempre no-store: sem isso, a CDN da própria hospedagem guarda a resposta já autorizada (a que saiu com o x-guard-auth aprovado) e passa a servi-la a quem não trouxe o segredo — vazamento que acontece atrás da borda, onde ela não alcança. Já aconteceu em produção.

Estático (css/js/imagem) cacheia forte: um modelo antigo punha no-store em tudo — aí a CDN busca cada asset de novo a cada acesso, saindo dos poucos IPs da borda, e sob carga a hospedagem corta com 429 (a página abre só com a cor de fundo, sem imagem nem estilo). Separar as duas coisas resolve os dois problemas de uma vez.

Se a origem roda nginx — não é .htaccess

nginx NÃO lê .htaccess

Os dois blocos acima são de Apache/LiteSpeed. Em nginx um .htaccess é um arquivo de texto que ninguém abre — a trava não existe e a oferta fica aberta, sem nenhuma mensagem de erro avisando. Para saber qual é o seu:

curl -sI https://origem.SEUDOMINIO.com/ | grep -i server

Peça isto a quem administra o servidor. Vai no bloco server do site (normalmente /etc/nginx/sites-available/SEUDOMINIO), e é a mesma coisa dos outros dois: trava, cache separado, e o 404 de verdade. Troque só o SEU_SEGREDO_AQUI:

# 0. Estaticos passam a trava (nao sao o segredo) e cacheiam forte
location ~* .(jpe?g|png|gif|webp|avif|svg|ico|css|js|mjs|woff2?|ttf|otf|eot|mp4|webm|map)$ {
    add_header Cache-Control "public, max-age=31536000, immutable" always;
    try_files $uri =404;
}

# 1. Trava: so a borda (com o segredo) entra; o resto leva 403.
# 2. Documento NUNCA cacheia.
# 3. Endereco que nao existe responde 404 — e o "=404" no fim que faz isso.
location / {
    if ($http_x_guard_auth != "SEU_SEGREDO_AQUI") { return 403; }
    add_header Cache-Control "private, no-store" always;
    try_files $uri $uri/ =404;
}
O erro que mais aparece: o final da linha try_files

Se a linha terminar em /index.html em vez de =404, o servidor responde 200 para qualquer endereço, inclusive os que não existem — e passa a devolver a página inicial no lugar do erro. Nenhum site de verdade faz isso, e é sinal que sistema automático de análise procura.

Medido em 25/09/2026: 11 de 33 origens tinham exatamente esse problema. Pediam /banana-voadora/ e recebiam a página inicial com 200.

Mesmo efeito, mesma correção: error_page 404 =200 /index.html; e rewrite ^ /index.html last;. Remova a linha.

WordPress em nginx

O WordPress precisa do encaminhamento para o index.php, e isso está certo — ele responde 404 sozinho quando o conteúdo não existe. Troque só a última linha do bloco location / por try_files $uri $uri/ /index.php?$args; e adicione as exceções de wp-admin/wp-login, como no primeiro bloco desta página —sem elas você tranca a si mesmo pra fora do painel.

Depois de editar, sempre

nginx -t && systemctl reload nginx — o nginx -t confere a sintaxe antes de aplicar. Se ele reclamar, não recarregue: o site sai do ar. E confirme no fim: curl -o /dev/null -s -w "%{http_code}" https://SEUDOMINIO/banana-voadora-123/ tem que responder 404.

Com Cloudflare na frente? O mesmo .htaccess

Se o domínio está na Cloudflare (o promo aponta pra borda por CNAME), a trava não muda. A origem fica em nuvem cinza (Somente DNS) — a Cloudflare nem passa por ela: quem serve é a hospedagem, e é ela que lê o .htaccess. A borda busca a origem direto, com o segredo. Só seria diferente se você deixasse a origem em nuvem laranja e trancasse por regra de firewall da Cloudflare no lugar do .htaccess.

06

Conferir e testar

No painel do site, clique em Conferir instalação. Ele roda oito checagens — todas de coisas que, quando estão erradas, não geram mensagem de erro nenhuma:

  • 01A origem recusa quem vem de fora — sem isso o filtro é decorativo
  • 02A origem responde para a borda — o segredo está certo dos dois lados
  • 03O documento não pode ser guardado em cache público — o vazamento por CDN
  • 04O domínio público passa pela borda — um raspador recebe coisa diferente
  • 05A validação de certificado passa livre — a renovação não vai quebrar
  • 06A borda não atrasa a página — compara com a origem sozinha
  • 07A página isca abre direto — sem redirecionamento no caminho
  • 08Imagem, CSS e JS podem ser guardados em cache — se estiverem como no-store, sua hospedagem é rebuscada a cada visita e começa a cortar com 429: a página abre só com a cor de fundo

O teste de dez segundos

Com a regra “só quem vem de anúncio” ligada, abra os dois endereços no seu próprio navegador:

https://promo.seudominio.com/paginareal/?gclid=teste   →  página real
https://promo.seudominio.com/paginareal/               →  página isca

Mesmo endereço, e a barra continua mostrando /paginareal/ nos dois casos. É proxy, não redirecionamento — quem foi reprovado não tem como perceber que foi filtrado, e o robô de revisão não vê o destino do anúncio mandando para outro lugar.

07

Fazer a conversão do Google Ads marcar

Este passo não tem nada a ver com o filtro, mas é onde a campanha silenciosamente deixa de dar retorno: a venda acontece e o Google nunca fica sabendo de qual anúncio ela veio. Sem isso, o Google Ads não tem como otimizar, e você fica olhando uma coluna de conversões zerada com vendas entrando.

Por que quebra

O clique no anúncio chega na sua página com um identificador, o gclid. O Google guarda esse clique num cookie do domínio da sua página. Quando o comprador clica em comprar e vai para o checkout, ele está em outro domínio — que não enxerga esse cookie. Se o gclid não for junto na URL, o checkout não tem como saber de qual anúncio a venda veio, e a conversão fica órfã.

anúncio  →  promo.seudominio.com/oferta/?k=SUACHAVE&gclid=ABC123
                    (o Google guarda o clique aqui)

comprar  →  checkout.plataforma.com/xyz
                    (sem gclid: o checkout está cego)

A correção

Um script que copia os parâmetros da URL para todos os links de saída da página. Cole no <head> da página de oferta:

<script>!function(){document.addEventListener("DOMContentLoaded",function(){
  var q = new URLSearchParams(window.location.search);
  var pular = ["k", "_verificar"];
  document.querySelectorAll("a").forEach(function(a){
    try {
      var u = new URL(a.href);
      q.forEach(function(v,k){
        if (pular.indexOf(k) < 0 && !u.searchParams.has(k)) u.searchParams.set(k, v);
      });
      a.href = u.toString();
    } catch(e) {}
  });
});}()</script>
A lista pular é obrigatória aqui, e não é no resto da internet

Todo tutorial de repasse de parâmetro copia tudo. Numa página comum isso é inofensivo. Na sua não é: sem a lista, o script mandaria a chave de URL junto para o domínio do checkout — ela apareceria na URL dele, no referrer e no painel da plataforma.

A chave é o que separa quem vê a oferta de quem vê a isca. Ela só pode existir no link do anúncio. Se o seu parâmetro tiver outro nome, troque "k" pelo nome que você configurou no painel.

Repassar não basta sozinho

O gclid chegar no checkout só resolve se o checkout souber o que fazer com ele: a plataforma precisa ter a tag de conversão do Google Ads na página de obrigado, ou enviar a conversão pela API dela. Se não tiver nada configurado lá, o parâmetro chega e morre. Confira isso no painel da plataforma de pagamento.

Duas contas de Google Ads na mesma página

É comum sobrar tag antiga de outra conta na página. Se a campanha roda numa conta e a ação de conversão foi criada na outra, não marca nem com o gclid chegando certinho. Confira no HTML quantos AW- diferentes existem, e se o do anúncio é o mesmo da conversão.

O filtro não atrapalha isso

A borda entrega a página com a URL inteira intacta, gclid incluído — é proxy, não redirecionamento, então a barra de endereço nunca perde parâmetro. Se a conversão não marca, o problema está no caminho da página para o checkout, não no filtro.

+

Opcional: presell nos anúncios

Presell é a página branca de transição entre o anúncio e a oferta: anúncio → presell → oferta. É ela que o moderador vê quando inspeciona o anúncio, então mantenha-a "white" — sem o conteúdo da oferta nela.

A chave não vai no anúncio: o anúncio aponta para a presell, sem chave. A chave vai no botão da presell que leva à oferta:

https://promo.seudominio.com/paginareal/?k=SUA_CHAVE

Só que aí o gclid/fbclid do anúncio fica na presell e some no salto para a oferta — e a trava “só quem vem de anúncio”reprovaria o comprador real. Este script na presell repassa esses parâmetros para o botão (troque o domínio pelo seu de oferta):

<script>
(function () {
  var qs = new URLSearchParams(location.search)
  if (![...qs].length) return
  document.querySelectorAll('a[href]').forEach(function (a) {
    try {
      var u = new URL(a.href, location.href)
      if (u.hostname !== 'promo.seudominio.com') return  // seu domínio de oferta
      qs.forEach(function (v, k) { if (!u.searchParams.has(k)) u.searchParams.set(k, v) })
      a.href = u.toString()
    } catch (e) {}
  })
})()
</script>
A chave não é segredo blindado — não confie só nela

Quem acha sua presell num spy lê a chave no código do botão, e o gclid é só um parâmetro (dá para forjar colando ?k=chave&gclid=qualquercoisa). Então essas duas travas filtram origem de tráfego, não seguram um humano determinado. Quem realmente barra o moderador e o concorrente é o que ele não controla: as travas de país, proxy/VPN e robô/datacenter. Mantenha essas ligadas — são elas o muro. A presell ainda soma uma camada (o revisor vê a branca).

Onde as instalações travam

Todos os itens abaixo aconteceram numa instalação real. O que eles têm em comum é não produzirem erro visível — o site funciona, e o problema aparece como outra coisa.

O certificado fica “pendente” para sempre
Quase sempre falta um TXT que o painel está pedindo, ou o valor foi copiado de uma tentativa anterior. Abra o painel agora e confira registro por registro contra o que está no seu DNS — inclusive o número deles, porque um segundo TXT pode ter aparecido depois de você criar o primeiro. Se estiver tudo certo e ainda assim passar de uma hora, o valor antigo pode estar preso em cache de DNS — nesse caso, um subdomínio novo, que nunca foi consultado, resolve na hora.
Cada visita leva quase 20 segundos
É o wp-cron do WordPress chamando o próprio site pela borda. Passo 2, DISABLE_WP_CRON. A sexta checagem do verificador acusa isso.
A isca não aparece — o reprovado vê uma página de indisponível
O caminho está respondendo redirecionamento, quase sempre por falta da barra no fim. Troque /paginaisca por /paginaisca/.
O site principal saiu do ar depois de mexer no DNS
Confira se o registro do domínio raiz (nome @) ainda existe. Ele é fácil de apagar sem querer no meio das mudanças, e o sintoma é específico: o endereço com www continua funcionando e o sem www não.
Tirando o “promo.” da frente, a oferta abre
A regra do .htaccess está trancando só a origem. Falta a regra 1 do passo 5, a que não tem condição de endereço — é ela que faz a oferta sumir do domínio raiz, do www e de qualquer subdomínio.
O editor do WordPress trava em “carregando”
A regra está bloqueando você também. Falta a linha do wordpress_logged_in: o editor carrega a página numa pré-visualização que não passa pela borda, e sem a exceção ela leva 403 como qualquer visitante.
As imagens somem na aba anônima, mas aparecem na aba logada
Clássico, e não é a borda: o WordPress serve as imagens pelo domínio próprio, e o origin-lock trancou tudo — quem está logado passa pelo cookie, o visitante anônimo toma 403 e a imagem quebra. É por isso que a regra 0 existe (deixa arquivo estático passar). Se você trancou antes dela existir, é só acrescentar a linha RewriteRule \.(jpe?g|png|...)$ - [L] logo depois de RewriteEngine On. O HTML da oferta continua trancado — só os arquivos passam.
Tomei 403 no /wp-admin depois de trancar a origem
A regra 1 tranca a origem inteira e você entra no painel por ela. Faltam as duas linhas de exceção: !^/(wp-login\.php|wp-admin) (senão a tela de login nem abre — antes de logar não há cookie) e !wordpress_logged_in (para seguir logado). Elas já estão no bloco do passo 5 acima.
Uma página de teste antiga está entregando o vídeo
Páginas que não estão na regra ficam públicas, com o endereço do vídeo no código-fonte. Apague as de teste, ou acrescente o nome delas na regra.
O painel diz “precisa de conserto”
Isso não é erro do sistema — é o verificador funcionando. Cada item aponta o que falta e como resolver.