Erro no seletor de datas do Google Search Console: como exportar via API

Erro no seletor de datas do Google Search Console: como exportar via API

Última verificação: 16 de outubro de 2026
25 min de leitura
Guia
SEO técnico

#Porque é que o seletor de datas do Google Search Console mostra o ano de 1969

A falha no seletor de datas do relatório de desempenho do Google Search Console mostra a fragilidade de depender apenas da interface web. A 13 de outubro de 2026, Barry Schwartz descreveu no Search Engine Roundtable que, ao definir um intervalo de datas personalizado, o relatório rejeita o formulário com a mensagem Date can't be after 1969-12-31, ou seja: a data não pode ser posterior a 31 de dezembro de 1969. O seletor foi corrigido, voltou a falhar a 14 de outubro e, algumas horas depois, estava de novo a funcionar. Enquanto a falha dura, os analistas perdem a possibilidade de filtrar dados históricos no navegador.

A Google não indicou a causa, mas a própria data diz muito. Na norma POSIX, o tempo Unix é o número de segundos decorridos desde a meia-noite de 1 de janeiro de 1970 UTC. Se um campo de data em JavaScript recebe um valor nulo, uma cadeia vazia ou um objeto ainda não preparado, acaba facilmente no valor 0. Em fusos horários com desvio negativo face ao UTC, esse ponto zero cai a 31 de dezembro de 1969, nos fusos norte-americanos entre as 16:00 e as 19:00. Por isso, a explicação mais provável é um carimbo de data/hora igual a zero que chegou ao validador como limite superior do intervalo.

Partindo deste pressuposto, o validador compara a data escolhida com um limite fixado em 1969. Qualquer data real é posterior, pelo que a regra considera o intervalo inválido e bloqueia o gráfico.

Para sites de grande escala operacional, lojas de comércio eletrónico e agências que gerem dezenas de portais, uma falha destas paralisa o diagnóstico diário. O trabalho das equipas de SEO não pode depender da estabilidade de uma única aplicação de página única (SPA). A solução que garante continuidade analítica total é a integração direta com a Google Search Console API oficial.

                  Arquitetura de acesso aos dados do Search Console
                  
    [Interface Web GSC]               [Search Analytics API v1]
             │                                    │
    Erros de UI, limite de 1000 linhas   Endpoint REST estável
    Problema Unix Epoch (1969)           25 000 linhas por pedido
    Sem exportação automática            50 000 linhas por dia
             │                                    │
             ▼                                    ▼
       [Navegador Web]                   [BD Local / BigQuery]

#Quais são os limites da interface do Google Search Console em comparação com a API

A interface gráfica do Google Search Console foi concebida para uma consulta rápida dos indicadores básicos e não para engenharia de dados avançada. Mesmo quando o seletor de datas funciona corretamente, o painel web impõe restrições que distorcem a imagem da visibilidade do domínio.

A primeira restrição é o limite rígido de apresentação. A tabela do painel do Search Console mostra no máximo 1000 linhas. Em portais com centenas de páginas e dezenas de milhares de consultas de cauda longa (long-tail keywords), o utilizador vê apenas uma parte das expressões que trazem tráfego.

O segundo problema é a retenção de dados. O Google Search Console elimina os registos com mais de 16 meses. Se o portal não tiver um mecanismo automático de arquivo, as comparações homólogas ao longo de vários anos tornam-se impossíveis. O terceiro fator é a anonimização de consultas raras (anonymized queries): a Google filtra-as por motivos de privacidade no painel, na API e na exportação para o BigQuery. Em contrapartida, a API não tem o limite de 1000 linhas da tabela, e os pedidos feitos separadamente para cada dia devolvem até 50 000 linhas por dia e por tipo de pesquisa (documentação da Google).

CaracterísticaInterface web GSCSearch Analytics API
Limite de linhas por pedido1 000 linhas25 000 linhas
Número máximo de linhas1 000 (limite rígido da tabela)50 000 por dia e por tipo de pesquisa (paginação com startRow)
Período de retenção16 meses16 meses, mais tempo depois de guardados na sua própria base de dados
Vulnerabilidade a erros de frontendElevada (erros de UI, bloqueios JS)Sem camada de UI (resposta JSON de um endpoint REST)
Automação de relatóriosExige cliques manuaisAutomação total (cron, workers, CI)
Análise multidimensionalFiltros cruzados limitadosCombinação total: page + query + device + country

A utilização da API torna os relatórios independentes dos erros de frontend da Google e dá aos programadores controlo sobre o arquivo de dados.

