CommunityEscrita e Ediçãogithub.com

bojan-basrak/rankscale-api-skill

Uma Skill de Agente não oficial e independente de provedor para consultar a API REST de visibilidade de marca da Rankscale — funciona com Claude Code, Cursor, Codex e outras ferramentas de agente.

O que é rankscale-api-skill?

Esta Skill de Agente permite que profissionais de SEO consultem a API REST da Rankscale, uma ferramenta de rastreamento de visibilidade de marca impulsionada por IA, sem precisar usar o painel web. A skill autentica-se por meio da variável de ambiente `RANKSCALE_API_KEY` e usa `curl` para chamar endpoints como `/v1/metrics/report`, `/v1/metrics/citations` e `/v1/metrics/sentiment`. A documentação detalha a estrutura das respostas (sempre verifique `.success` e `warnings[]`), parâmetros de consulta (como `timeFrame` em camelCase, `isoStartDate` e `isoEndDate`) e filtros opcionais (como `selectedTopic`, `selectedEngine` e `selectedTags`). A skill suporta o cálculo de classificação de marca por visibilidade, extração de dados de citações e sentimento, e inclui notas sobre tamanhos de payload potencialmente grandes (alguns endpoints retornam megabytes), eficiência de tokens e como lidar com peculiaridades da API (por exemplo, o campo `latestRank` não representa uma classificação ordinal real). Também cobre técnicas para evitar confundir respostas com flags `caps` ou respostas incompletas.

Funciona com✓Claude Code✓Codex CLI✓Cursor✓Antigravity✓Gemini CLI
npx skills add bojan-basrak/rankscale-api-skill

Installed? Explore more Escrita e Edição skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

API REST da Rankscale

Rankscale é uma ferramenta de rastreamento de visibilidade de marca com IA. Ela envia prompts para vários modelos de IA (ChatGPT, Gemini, Claude, Perplexity, etc.) com os termos de pesquisa rastreados pelo usuário, analisa as respostas e relata com que frequência, onde e quão favoravelmente as marcas rastreadas são mencionadas.

Esta skill chama a API REST diretamente para que o usuário (um profissional de SEO, não um desenvolvedor) possa extrair dados para relatórios, gráficos e análises personalizadas sem precisar navegar pelo painel.

Configuração

  • Chave de API: Lida da variável de ambiente RANKSCALE_API_KEY. O formato da chave é rk_<hash>_<workspaceId> - o sufixo é um identificador de workspace, não um ID de marca, então uma chave acessa todas as marcas em seu workspace (peculiaridades §15). Se não estiver definida, peça ao usuário para defini-la uma vez: PowerShell setx RANKSCALE_API_KEY "rk_..." (um novo shell é necessário para fazer efeito) ou passe por sessão com $env:RANKSCALE_API_KEY = "rk_...". Nunca imprima a chave nas respostas ou a escreva em arquivos.
  • URL base: https://rankscale.ai (nota: sem prefixo /api - o caminho é /v1/... diretamente no domínio de marketing).
  • Cabeçalho de autenticação: Authorization: Bearer $RANKSCALE_API_KEY.
  • Limite de taxa: 200 requisições por minuto por chave de API. A resposta carrega X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset (segundos até a janela reiniciar) - leia-os com curl -i se estiver fazendo trabalho em lote. Armazene em cache as respostas de relatórios por 5-10 minutos quando possível.
  • Ferramentas disponíveis: curl para requisições. Para análise de JSON, use o que o ambiente fornecer - node -e "...", jq ou python -m json.tool. Verifique o que está no PATH antes de assumir; não dependa rigidamente de nenhum deles.
  • Sintaxe do shell: os exemplos abaixo usam expansão de variável no estilo bash ($RANKSCALE_API_KEY). No Windows PowerShell, isso se torna $env:RANKSCALE_API_KEY. Escolha a ferramenta de shell que você chamar - ambas funcionam, mas preste atenção à sintaxe.

Padrão de chamada

Todo endpoint retorna {success: true, data: {...}} em caso de sucesso, ou {success: false, error: {code, message, details}} em caso de falha. Sempre verifique .success antes de ler .data.

