Playwright MCP: custo em tokens vs ler a página em markdown

Rodamos o servidor Playwright MCP real e o markdown do FastAF em 11 páginas públicas e contamos tokens. Página mediana: 9.874 vs 5.083, com exceções nos dois sentidos.

Uma leitura de página com o Playwright MCP custa uma mediana de 9.874 tokens no nosso teste, contra 5.083 para as mesmas páginas em markdown pelo FastAF. É cerca do dobro de tokens, não cem vezes mais. A dispersão, porém, é grande: de 0,4x numa página a 4x em outra. Medimos 11 páginas públicas em 19 de outubro de 2026 com o @playwright/mcp 0.0.83 e contamos os tokens com o tiktoken o200k_base.

Não encontramos uma medição por página do Playwright MCP que pudéssemos reproduzir, então fizemos uma. O método e o script estão abaixo, junto com os casos em que o navegador é a ferramenta certa.

Quantos tokens o Playwright MCP usa por página?

Iniciamos o servidor real (@playwright/mcp 0.0.83, a mais recente no npm nesta data, rodando o Playwright 1.64 alpha) em modo headless via stdio, com o SDK Python oficial do MCP como cliente. Para cada página, o cliente chamou browser_navigate e depois browser_snapshot, e contamos cada caractere que o modelo teria recebido. Na 0.0.83, browser_navigate devolve só um link para um arquivo de snapshot (78 a 168 tokens), então ler a página exige a segunda chamada. O outro braço foi o /v1/scrape do FastAF com formats=markdown, primeiro simples e com dynamic=true só quando a chamada simples falhava ou as frases de verificação não apareciam.

“Funcionou” significa que duas frases definidas de antemão estavam presentes no que o modelo veria. Os tokens são da execução 1 de 3 e cobrem navigate mais snapshot.

Página HTML bruto Snapshot do Playwright Playwright --mobile Markdown do FastAF
MDN, Fetch API (docs) 41.439 7.481 6.367 4.110
Docs do Python, asyncio tasks (docs longa) 50.276 34.405 33.354 15.236
Artigo do Guardian (notícia) 101.462 6.343 6.129 3.585
Estante BILLY da IKEA (produto) 336.714 10.017 7.812 5.092
Wikipedia, Model Context Protocol 79.923 24.931 3.864 (dobrado) 21.784
GitHub, python-sdk (repositório) 135.152 9.874 6.807 5.083
crates.io, serde (app renderizado em JS) n/d (404) 4.693 4.767 1.408 (5 créditos)
Página inicial do Hacker News (listagem) 11.694 13.649 13.649 3.365
Post do blog de engenharia da Anthropic 51.697 11.689 11.447 6.115
PyPI, requests (pacote) 73.730 7.931 4.840 (rala) 20.165
GOV.UK, alíquotas de IVA 19.415 3.378 3.337 1.392
Mediana, 11 páginas 51.697 9.874 6.367 5.083
Total, 11 páginas 901.502 134.391 102.373 87.335

“HTML bruto” é um GET simples, só para dar escala. O crates.io devolveu um shell 404 para ele. Os tempos ficaram próximos: uma página do Playwright já aquecido levou uma mediana de 0,5 s (a primeira chamada depois do início somou 0,4 a 0,9 s), e o FastAF uma mediana de 0,5 s em três execuções, com renderização dinâmica de 6 a 7 s. As contagens de tokens do Playwright variaram menos de 2% entre execuções, exceto no Guardian (5.671 a 6.343) e na página do GitHub (9.376 a 9.874). A saída em markdown da Wikipedia pelo FastAF foi de 21.784 tokens em duas chamadas e 9.513 em outras duas, então trate essa linha como uma faixa.

Por que um snapshot é maior que o markdown?