#Como configurar uma service account para a Google Search Console API

Para aceder à Search Analytics API sem ter de iniciar sessão no navegador a cada vez com o protocolo OAuth2 para utilizadores finais, é necessário configurar uma conta de serviço (Service Account) na Google Cloud Platform. A conta de serviço funciona como uma entidade técnica autónoma com o seu próprio par de chaves criptográficas.

O primeiro passo é criar um projeto na consola da Google Cloud (console.cloud.google.com). Depois de criado o projeto, acede-se à secção APIs & Services, pesquisa-se Google Search Console API e clica-se no botão que ativa o serviço.

O segundo passo é gerar a conta de serviço na secção IAM & Admin, na subsecção Service Accounts. Atribui-se à conta um nome único, por exemplo gsc-analytics-extractor. Depois de criada a conta, abre-se o separador Keys e cria-se uma nova chave privada em formato JSON. O ficheiro é descarregado para o disco local e contém o identificador da chave, o endereço de email da conta de serviço e a chave privada RSA em formato PEM.

{
  "type": "service_account",
  "project_id": "analytics-core-pipeline",
  "private_key_id": "8a9b0c1d2e3f4a5b",
  "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDE...\n-----END PRIVATE KEY-----\n",
  "client_email": "gsc-analytics-extractor@analytics-core-pipeline.iam.gserviceaccount.com",
  "client_id": "103847562910384756291",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token"
}

O terceiro passo é autorizar a conta de serviço no painel do Google Search Console. Copia-se o endereço client_email e abre-se o Search Console da propriedade verificada. Acede-se a Definições (Settings), escolhe-se Utilizadores e autorizações (Users and permissions) e adiciona-se o novo endereço de email com a função Restrito (Restricted) ou Total (Full). A partir deste momento, a conta de serviço pode consultar os endpoints do Search Console para essa propriedade.

O ficheiro JSON com a chave privada nunca pode chegar a um repositório de código público. Deve ser adicionado ao .gitignore ou o seu conteúdo deve ser passado como variável de ambiente encriptada no servidor de produção.

#Como verificar a que propriedades do Search Console a conta de serviço tem acesso

A causa mais frequente de um erro 403 depois de configurar a conta de serviço é uma discrepância entre o endereço da propriedade no script e aquele que o Search Console conhece. Em vez de adivinhar, vale a pena perguntar à API. O método sites.list devolve a lista de propriedades a que a conta tem acesso, e cada entrada contém dois campos: siteUrl, escrito exatamente como os restantes métodos o esperam, e permissionLevel (documentação do recurso sites).

O campo permissionLevel assume um de quatro valores: siteOwner (proprietário), siteFullUser (permissões totais), siteRestrictedUser (permissões restritas) e siteUnverifiedUser (utilizador sem propriedade verificada). Se a propriedade não aparecer na lista, o email da conta de serviço não foi adicionado nas definições do Search Console ou foi adicionado a outra propriedade, por exemplo ao prefixo https://www. em vez da propriedade de domínio.

const { data } = await searchconsole.sites.list();
for (const site of data.siteEntry || []) {
  console.log(site.siteUrl, site.permissionLevel);
}
// sc-domain:wppoland.com siteFullUser

O mesmo recurso tem os métodos add, delete e get. Para obter dados basta o âmbito webmasters.readonly e um list executado uma vez no arranque do script: se o siteUrl devolvido for diferente do configurado, o script pode terminar com uma mensagem clara antes de disparar centenas de pedidos com erro.

#Como obter dados de sc-domain e de prefixo de URL em Node.js

Ao trabalhar com a Search Console API, os programadores deparam-se muitas vezes com um erro 403 ou 404 causado por um formato incorreto do identificador do site (siteUrl). A Google suporta dois tipos de propriedade distintos:

  1. Propriedade de domínio (Domain Property): agrega todos os protocolos e subdomínios. Na API, o identificador tem de ter o prefixo sc-domain:, por exemplo sc-domain:wppoland.com.
  2. Propriedade de prefixo de URL (URL-prefix Property): diz respeito a um protocolo e a um caminho concretos. Na API, o identificador é o URL completo com barra final, por exemplo https://wppoland.com/pt-pt/.

Em sites multilingues, a boa prática é consultar as propriedades de prefixo de cada versão linguística ou a propriedade de domínio e filtrar depois os caminhos de URL no código.

