PageWatch
Extraia preços, listas e tabelas de páginas web públicas e receba alertas de alterações via RSS, ICS ou webhooks. Plano gratuito além de x402 pagamento por chamada.
Servidor MCP hospedado
npx add-mcp 'https://pagewatch.erikssonanton2001.workers.dev/mcp'Instala no Claude Code, Codex, Cursor e outros
Documentação
PageWatch: extração de páginas estáticas (preço, lista, tabela, eventos) + monitoramento de alterações em Cloudflare Workers, com MCP e x402
- JavaScript 100%
Transforme páginas web públicas em dados e seja avisado quando elas mudarem.
O PageWatch roda como um único Cloudflare Worker no plano gratuito (D1 para armazenamento, um gatilho cron). Ele lê uma página, extrai o que você pedir (um preço, uma lista de itens, uma tabela, um calendário de eventos, um hash de conteúdo) e pode repetir isso em um agendamento e reportar alterações por meio de um feed RSS, um log de eventos JSON, um calendário ICS ou um webhook assinado.
Somente HTML estático e JSON. Não há renderização de JavaScript, login ou cookies. Páginas que constroem seu conteúdo no navegador retornarão pouco ou nada. JSON-LD, Open Graph e microdados são lidos.
Para que as pessoas usam
- Acompanhar uma página de produto e receber uma mensagem quando o preço cair (modo preço, webhook ou RSS).
- Transformar a página de eventos de um clube em um calendário que você pode assinar (modo eventos, ICS).
- Manter uma lista de vagas de emprego ou lançamentos e ver o que foi adicionado ou removido (modo lista).
- Notar quando um concorrente muda seus preços ou página de destino (modo página: título, cabeçalhos, hash de conteúdo).
- Deixar um agente ou um fluxo n8n/Zapier chamar uma URL e receber JSON de volta.
Início rápido
Extração única (grátis, 30 por dia por cliente):
curl -G 'https://pagewatch.erikssonanton2001.workers.dev/v1/extract' \
--data-urlencode 'url=https://shop.example/product/1' -d mode=price
Uma lista como CSV:
curl -G 'https://pagewatch.erikssonanton2001.workers.dev/v1/extract' \
--data-urlencode 'url=https://example.org/jobs' -d mode=list \
--data-urlencode 'selector=li.job' \
--data-urlencode 'fields={"title":"h3","link":"a@href"}' -d format=csv
Acompanhar uma página (grátis: verifica no máximo a cada 60 minutos, 3 monitores ativos por cliente, 30 dias):
curl -X POST 'https://pagewatch.erikssonanton2001.workers.dev/v1/monitors' \
-H 'content-type: application/json' \
-d '{"url":"https://shop.example/product/1","mode":"price","interval_minutes":360,
"webhook_url":"https://hooks.example/pagewatch"}'
A resposta contém o id do monitor, um manage_token e (com um webhook) um webhook_secret. Ambos são mostrados uma vez. Leia as alterações em /m/<id>/feed.rss, /m/<id>/events.json, /m/<id>/latest.json e, para o modo eventos, /m/<id>/calendar.ics. Qualquer pessoa que conheça o id pode ler esses dados, então o id tem 128 bits de aleatoriedade.
Gerencie um monitor com o token:
curl -X POST 'https://pagewatch.erikssonanton2001.workers.dev/v1/monitors/<id>/check-now' -H 'Authorization: Bearer <manage_token>'
curl -X POST 'https://pagewatch.erikssonanton2001.workers.dev/v1/monitors/<id>/renew' -H 'Authorization: Bearer <manage_token>'
curl -X DELETE 'https://pagewatch.erikssonanton2001.workers.dev/v1/monitors/<id>' -H 'Authorization: Bearer <manage_token>'
check-now é limitado a uma vez a cada 10 minutos por monitor.
Modos de extração
| Modo | Necessita | Retorna |
|---|---|---|
| text | seletor | texto da primeira correspondência (ou todas com all=true) |
| attr | seletor, attr | valor do atributo |
| list | seletor, campos | array de objetos; os valores dos campos são css ou css@attr |
| table | seletor opcional, tableIndex | cabeçalhos e linhas (CSV suportado) |
| price | seletor opcional | preço, moeda, disponibilidade, nome, fonte (JSON-LD, Open Graph, microdados, texto) |
| events | nenhum | eventos JSON-LD (JSON, CSV ou ICS) |
| page | nenhum | título, descrição, canônico, h1, contagem de palavras, hash de conteúdo |
| links | match opcional, sameHost | links absolutos com texto |
| json | jsonpath opcional | valor em uma expressão JSONPath-lite como $.a.b[0].c |
Os seletores suportam tag, classe, id, operadores de atributo, combinadores descendente e filho, listas separadas por vírgula, :first-child, :nth-child(n) e :not(simple). Os monitores usam por padrão o modo page.
Webhooks
Um POST por alteração com JSON {monitor_id, url, kind, old, new, at, summary} e o cabeçalho X-PageWatch-Signature: sha256=<hex>, o HMAC-SHA256 do corpo bruto com a chave do webhook_secret do monitor. As URLs de webhook devem ser https e passar pelas mesmas verificações de SSRF que as URLs de página. O timeout é de 5 segundos, redirecionamentos não são seguidos, e uma entrega com falha é tentada novamente em execuções cron posteriores, três tentativas no total. Depois disso, o monitor é marcado como webhook_failed e para de enviar até ser renovado. O feed RSS e o events.json continuam sendo a fonte da verdade. Um evento broken (monitoramento interrompido após 10 verificações com falha) é entregue da mesma forma.
Limites
| O quê | Limite |
|---|---|
| Tamanho da página | 600 KB por página, páginas maiores são rejeitadas (422) |
| Extrações gratuitas | 30 por dia por cliente, depois 429 com instruções para o endpoint pago |
| Monitores gratuitos | 3 ativos por cliente, 30 dias (renováveis), intervalo de 60 minutos ou mais (padrão 360) |
| Monitor Pro | 30 dias, intervalo a partir de 15 minutos (padrão 15), até 5 URLs de webhook, sem limite por cliente |
| Capacidade global | 400 monitores ativos (MAX_ACTIVE) |
| Polidez | robots.txt respeitado (cache de 1 hora); verificações agendadas buscam um host no máximo uma vez a cada 15 minutos |
| Requisições | http/https, portas 80/443, apenas nomes DNS públicos; sem credenciais, sem literais de IP |
| Proteção de loop | este serviço, *.workers.dev e *.pages.dev são recusados como alvos e webhooks |
| Entrada | seletor de até 300 caracteres, até 20 campos, corpos JSON de até 8 KB |
| Falhas | 3 falhas seguidas desaceleram um monitor (dobrando, até 24 h); 10 o interrompem com um evento broken |
| Cron | a cada 15 minutos, até 20 monitores por execução dentro de 45 requisições de saída e 45 declarações D1 |
Endpoints pagos (x402)
Dois endpoints são pagos por chamada em USDC na Base com x402. Sem conta, sem chave de API. Uma requisição não paga retorna HTTP 402 com um cabeçalho PAYMENT-REQUIRED. O pagamento é liquidado apenas quando o status da resposta é inferior a 400, então erros de validação, bloqueios de robots.txt e falhas upstream são gratuitos.
| Endpoint | Preço |
|---|---|
GET /v1/pro/extract | $0,002, sem limite diário |
POST /v1/pro/monitors | $0,25, 30 dias, verificações a cada 15 minutos, até 5 webhooks |
OpenAPI com x-payment-info: /openapi.json. Listagem: /.well-known/x402. Documentação para agentes: /llms.txt.
MCP
POST /mcp fala MCP sobre HTTP transmissível (JSON-RPC 2.0). Ferramentas: extract_page, watch_page, get_changes. As duas primeiras seguem as regras do nível gratuito; com paid: true elas retornam os requisitos de pagamento x402 do endpoint pago (ou executam a chamada quando um cabeçalho PAYMENT-SIGNATURE é enviado).
Privacidade
O PageWatch armazena a configuração de cada monitor, o valor extraído mais recente e um log de alterações, até que o monitor seja excluído ou tenha expirado por 30 dias. Endereços IP nunca são armazenados: as cotas usam um hash SHA-256 com sal que gira diariamente, e o limite de monitores por cliente usa um hash com sal do IP criador (defina o segredo SALT; sem ele, um sal fixo de fallback é usado e os hashes são tão privados quanto esse sal). O token de gerenciamento é armazenado apenas como um hash SHA-256. O segredo do webhook é armazenado para que as entregas possam ser assinadas. Não monitore páginas cujo conteúdo você não possa compartilhar: os feeds são públicos para qualquer pessoa com o id.
Limites honestos
- Sem renderização de JavaScript, sem login ou páginas com paywall, sem bypass de proteção contra bots.
- As verificações são de melhor esforço em um plano gratuito. Uma execução cron lida com cerca de uma dúzia de monitores, então com muitos monitores devidos algumas verificações atrasam (elas são pegas na próxima execução).
- Seletores quebram quando um site muda. Monitores que continuam falhando desaceleram e eventualmente param.
- O plano gratuito permite poucas declarações D1 por invocação; o trabalho cron conta as suas próprias e para cedo.
- O parser de robots.txt segue o RFC 9309 para Allow/Disallow, curingas e correspondência mais longa; ele ignora Crawl-delay.
- Um webhook ou alvo em um nome público que resolve para um endereço privado não pode ser detectado de dentro de um Worker; o Cloudflare não roteia fetches de Worker para faixas privadas, o que é a proteção real nesse caso.
- O limite por cliente é verificado antes da inserção, não em uma transação, então uma rajada de requisições paralelas pode excedê-lo ligeiramente.
Desenvolvimento
npm test # builds, then runs node --test (no network; fakes for fetch, clock, database, facilitator)
npm run build # dist/worker.js, fails if the bundle imports node: modules
npm run make-deploy # writes deploy-fn.js (one async function for the Cloudflare MCP execute tool)
node scripts/migrate-sql.mjs # prints schema.sql
Layout: src/index.js (fiação), src/routes/*, src/service/* (ciclo de vida do monitor, verificações, cron, webhooks, cotas), src/db/* (adaptador D1 e um gêmeo em memória usado nos testes), src/extract/* (mecanismo de extração puro), src/lib/* (proteção contra SSRF, fetch limitado, robots.txt), src/docs.js e src/paid-routes.js (tabelas de rotas).
Ambiente: PAY_TO, NETWORK, FACILITATOR_URL, PUBLIC_BASE_URL, opcionais MAX_ACTIVE e SALT; binding D1 DB.
Licenciado sob MIT.