Um snapshot é uma árvore de acessibilidade em YAML. Cada nó carrega um papel, um nível de aninhamento e um id [ref=...] para o agente poder clicar nele, e cada link gasta uma linha com o seu destino - /url:. Só as linhas de URL, contadas à parte, somam 18% dos tokens do snapshot nas páginas (9% nos docs do Python, 25% no Hacker News). O Hacker News é o caso mais claro: o layout em tabela vira table > rowgroup > row > cell vários níveis abaixo antes da primeira notícia, e o snapshot é 4x o markdown.

O markdown não tem refs e quase nenhuma estrutura, então páginas ricas em prosa saem cerca de 2x menores. Duas páginas não seguiram esse padrão. O markdown do PyPI (20.165) manteve a página inteira, incluindo a lista de arquivos e os classificadores, enquanto o snapshot (7.931) não. O markdown da Wikipedia ficou a 13% do snapshot. O resumo honesto é que o snapshot é um pouco maior na maioria das páginas e a estrutura é o que você paga, mas uma página com muito texto pode custar mais em markdown.

Quanto isso custa em dólares?

A página de preços da Anthropic lista o Claude Sonnet 5.5 a $2 por milhão de tokens de entrada e o Claude Fable 5.1 a $10 (ambos em 19 de outubro de 2026, página de preços). Nossas contagens usam um tokenizador da OpenAI, então as do Claude vão diferir um pouco; o que vale confiar são as proporções. Na página mediana:

Por 1.000 leituras de página Tokens Entrada Sonnet 5.5 Entrada Fable 5.1
HTML bruto 51,7 M $103,39 $516,97
Snapshot do Playwright MCP 9,9 M $19,75 $98,74
Playwright MCP, --mobile 6,4 M $12,73 $63,67
Markdown do FastAF 5,1 M $10,17 mais 1.000 créditos $50,83 mais 1.000 créditos

No pacote Starter ($10 por 20.000 créditos), 1.000 scrapes simples custam $0,50, então o FastAF fica perto de $10,70 no Sonnet contra $19,75 do snapshot. É cerca da metade, e só de entrada. Uma leitura de página também fica no contexto em todos os turnos seguintes, a menos que você use cache ou a descarte, então uma execução longa a paga mais de uma vez. As definições de tools são um custo fixo por sessão: o Playwright MCP lista 25 tools (5.250 tokens), o servidor MCP do FastAF 15 (3.831).

Dá para deixar o Playwright MCP mais barato?

Dá, e o README do pacote diz isso: recomenda o Playwright CLI com skills para agentes de programação porque mantém as árvores de acessibilidade fora do contexto do modelo. Dentro do MCP, a flag --mobile (documentada como economia de tokens) reduziu a mediana de 9.874 para 6.367 aqui. Ela tem um porém. Na Wikipedia derrubou 24.931 tokens para 3.864 porque o layout mobile dobra as seções: 1 parágrafo no snapshot em vez de 22. No PyPI perdeu o campo de licença e reprovou na nossa verificação. Não leia um snapshot menor como o mesmo conteúdo.

Há outras alavancas na lista de tools que não medimos: browser_find devolve os nós que casam, com contexto, em vez da árvore toda; browser_snapshot aceita depth e filename; e browser_navigate já escreve em um arquivo em vez de no chat. Se você sabe qual parte da página precisa, elas vencem qualquer leitura da página inteira.

Quando o navegador é a ferramenta certa?

Quando a tarefa é interação: clicar por uma interface, preencher um formulário, um fluxo atrás de um login seu, uma página em que o próximo passo depende do que o último clique fez. Os refs do snapshot existem para isso, e o markdown não tem nada em que clicar.

Também tentamos uma pergunta do Stack Overflow e a deixamos fora da tabela: respondeu com uma página de verificação de bot (HTTP 403), e o FastAF devolveu 400 e 422 target_unavailable sem cobrança. As verificações de bot de um site são decisão do dono; o FastAF lê páginas públicas e não tenta passar por elas, e não comparamos ferramentas contra elas.