O script em Node.js abaixo mostra uma implementação completa da extração de dados analíticos com paginação e gravação num ficheiro JSON. Utiliza a biblioteca oficial googleapis.

import fs from "node:fs";
import path from "node:path";
import { google } from "googleapis";

async function exportarMetricasSearchConsole() {
  const caminhoCredenciais = path.resolve("./scripts/gsc-service-account.json");
  const credenciais = JSON.parse(fs.readFileSync(caminhoCredenciais, "utf8"));

  if (credenciais.private_key) {
    credenciais.private_key = credenciais.private_key.replace(/\\n/g, "\n");
  }

  const auth = new google.auth.GoogleAuth({
    credentials: credenciais,
    scopes: ["https://www.googleapis.com/auth/webmasters.readonly"],
  });

  const cliente = await auth.getClient();
  const searchconsole = google.searchconsole({ version: "v1", auth: cliente });

  const siteUrl = "sc-domain:wppoland.com";

  // Margem de 3 dias para permitir a consolidacao final dos dados pelo Google
  const dataFim = new Date(Date.now() - 3 * 864e5).toISOString().slice(0, 10);
  const dataInicio = new Date(Date.now() - 33 * 864e5).toISOString().slice(0, 10);

  console.log(`A iniciar extracao para ${siteUrl} entre ${dataInicio} e ${dataFim}`);

  const todasAsLinhas = [];
  let startRow = 0;
  const limiteLinhas = 25000;

  while (true) {
    const resposta = await searchconsole.searchanalytics.query({
      siteUrl,
      requestBody: {
        startDate: dataInicio,
        endDate: dataFim,
        dimensions: ["page", "query", "device", "country"],
        rowLimit: limiteLinhas,
        startRow,
      },
    });

    const linhas = resposta.data.rows || [];
    todasAsLinhas.push(...linhas);
    console.log(`Lote obtido: ${linhas.length} linhas (Total acumulado: ${todasAsLinhas.length})`);

    if (linhas.length < limiteLinhas) {
      break;
    }

    startRow += limiteLinhas;
  }

  const ficheiroDestino = "./reports/gsc-performance-data.json";
  fs.mkdirSync(path.dirname(ficheiroDestino), { recursive: true });
  fs.writeFileSync(ficheiroDestino, JSON.stringify(todasAsLinhas, null, 2), "utf8");

  console.log(`Extracao terminada. Guardados ${todasAsLinhas.length} registos em ${ficheiroDestino}`);
}

exportarMetricasSearchConsole().catch((erro) => {
  console.error("Falha na extracao do Search Console:", erro.message);
  process.exit(1);
});

Este código percorre as páginas de resultados sucessivas com o parâmetro startRow. Quando a resposta da API contém menos linhas do que o limite declarado de 25 000, o ciclo termina. Assim obtém o histórico completo de consultas sem perder os dados da cauda longa.

#Como extrair dados do Google Search Console em Python

Para engenheiros de dados e equipas que trabalham com Pandas e Jupyter, um script em Python é a ferramenta mais prática para extrair e limpar dados do Search Console. O exemplo abaixo obtém os dados divididos por dia e grava-os no formato otimizado Parquet, que ocupa menos espaço do que o CSV e preserva os tipos das colunas.

Para executar o script são necessárias as bibliotecas google-api-python-client, google-auth, pandas e pyarrow:

pip install google-api-python-client google-auth pandas pyarrow

Implementação do script:

import datetime
import pandas as pd
from google.oauth2 import service_account
from googleapiclient.discovery import build

def extrair_dados_pesquisa(site_url: str, dias: int = 30) -> pd.DataFrame:
    ficheiro_chave = "scripts/gsc-service-account.json"
    credenciais = service_account.Credentials.from_service_account_file(
        ficheiro_chave,
        scopes=["https://www.googleapis.com/auth/webmasters.readonly"]
    )
    
    servico = build("searchconsole", "v1", credentials=credenciais)
    
    data_fim = (datetime.date.today() - datetime.timedelta(days=3)).strftime("%Y-%m-%d")
    data_inicio = (datetime.date.today() - datetime.timedelta(days=dias + 3)).strftime("%Y-%m-%d")
    
    linhas_acumuladas = []
    start_row = 0
    row_limit = 25000
    
    while True:
        corpo = {
            "startDate": data_inicio,
            "endDate": data_fim,
            "dimensions": ["date", "page", "query", "country", "device"],
            "rowLimit": row_limit,
            "startRow": start_row
        }
        
        resposta = servico.searchanalytics().query(
            siteUrl=site_url,
            body=corpo
        ).execute()
        
        registos = resposta.get("rows", [])
        if not registos:
            break
            
        for reg in registos:
            linhas_acumuladas.append({
                "date": reg["keys"][0],
                "page": reg["keys"][1],
                "query": reg["keys"][2],
                "country": reg["keys"][3],
                "device": reg["keys"][4],
                "clicks": reg["clicks"],
                "impressions": reg["impressions"],
                "ctr": reg["ctr"],
                "position": round(reg["position"], 2)
            })
            
        print(f"Obtidas {len(registos)} linhas (startRow={start_row})")
        if len(registos) < row_limit:
            break
            
        start_row += row_limit
        
    df = pd.DataFrame(linhas_acumuladas)
    return df