Verifique warnings também. Uma resposta bem-sucedida pode carregar uma terceira chave de nível superior, warnings[], listando quaisquer campos da requisição que a API não reconheceu e ignorou - geralmente com uma sugestão ("Campo não reconhecido 'startDate' ignorado. Você quis dizer 'isoStartDate'? …"). Ele está ausente quando a requisição estava limpa, então if (json.warnings) é uma proteção confiável. Um aviso significa que os números respondem a uma pergunta diferente da que foi feita - a API usa os padrões para o campo ignorado. Apresente-o ao usuário em vez de engoli-lo; esta é a captura mais barata possível para a armadilha do camelCase (peculiaridades §1).

Salve as respostas JSON brutas em um arquivo próximo ao trabalho do usuário (tipicamente Rankscale/<endpoint>_<contexto>.json) para que possam ser reanalisadas sem chamar a API novamente. Mostre ao usuário um resumo limpo, não o JSON bruto, a menos que ele solicite.

Eficiência de tokens - a maior alavanca. Para qualquer coisa em lote (multitópico, multi-mecanismo, histórico completo ou /search-terms-report com includeAnswerTexts), escreva a resposta diretamente no disco com -o e extraia apenas os valores necessários com node -e. Não leia cargas inteiras de /report no contexto - um relatório filtrado tem cerca de 40-50 KB e uma varredura de 7 tópicos tem ~300 KB. Extrair escalares/séries do lado do cliente mantém isso fora do contexto e, em extrações em massa, reduz aproximadamente pela metade o uso de tokens em comparação com a leitura de cargas inline. (Para uma única métrica restrita, a sobrecarga não vale a pena - apenas leia a pequena resposta.)

Os tamanhos das cargas são extremamente desiguais - planeje em torno deles. Medido em uma única marca:

EndpointJanelaTamanho
/report (filtrado)30d~40-50 KB
/report (filtrado)1 mês calendário~105-110 KB
/citations3m~3.9 MB
/citations uncapped: true1 mês calendário~4.4-5.7 MB
/sentiment30d~9 MB
/sentiment3m~17 MB

O tamanho não escala com a duração da janela - uncapped: true importa muito mais. Uma única mês sem limite retornou maior do que uma extração de três meses com limite, então não extrapole o tamanho de 1 mês a partir da linha de 3m.

/sentiment e /citations nunca são seguros para ler inline - sempre use -o para um arquivo e extraia. Em chamadas tão pesadas, capture também o status HTTP (curl -w '%{http_code}'), porque um 502 transitório chega como um corpo HTML que parece um caminho quebrado, mas só precisa de uma nova tentativa (peculiaridades §6).

# Bash (Git Bash / WSL / macOS / Linux)
curl -s -H "Authorization: Bearer $RANKSCALE_API_KEY" \
     "https://rankscale.ai/v1/metrics/brands" \
     -o brands.json

curl -s -X POST -H "Authorization: Bearer $RANKSCALE_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{"brandId":"<id>"}' \
     "https://rankscale.ai/v1/metrics/report" \
     -o report.json
# Equivalente PowerShell
curl.exe -s -H "Authorization: Bearer $env:RANKSCALE_API_KEY" `
     "https://rankscale.ai/v1/metrics/brands" `
     -o brands.json

curl.exe -s -X POST -H "Authorization: Bearer $env:RANKSCALE_API_KEY" `
     -H "Content-Type: application/json" `
     -d '{\"brandId\":\"<id>\"}' `
     "https://rankscale.ai/v1/metrics/report" `
     -o report.json

Observe no PowerShell: use curl.exe (o alias curl aponta para Invoke-WebRequest, que se comporta de forma diferente), escape as aspas internas em corpos JSON -d com \" e use crase ` para continuação de linha. Invoke-RestMethod também funciona e analisa JSON automaticamente, mas a forma curl mantém as respostas consistentes entre shells.

O inventário completo de endpoints e formas de requisição está em references/endpoints.md. Leia-o antes de qualquer chamada sobre a qual você não tenha certeza. Surpresas e pegadinhas estão em references/quirks.md - leia-o antes de reportar métricas ao usuário, porque várias delas afetam como os números devem ser interpretados.

Fora do escopo: a API de Links de Compartilhamento. A Rankscale publica uma segunda API REST para links de compartilhamento público de painéis. Ela usa uma chave diferente (Configurações → Compartilhamento, não Configurações → Integrações), então RANKSCALE_API_KEY não autenticará nela. Se o usuário pedir para criar ou revogar um link de compartilhamento, diga que é uma API separada que esta skill não cobre - não adivinhe seus caminhos.