Apps em JavaScript são o caso intermediário. No crates.io o primeiro snapshot do Playwright teve 35 tokens porque o app ainda não tinha carregado; um segundo, depois de uma espera, deu 4.693. A chamada simples do FastAF devolveu 422, e a renderização com dynamic=true custou 5 créditos e 1.408 tokens em 6,3 s. Veja por que um fetch volta vazio e renderização de JavaScript. Uma correção: nossa primeira frase de verificação para o crates.io não casava com a forma como a página divide o texto, então a corrigimos e rodamos as duas ferramentas de novo nessa página.

Quando o trabalho é ler uma página pública e responder a partir dela, ler basta, e a API de web scraping ou a tool scrape_page faz isso em uma chamada. Para a configuração no Claude Code, no Cursor e no Codex, veja busca na web via MCP.

Como reproduzir isso?

import asyncio, os, sys, requests, tiktoken
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

enc = tiktoken.get_encoding("o200k_base")
tokens = lambda s: len(enc.encode(s, disallowed_special=()))

def fastaf_markdown(url, dynamic=False):
    params = {"url": url, "formats": "markdown"}
    if dynamic:
        params.update(dynamic="true", wait=3000)
    r = requests.get("https://api.fastaf.co/v1/scrape", params=params, timeout=120,
                     headers={"Authorization": f"Bearer {os.environ['FASTAF_API_KEY']}"})
    return r.text if r.status_code == 200 else "", r.headers.get("X-FastAF-Credits-Used")

async def playwright_snapshot(urls):
    # npm i @playwright/mcp@0.0.83   (the real server, over stdio, headless)
    server = StdioServerParameters(command="node", cwd=os.getcwd(),
        args=["node_modules/@playwright/mcp/cli.js", "--headless", "--isolated"])
    out = {}
    async with stdio_client(server) as (r, w), ClientSession(r, w) as s:
        await s.initialize()
        for url in urls:
            nav = await s.call_tool("browser_navigate", {"url": url})
            snap = await s.call_tool("browser_snapshot", {})
            text = lambda res: "\n".join(c.text for c in res.content if c.type == "text")
            out[url] = tokens(text(nav)) + tokens(text(snap))
    return out

urls = sys.argv[1:]
pw = asyncio.run(playwright_snapshot(urls))
for url in urls:
    md, credits = fastaf_markdown(url)
    print(f"{url}\n  playwright {pw[url]:>7,} tokens   fastaf {tokens(md):>7,} tokens ({credits} credit)")

Executado em 19 de outubro de 2026 contra duas das páginas acima, imprimiu:

https://www.gov.uk/vat-rates
  playwright   3,038 tokens   fastaf   1,392 tokens (1 credit)
https://news.ycombinator.com/
  playwright  13,647 tokens   fastaf   3,323 tokens (1 credit)

O snapshot do GOV.UK deu 3.038 aqui contra 3.378 na tabela porque as páginas mudam entre execuções. Nossa execução completa acrescentou as verificações das frases-agulha, uma nova tentativa depois de 3 s de espera para snapshots ralos, três repetições e o braço --mobile. O tempo todo rodamos o Chromium num notebook na Itália, e as URLs são as mesmas da tabela, então você pode repetir.

Resumindo

Em 11 páginas públicas, uma leitura com o Playwright MCP levou uma mediana de 9.874 tokens e o markdown 5.083: cerca da metade, não um centésimo. O snapshot gasta tokens com refs, papéis e URLs; o --mobile o enxuga mas pode perder conteúdo; e o snapshot ainda pode ganhar em páginas que são quase só estrutura. Use o navegador quando precisar clicar, digitar ou entrar em algo seu, e leia a página como markdown quando só precisar do que ela diz. Pegue 500 créditos grátis e rode o script nas páginas que o seu agente mais lê. Preços e limites estão na página de preços e na documentação.