if __name__ == "__main__":
    identificador = "sc-domain:wppoland.com"
    df_dados = extrair_dados_pesquisa(identificador, dias=60)
    
    if not df_dados.empty:
        df_dados["date"] = pd.to_datetime(df_dados["date"])
        df_dados.to_parquet("reports/gsc_performance.parquet", index=False)
        print(f"Sucesso. {len(df_dados)} registos guardados em Parquet.")
    else:
        print("Sem dados disponiveis para exportacao.")

A gravação no formato colunar Parquet permite agregar rapidamente e agrupar consultas por categoria de produto ou por modelo de página no WordPress, sem sobrecarregar a memória do servidor.

#Como obter dados recentes e por hora da Search Console API

Os scripts acima ignoram os últimos três dias, porque a Google indica que os dados ficam normalmente disponíveis ao fim de 2 a 3 dias (guia para obter todos os dados). O mesmo guia recomenda um teste simples: um pedido com a dimensão date para os últimos 10 dias mostra qual é o último dia disponível.

Se a API devolve ou não dados preliminares é decidido pelo parâmetro dataState (documentação do método query):

Valor de dataStateO que a API devolve
final (ou sem parâmetro)Apenas dados finalizados
allTambém dados recentes, que ainda podem mudar
hourly_allDados divididos por hora, parciais, para usar com a dimensão hour

Com dataState: "all" e agrupamento por data, a resposta inclui nos metadados o campo first_incomplete_date. Todos os valores posteriores a essa data ainda podem mudar de forma significativa, pelo que um script de arquivo deve guardá-los à parte ou substituí-los na execução seguinte. As horas nos metadados são indicadas no fuso America/Los_Angeles, o que conta quando se cruzam os dados com os registos de um servidor em Portugal.

A Google acrescentou a dimensão hour a 9 de abril de 2025. O painel mostra dados por hora apenas para as últimas 24 horas, enquanto a API os devolve para um máximo de 10 dias (anúncio no Google Search Central Blog). Isto permite comparar o último dia com o mesmo dia da semana anterior, por exemplo depois de publicar um artigo ou de implementar um novo tema.

{
  "startDate": "2026-10-15",
  "endDate": "2026-10-15",
  "dataState": "hourly_all",
  "dimensions": ["hour"]
}

As chaves na resposta têm o formato 2026-10-15T00:00:00-07:00, ou seja, a hora no fuso de Los Angeles com o respetivo desvio. Antes de gravar na base de dados, convém convertê-las para UTC.

#Como filtrar páginas e consultas na Search Analytics API

Um pedido sem filtros devolve todo o tráfego da propriedade. Num site multilingue, normalmente é preciso apenas uma fatia, por exemplo só os endereços com /pt-pt/. Para isso serve a matriz dimensionFilterGroups. É possível filtrar pelas dimensões country, device, page, query e searchAppearance, e os operadores disponíveis são (documentação do método query):

  • equals (predefinido) e notEquals: correspondência exata, com distinção entre maiúsculas e minúsculas para page e query,
  • contains e notContains: correspondência parcial sem distinção entre maiúsculas e minúsculas,
  • includingRegex e excludingRegex: expressão regular na sintaxe RE2.
{
  "startDate": "2026-09-01",
  "endDate": "2026-09-30",
  "dimensions": ["page", "query"],
  "type": "web",
  "dimensionFilterGroups": [{
    "filters": [
      { "dimension": "page", "operator": "includingRegex", "expression": "^https://wppoland\\.com/pt-pt/" },
      { "dimension": "query", "operator": "notContains", "expression": "wppoland" }
    ]
  }],
  "rowLimit": 25000
}