Receitas de fluxo de trabalho

1. Identificar a marca

A maioria dos endpoints de relatório precisa de um brandId. Quando o usuário nomear uma marca ("mostre-me as métricas da Acme"), resolva o ID primeiro:

  1. Se Rankscale/brands.json existir no diretório de trabalho do usuário, leia-o.
  2. Caso contrário, chame GET /v1/metrics/brands e salve o resultado.
  3. Combine o nome da marca do usuário com brands[].name (sem distinção entre maiúsculas e minúsculas) e com brands[].brandInfo.names (apelidos). Se houver múltiplas correspondências, peça ao usuário para desambiguar.

2. Extrair métricas para uma marca em uma janela

O usuário quase sempre pede uma janela de tempo. Use timeFrame (camelCase, F maiúsculo - a API ignora silenciosamente qualquer outra grafia) com um destes valores predefinidos documentados: 24h, 7d, 30d, 3m, 1y. Combine com aggregation (hourly, daily, weekly ou monthly) para o tamanho do balde. Para janelas personalizadas, use isoStartDate + isoEndDate (strings de data ISO emparelhadas); estes substituem timeFrame.

{
  "brandId": "<id>",
  "timeFrame": "30d",
  "aggregation": "daily",
  "includeNotFoundExecutions": true
}

Filtros de relatório opcionais (todos aceitam uma única string, um array para OU-dentro-do-campo, ou "all" para nenhum filtro; filtros combinam com E entre campos):

  • selectedTopic - ID do tópico, nome do tópico, _orphaned ou array
  • selectedTags - tag, __UNTAGGED__ ou array
  • selectedEngine - ID do mecanismo (preferido - veja references/endpoints.md para o catálogo) ou nome amigável
  • selectedQuery - string de consulta de termo de pesquisa exato ou array
  • searchTermId - ID de termo de pesquisa único
  • periodOffset - inteiro, desloca a janela predefinida para trás N períodos (0 = atual, 1 = anterior, ...)
  • userTimezone - fuso horário IANA como Europe/Berlin para limites de dia local do usuário
  • includeNotFoundExecutions - booleano, controla se as execuções "marca não encontrada na resposta" contam para as métricas (veja quirks.md)

Leia a resposta de data.ownBrandMetrics.historicalData.<aggregation> (por exemplo, .daily quando você pediu aggregation: "daily"). Cada array de balde - visibilityScore, sentiment, mentions, sources, citations, citationCounts, avgPosition, detectionRate, top3, brandNotFound - executa em paralelo com timestamps.

Três séries temporais paralelas estão ao lado:

  • data.ownBrandMetrics.topicMetricsData.<aggregation> - por tópico
  • data.ownBrandMetrics.engineMetricsData.<aggregation> - por mecanismo; não documentado upstream, e geralmente o corte de maior valor quando uma janela agregada parece plana, porque movimentos no nível do mecanismo se cancelam no total (peculiaridades §25)
  • data.competitorTimeSeriesData.<aggregation> - por concorrente, marca própria excluída (peculiaridades §16)

brandNotFound[] é um não-sinal - ele lê true para essencialmente qualquer marca com detecção abaixo de 100%. Use detectionRate e nunca reporte "marca não encontrada" a partir da flag (peculiaridades §2).

Apresente uma tabela de métricas com estas colunas: Data, Visibilidade, Sentimento, Menções, Citações, Posição Média, % Detecção, % Top-3. Acima dela, mostre o resumo do instantâneo (valores atuais do instantâneo de ownBrandMetrics + o delta de trends).

Classificação da Marca (por Visibilidade) - vs. concorrentes. Calcule isso a partir de data.competitorMetrics[] (que inclui a própria marca, sinalizada isOwnBrand: true): classificação = 1 + (contagem de entradas com visibilidadeScore estritamente maior) - empates não empurram a marca para baixo. Isso reproduz a classificação do painel. A resposta também carrega latestRank/avgRank por entrada - estes não são classificações. Verificado em 2026-08-07: eles retornam valores não inteiros (latestRank: 2.7, avgRank: 2.9) para uma marca cuja classificação calculada era 1, então eles rastreiam algo parecido com posição, não um ordinal. Ignore-os. O equivalente own_brand_rank do MCP é igualmente sempre 1 (um pino de exibição). O cálculo de classificação por visibilidade acima é o método que correspondeu ao painel nos testes. Os filtros compartilhados (selectedEngine, selectedTopic, selectedTags, selectedQuery) funcionam por corte, então você pode classificar dentro de um único mecanismo, tópico, tag ou consulta executando novamente com filtro. Observe que as entradas competitorMetrics podem carregar um validMetricsCount diferente da própria marca (as linhas de base dos concorrentes usam uma janela mais ampla) - a ordenação ainda corresponde à interface do usuário. Receita completa - incluindo classificação diária ao longo do tempo e suas ressalvas - na receita §6 abaixo.