O segundo filtro exclui as consultas de marca, um passo típico antes de analisar a cauda longa. O parâmetro type substituiu o obsoleto searchType e aceita os valores web (predefinido, separador Tudo sem Discover nem Google News), image, video, news (separador Notícias), discover e googleNews. Cada tipo tem de ser obtido num pedido separado.

O parâmetro aggregationType decide se as métricas são calculadas por propriedade (byProperty) ou por URL (byPage); o valor predefinido auto deixa a escolha à Google. O valor byProperty não funciona com os tipos discover e googleNews.

#Porque é que o total da API não coincide com o gráfico do Search Console

Depois da primeira exportação, quase todas as equipas reparam que a soma dos cliques nas linhas é inferior ao número apresentado no gráfico do painel. Não é um erro do script. A Google descreve três causas (guia para obter todos os dados):

  1. A API disponibiliza no máximo 50 000 linhas por dia e por tipo de pesquisa, ordenadas por cliques. Em sites grandes, a cauda de consultas abaixo desse limiar não chega à resposta.
  2. Ao agrupar pelas dimensões page ou query, o sistema pode omitir parte dos dados para que os cálculos continuem exequíveis.
  3. Impressões, cliques, posição e CTR são calculados de forma diferente na agregação por página e na agregação por propriedade.

A isto juntam-se as consultas anonimizadas, que não existem em nenhuma fonte. Conclusão prática: obtenha os totais de tráfego com um pedido sem as dimensões page e query (apenas date) e trate a divisão por expressões como uma amostra ordenada por cliques. A Google recomenda também obter os dados dia a dia e paginar de 25 000 em 25 000 linhas até surgir uma página vazia, separadamente para cada tipo de pesquisa.

#Como guardar dados do Google Search Console no Google BigQuery

A solução mais resistente a falhas para sites grandes é a exportação automática dos dados do Google Search Console para o armazém de dados Google BigQuery. A Google lançou o Bulk Data Export a 21 de fevereiro de 2023: o mecanismo envia diariamente uma cópia dos dados de desempenho para o projeto BigQuery indicado (anúncio no Google Search Central Blog).

Vantagens desta abordagem:

  1. Sem o limite de 16 meses: os dados guardados no BigQuery ficam lá durante o tempo de que precisar.
  2. A exportação não está sujeita ao limite diário de linhas da API. A Google filtra apenas as consultas anonimizadas, por motivos de privacidade.
  3. Possibilidade de cruzar os dados do Search Console com tabelas da base de dados do WordPress (encomendas WooCommerce, carrinhos, conversões).

A exportação configura-se em dois passos. Na Google Cloud Console, ative a BigQuery API no projeto e conceda permissões à conta de serviço do Search Console. Nas definições do Search Console, indique o identificador do projeto e a localização do conjunto de dados. Só o proprietário da propriedade pode configurar a exportação. O Search Console começa por simular a exportação; se a simulação correr bem, todos os proprietários recebem um email e as exportações regulares arrancam no prazo de 48 horas. Em caso de erro, o alerta surge de imediato.

A exportação cria três tabelas:

  • searchdata_site_impression: dados agregados por propriedade, com consulta, país, tipo de pesquisa e dispositivo.
  • searchdata_url_impression: dados agregados por URL, com detalhes das consultas e dos resultados com elementos avançados.
  • ExportLog: registo dos dados que chegaram à base em cada dia. As exportações falhadas não ficam aqui registadas.

Exemplo de consulta SQL no BigQuery que identifica páginas com muitas impressões e CTR baixo no mercado português (candidatas à otimização das meta tags e dos títulos):

SELECT
  url,
  query,
  SUM(impressions) AS total_impressions,
  SUM(clicks) AS total_clicks,
  ROUND(SAFE_DIVIDE(SUM(clicks), SUM(impressions)) * 100, 2) AS calculated_ctr,
  ROUND(SUM(sum_position) / SUM(impressions) + 1, 1) AS avg_position
FROM
  `projeto-analytics.searchconsole.searchdata_url_impression`
WHERE
  data_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
  AND country = 'prt'
GROUP BY
  url,
  query
HAVING
  total_impressions > 500
  AND calculated_ctr < 2.0
  AND avg_position BETWEEN 3.0 AND 10.0
ORDER BY
  total_impressions DESC
LIMIT 100;

A tabela searchdata_url_impression inclui, entre outras, as colunas data_date, url, query, country, search_type, impressions, clicks e sum_position, bem como indicadores dos tipos de resultados avançados (o exemplo da Google filtra search_type = 'WEB'). A coluna sum_position conta a posição a partir de zero, por isso a posição média calcula-se como SUM(sum_position) / SUM(impressions) + 1, tal como no exemplo da Google. A consulta seleciona expressões da primeira página de resultados que obtêm menos de 2 por cento de cliques. São candidatas a um teste de novo título, cabeçalho H1 e descrição; o efeito da alteração tem de ser medido nas semanas seguintes, não presumido à partida.

                  Pipeline Search Console para o BigQuery
                  
   [Google Search Console] ──(Bulk Export)──> [Google BigQuery]
                                                    │
                                                    ├──> [Painel Looker Studio]
                                                    ├──> [Auditoria de perda de posicoes]
                                                    └──> [Cruzamento com encomendas WooCommerce]

#Quando escolher a Search Analytics API e quando o Bulk Data Export

As duas fontes dão as mesmas métricas, mas resolvem problemas diferentes. No anúncio da exportação, a Google escreve que ela é especialmente útil para sites grandes, com dezenas de milhares de páginas ou com tráfego de dezenas de milhares de consultas por dia, e que os sites pequenos e médios têm acesso a todos os seus dados através da interface, do conector do Looker Studio ou da Search Analytics API (Google Search Central Blog).

CritérioSearch Analytics APIBulk Data Export
Limite de linhas25 000 por pedido, 50 000 por dia e por tipo de pesquisaSem limite diário de linhas
Consultas anonimizadasOmitidasOmitidas
AtualidadeDados preliminares (all) e por hora (hourly_all)Cópia diária
Quem pode configurarQualquer utilizador com acesso à propriedadeApenas o proprietário da propriedade
Para onde vão os dadosPara onde o seu script os gravarPara o seu projeto BigQuery

Na prática, as duas abordagens complementam-se. A exportação para o BigQuery funciona como arquivo e fonte para análises de cauda longa, enquanto um script leve sobre a API com dataState: "hourly_all" vigia as últimas horas depois de uma publicação ou implementação. Para um blog pequeno em WordPress, o script das secções anteriores, executado uma vez por dia por cron, costuma bastar.

#Como associar dados do Search Console à base de dados do WordPress

Os dados brutos do Search Console ganham o maior valor de negócio quando são associados à estrutura interna de conteúdos do CMS. A exportação tradicional do Search Console contém apenas URLs completos sob a forma de cadeias de texto. Não informa sobre o tipo de conteúdo (artigo, produto WooCommerce, página de destino), a data da última alteração no editor Gutenberg nem o autor do texto.

A integração dos dados consiste em traduzir o caminho do URL para o identificador do objeto no WordPress (post_id). No WordPress, para isso serve a função url_to_postid($url) ou a correspondência direta do slug na tabela wp_posts.

O excerto de código PHP abaixo ilustra como atribuir os dados de consultas importados da API ao produto ou artigo correto na base de dados:

<?php
/**
 * Integracao de metricas do Search Console com o WordPress
 */
declare(strict_types=1);

namespace WPPoland\Analytics;

class SearchConsoleIngestor {
    
    public function atualizarMetricasArtigo(string $url, int $cliques, int $impressoes, float $posicao): void {
        $caminho = wp_parse_url($url, PHP_URL_PATH);
        if (!$caminho) {
            return;
        }

        $postId = url_to_postid($url);
        
        if ($postId === 0) {
            $postId = $this->obterIdTermoTaxonomia($caminho);
        }

        if ($postId > 0) {
            update_post_meta($postId, '_gsc_cliques_30d', $cliques);
            update_post_meta($postId, '_gsc_impressoes_30d', $impressoes);
            update_post_meta($postId, '_gsc_posicao_media', $posicao);
            update_post_meta($postId, '_gsc_data_atualizacao', current_time('mysql', true));
        }
    }

    private function obterIdTermoTaxonomia(string $caminho): int {
        global $wpdb;
        $slugLimpo = trim($caminho, '/');
        $segmentos = explode('/', $slugLimpo);
        $slugFinal = end($segmentos);

        $termId = $wpdb->get_var($wpdb->prepare(
            "SELECT t.term_id FROM {$wpdb->terms} t 
             JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id 
             WHERE t.slug = %s LIMIT 1",
            $slugFinal
        ));

        return $termId ? (int)$termId : 0;
    }
}