3. Análise de citações

/v1/metrics/citations retorna quais fontes (sites, artigos) os modelos de IA citam ao responder aos termos de pesquisa do usuário. Útil para entender quais domínios de terceiros influenciam as respostas de IA sobre uma marca.

Campos-chave: data.totalCitations, data.uniqueCitations (URLs distintas), data.uniqueDomains e data.citationsByDomain[] (cada domínio). Em cada entrada de domínio, occurrences é a contagem; o campo citations é o array de URLs, não um número - então a parcela de citações = occurrences / totalCitations, e as principais URLs vêm de achatar o array de URLs de cada domínio e classificar por occurrences.

Cada objeto de URL é {url, normalizedUrl, occurrences, engineAppearances: {<engineId>: count}, firstSeenAt, lastSeenAt, category, searchTerms[]}. engineAppearances é a única divisão de citações por mecanismo na API - some-a nos URLs de um domínio para responder "quais mecanismos citam nosso site." firstSeenAt/lastSeenAt são o único eco da janela que você realmente obteve. Normalize normalizedUrl ainda mais antes da análise no nível da página (ela deixa variantes de www./barra final/consulta distintas) e observe que category: "owned" significa "o próprio site de uma empresa", não de propriedade da marca rastreada - concorrentes também o carregam. Veja quirks.md §13b. data.domainSummary tem visualizações pré-cortadas (topDomainsOverall, topDomainsByEngine, topDomainsByQuery, topDomainsByOwnBrandCitations, topDomainsByCompetitor) - mas estas são limitadas (≈20/10 entradas) e topDomainsByCompetitor lista domínios onde um concorrente foi mencionado (inclui sites neutros de terceiros como Reddit/Booking), então não o use para identificar sites de propriedade do concorrente. Veja quirks.md §13b.

Verifique os limites antes de considerar uma lista completa. A resposta limita em 5.000 URLs únicos e 50 marcas por padrão. data.paginationInfo relata a verdade - citationsCapped, brandsCapped, responseTrimmed, capBypassed, maxCitations, maxBrands, totalCount vs returnedCount. Passe uncapped: true (corpo ou parâmetro de consulta) para levantar o limite de URL; ele não levanta o limite de 50 marcas ou o guarda de tamanho de resposta. deduplicated: true desduplica caminhos de resposta e adiciona data.searchTermsById. Se qualquer flag de limite for true, informe o usuário e restrinja a janela ou filtre em vez de apresentar uma lista truncada como o quadro completo. Veja quirks.md §13c.

4. Sentimento

/v1/metrics/sentiment retorna agregados de sentimento no nível da janela mais nuvens de palavras-chave para a marca rastreada e cada concorrente - não uma série temporal (use historicalData.<agg>.sentiment[] do /report para sentimento ao longo do tempo). Mesmos filtros compartilhados, mais deduplicated: true.

Dois arrays com escopos diferentes: data.brandSentiments[] é apenas a marca rastreada; data.companySentiments[] é toda marca detectada incluindo a própria marca (isOwnBrand: true) - use este para comparações de concorrentes. brandSentimentsBySearchTerm[] / companySentimentsBySearchTerm[] fornecem os mesmos cortes por termo de pesquisa.

Por entrada: avgSentiment (escala 0-100, = totalSentimentScore / sentimentCount), sentimentCount, executionCount e positiveCount / neutralCount / negativeCount. O sentimento é dividido por fonte - blocos webGrounding* (mecanismos com base na web) vs trainingData*, controlados pelos booleanos hasWebGrounding / hasTrainingData, com webGroundingSentimentByEngine[<engineId>] = {sum, count, avg} para pontuações por mecanismo.

Duas armadilhas - leia quirks.md §19 antes de relatar qualquer coisa disso. (1) ...

[truncated for translation]

Habilidades Relacionadas