Com esta associação, a equipa editorial vê no painel do WordPress o número exato de impressões e a posição de cada página. Se, depois de uma atualização do tema ou da implementação de novo código, a posição média de um artigo cair do lugar 4 para o 18, o sistema pode gerar automaticamente uma notificação num canal do Slack ou criar uma tarefa de auditoria para o programador.

Em arquiteturas baseadas em WordPress headless ou em geradores de sites estáticos, os dados da Search Console API podem ser obtidos durante a compilação do site (build time) e usados para gerar secções dinâmicas com os temas mais populares e os artigos relacionados.

#Como verificar o estado de indexação dos endereços exportados com a URL Inspection API

Uma queda de cliques de um artigo nos dados da Search Analytics não diz se a página continua no índice. A resposta vem da URL Inspection API, que usa a mesma conta de serviço e os mesmos âmbitos (webmasters ou webmasters.readonly). O pedido é POST https://searchconsole.googleapis.com/v1/urlInspection/index:inspect com os campos inspectionUrl (endereço completo, que tem de pertencer à propriedade), siteUrl (no mesmo formato de antes: sc-domain: ou prefixo com barra final) e o campo opcional languageCode (documentação do método inspect).

O resultado indexStatusResult contém, entre outros (descrição de UrlInspectionResult):

CampoO que significa
verdictResultado geral: se o endereço está indexado
coverageStateSe a Google encontrou e indexou a página
indexingStateSe uma regra noindex bloqueia a indexação
robotsTxtStateSe o robots.txt bloqueia o rastreio
lastCrawlTimeQuando o rastreador principal obteve o endereço pela última vez
googleCanonical e userCanonicalCanónico escolhido pela Google e canónico declarado na página

No WordPress, isto combina bem com a classe SearchConsoleIngestor da secção anterior: quando a posição de um artigo cai, o script verifica o seu endereço e grava coverageState e googleCanonical nos metadados do artigo. Uma discrepância entre o canónico da Google e o do plugin de SEO costuma explicar a queda mais depressa do que a análise de expressões. O limite, porém, é baixo: 2000 pedidos por dia e 600 por minuto por site (limites da Search Console API), por isso verifique apenas os endereços com sinal de queda, não o sitemap inteiro. O método mostra a versão do índice da Google e não testa o endereço em tempo real. A diferença entre esta ferramenta e a Indexing API é explicada no nosso guia do GSC e da Indexing API.

#Como lidar com limites de quota e erros da API

A Search Analytics API tem limites descritos na documentação da Google. Ultrapassá-los resulta num erro de quota, e o script tem de esperar:

Âmbito do limiteValor
Por site (pedidos sobre a mesma propriedade)1 200 pedidos por minuto
Por utilizador (pedidos da mesma conta)1 200 pedidos por minuto
Por projeto Google Cloud40 000 pedidos por minuto e 30 000 000 por dia

À parte funciona o limite de carga (load quota), calculado em janelas de 10 minutos e diárias. Segundo a Google, os pedidos são dispendiosos quando agrupa ou filtra por página ou por consulta, e a carga aumenta com a extensão do intervalo de datas. A Google desaconselha expressamente obter os mesmos dados várias vezes, por exemplo o mês anterior inteiro a cada execução. Um script de arquivo deve, por isso, ir buscar apenas os dias em falta.

Para garantir a fiabilidade de scripts que obtêm milhões de registos em grandes lojas de comércio eletrónico, convém implementar três mecanismos de defesa:

  1. Atraso exponencial nas novas tentativas (Exponential Backoff): ao receber um código de erro 429 ou 503, o script não interrompe o trabalho e espera um número crescente de segundos (2 elevado a n mais um jitter aleatório) antes de repetir o pedido.
  2. Divisão dos pedidos por dias individuais (Daily Date Chunking): em vez de obter os dados de um ano inteiro numa só chamada com paginação enorme, divide-se a tarefa em ciclos de um dia. Se um dos pedidos falhar por um erro de rede momentâneo, repete-se apenas o dia em falta.
  3. Reutilização dos tokens de autorização: as bibliotecas cliente da Google renovam automaticamente o token OAuth2 com base na chave da conta de serviço, mas em ambientes serverless (AWS Lambda, Cloudflare Workers) é preciso garantir que o token não é gerado de novo para cada pedido HTTP.

O excerto de código abaixo ilustra um mecanismo de consulta resiliente com novas tentativas:

async function executarComRepeticao(acaoApi, limiteTentativas = 5) {
  let tentativa = 0;
  while (tentativa < limiteTentativas) {
    try {
      return await acaoApi();
    } catch (erro) {
      tentativa++;
      const eLimiteQuota = erro.code === 429 || erro.status === 429;
      const eErroServidor = erro.code >= 500 && erro.code < 600;

      if ((eLimiteQuota || eErroServidor) && tentativa < limiteTentativas) {
        const esperaMs = Math.pow(2, tentativa) * 1000 + Math.random() * 500;
        console.warn(`Erro ${erro.code}. Nova tentativa em ${Math.round(esperaMs)} ms (Tentativa ${tentativa}/${limiteTentativas})...`);
        await new Promise((resolve) => setTimeout(resolve, esperaMs));
      } else {
        throw erro;
      }
    }
  }
}

Estes três mecanismos fazem com que o arquivo de dados de SEO funcione independentemente das falhas no painel do Google Search Console no navegador.

#Como gerir dados de SEO com a Search Console API

Erros da interface gráfica, como a falha do seletor de datas e o recuo do calendário para 1969, lembram que os dados analíticos de um site devem estar no sistema do seu proprietário e não apenas num painel externo.

Um pipeline independente assente na Search Console API traz benefícios concretos:

  • Até 50 000 linhas por dia e por tipo de pesquisa em vez das 1000 linhas da tabela do painel e, com o Bulk Data Export, o conjunto completo sem as consultas anonimizadas.
  • Relatórios independentes dos erros de frontend da Google.
  • Proteção contra a perda de dados históricos ao fim de 16 meses, graças ao arquivo no BigQuery ou numa base de dados relacional.
  • Possibilidade de correlacionar diretamente o tráfego com as receitas da loja WooCommerce e com as alterações no código do tema WordPress.

Para implementar análises avançadas, automatizar relatórios ou fazer uma auditoria técnica do site, vale a pena consultar um programador WordPress que ligue o pipeline de dados à arquitetura da sua loja e o proteja contra falhas. Para consultoria técnica, entre em contacto com a nossa equipa.

Próximo passo

Transforme o artigo numa implementação real

Este bloco reforça a ligação interna e conduz o leitor para o passo seguinte mais útil dentro da arquitetura do site.

Quer implementar isto no seu site?

Se a visibilidade no Google e em sistemas de IA importa, posso estruturar conteúdo, FAQ, schema e linkagem interna para SEO, GEO e AEO.

Cluster relacionado

Explorar outros serviços WordPress e base de conhecimento

Reforce o seu negócio com suporte técnico profissional em áreas-chave do ecossistema WordPress.

Por que razão o seletor de datas do Google Search Console bloqueia em 1969-12-31#
A Google não publicou a causa. A própria data aponta para um carimbo de data/hora igual a zero, ou seja, a meia-noite de 1 de janeiro de 1970 UTC (Unix epoch), que em fusos horários a oeste de Greenwich é apresentada como 31 de dezembro de 1969. O Search Engine Roundtable descreveu o erro a 13 de outubro de 2026; o seletor foi corrigido, voltou a falhar a 14 de outubro e no mesmo dia voltou a funcionar.
Quantas linhas de dados podem ser extraídas através da Google Search Console API#
Um único pedido ao método searchanalytics.query devolve até 25 000 linhas (1000 por predefinição). O parâmetro startRow permite paginar os resultados, mas a Google disponibiliza através da API no máximo 50 000 linhas por dia e por tipo de pesquisa, ordenadas por cliques. Um conjunto mais completo, sem as consultas anonimizadas, é dado pelo Bulk Data Export para o BigQuery.
Qual é a diferença entre consultar sc-domain e um prefixo de URL na API#
A sintaxe sc-domain agrega todo o tráfego em todos os subdomínios e protocolos. Uma propriedade de prefixo de URL restringe-se a uma pasta ou protocolo específico e requer uma barra final no parâmetro siteUrl.
Durante quanto tempo o Google guarda os dados no Search Console#
O Google guarda os dados de cliques e impressões durante 16 meses. Após esse período, os registos são eliminados permanentemente. A exportação para o BigQuery ou bases de dados locais assegura a retenção para comparações homólogas (YoY).
Como se associam os dados da Search Console API ao WordPress#
O script associa o URL da página presente na resposta da API ao registo wp_posts utilizando a função url_to_postid. Desta forma, é possível monitorizar impressões orgânicas e quedas de posição diretamente no painel do WordPress.

Precisa de FAQ adaptado ao setor e mercado? Criamos uma versão alinhada com os seus objetivos de negócio.

Fale connosco

Artigos Relacionados