Veilus
Navegador anti-detecção para várias contas em um computador: uma impressão digital e proxy por perfil, e automação que seu assistente de IA escreve e executa via MCP.
Documentação
Estas documentações descrevem o lançamento do Veilus após v0.2.1, que está por vir. Se você tem a v0.2.1, algumas telas e recursos (Datasets, Lixeira, o novo painel de perfil, muitas ferramentas MCP) ainda não estão na sua versão.
MCP (Model Context Protocol) é o padrão pelo qual ferramentas de LLM como Claude Code, Cursor e Claude Desktop se conectam a ferramentas externas — o Veilus fala esse protocolo via stdio, então um LLM pode importar proxies, criar e iniciar perfis, controlar a página de um perfil em execução, escrever e executar scripts Veilus Flow e agendá-los — em seu nome.
Assim como a API REST, isso exige que a API local esteja ativada primeiro, pela página API & MCP na barra lateral do aplicativo — essa página também gera o token que você precisará abaixo.
Conectando
O binário do aplicativo Veilus tem um subcomando mcp que fala MCP via stdio. O cliente precisa do caminho para esse binário e do seu token, passado como variável de ambiente VEILUS_API_TOKEN.
Claude Code
claude mcp add --scope user veilus -e VEILUS_API_TOKEN=<token> -- "<path to Veilus>" mcp
--scope user disponibiliza o Veilus em todas as pastas onde você abrir o Claude Code; sem isso, o Claude Code só vê o Veilus na pasta onde você executou o comando.
Cursor / Claude Desktop
Adicione isto à configuração do servidor MCP do cliente:
{
"mcpServers": {
"veilus": {
"command": "<path to Veilus>",
"args": ["mcp"],
"env": {
"VEILUS_API_TOKEN": "<token>"
}
}
}
}
A página API & MCP preenche o caminho real do binário e o token para você assim que você gerar um — copie o trecho de lá em vez de digitar manualmente.
Ferramentas
Perfis
Proxy
import_proxies
Crie um pool de proxies estático a partir de linhas de proxy (host:porta, host:porta:usuário:senha ou usuário:senha@host:porta). Prefixe uma linha com socks5:// para um proxy SOCKS5; http:// ou sem prefixo significa HTTP; https:// é rejeitado (TLS para o proxy não é suportado). Linhas inválidas são reportadas em rejected\ por número de linha (contando a partir de 1) e não bloqueiam as válidas; se nenhuma linha for válida, nada é criado. Retorna pool_id para create_profiles ou assign_proxy_pool. Senhas são armazenadas, mas nunca retornadas.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
lines | string[] | sim | Um proxy por elemento |
name | string | sim | |
type | string | não |
list_proxy_pools
Liste pools de proxies: pool\_id\, name\, kind\ (estático ou rotativo), entry\_count\ e countries\ detectados para seus IPs de saída. Nunca retorna credenciais.
test_proxy
Teste cada proxy de um pool agora: vivo ou morto, latência, IP de saída e seu país e fuso horário. Atualiza a geo em cache do pool, que create_profiles usa. Um proxy morto pode levar até cerca de 10 segundos.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
pool_id | string | sim | UUID do pool de proxies |
assign_proxy_pool
Atribua um pool de proxies a perfis existentes, um slot para cada. Recusa a chamada inteira (nada é atribuído) se qualquer perfil já tiver um proxy ou pool, listando-os; passe force: true para substituir. NÃO altera o fuso horário dos perfis: se o novo proxy estiver em outro país, launch_profile será bloqueado pela verificação de geo. Novos perfis devem receber seu pool por meio de create_profiles.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
force | boolean | não | Substituir um proxy existente. Padrão false |
pool_id | string | sim | UUID do pool de proxies |
profile_ids | string[] | sim |
Controle de página
navigate
Carregue uma URL na aba de um perfil EM EXECUÇÃO e aguarde o evento de carregamento (até 15 s); em caso de timeout, ele CONTINUA MESMO ASSIM e o resultado diz que a página ainda está carregando — então chame wait_for_element para o que você precisar antes de ler a página. O perfil já deve estar aberto — chame launch_profile primeiro; isso nunca o abre.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
profile_id | string | sim | UUID de um perfil em execução (launch_profile primeiro) |
url | string | sim |
snapshot
Snapshot de acessibilidade da página atual de um perfil em execução: uma linha por elemento com papel, nome e [id=N]; passe N como node_id para clicar ou digitar. Os IDs mudam quando a página muda — tire um novo snapshot após navegar ou clicar. Lista no máximo 150 elementos e 64 KiB; truncated: true significa que a página tem mais — use wait_for_element com um seletor CSS para alcançar um elemento que não está listado. Elementos dentro de iframes de mesma origem seguem uma linha --- iframe URL ---\ e funcionam com click e type como qualquer outro; um iframe de origem cruzada recebe uma linha (cross-origin …)\ com sua URL, mas seus elementos não são listados — navegue para essa URL para trabalhar dentro dele.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
profile_id | string | sim | UUID de um perfil em execução (launch_profile primeiro) |
click
Clique em um elemento da página de um perfil em execução por node_id com um mouse real: o ponteiro se move para um ponto dentro do elemento e então pressiona e solta. Falha se a página mudou desde o snapshot (tire um novo), se o elemento não tem caixa visível (oculto ou tamanho zero — clique em seu rótulo visível ou pai), ou se outro elemento o cobre (o erro o nomeia — feche ou role além dele primeiro). Um alerta/confirmação/prompt de JavaScript que a ação abre é respondido imediatamente: dialog\ "dismiss" (padrão, ou seja, Cancelar) ou "accept" (OK), com prompt\_text\ como a resposta digitada para um prompt; o resultado diz qual diálogo abriu e como foi respondido.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
dialog | string | não | |
node_id | integer | sim | node_id do snapshot ([id=N]) ou wait_for_element |
profile_id | string | sim | UUID de um perfil em execução (launch_profile primeiro) |
prompt_text | string | não |
type
Foque um elemento por node_id e digite texto nele, um evento de tecla por caractere (no máximo 5000 caracteres). Substitui o conteúdo atual do campo: o texto existente é removido antes de digitar. Se o resultado notar que o valor não pôde ser confirmado (campos mascarados, com limite de comprimento ou formatados automaticamente), verifique o campo com snapshot ou evaluate_js.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
node_id | integer | sim | node_id do snapshot ([id=N]) ou wait_for_element |
profile_id | string | sim | UUID de um perfil em execução (launch_profile primeiro) |
text | string | sim |
press_key
Pressione uma tecla nomeada na página de um perfil em execução: Enter, Tab, Escape, ArrowUp, ArrowDown, ArrowLeft, ArrowRight, Backspace, Delete ou Space. Se nenhuma entrada estiver focada, a ÚLTIMA entrada da página é focada primeiro. Para texto, use type\. Um alerta/confirmação/prompt de JavaScript que a ação abre é respondido imediatamente: dialog\ "dismiss" (padrão, ou seja, Cancelar) ou "accept" (OK), com prompt\_text\ como a resposta digitada para um prompt; o resultado diz qual diálogo abriu e como foi respondido.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
dialog | string | não | |
key | string | sim | |
profile_id | string | sim | UUID de um perfil em execução (launch_profile primeiro) |
prompt_text | string | não |
scroll
Role a página de um perfil em execução em amount\ pixels (1 a 20000) na direção cima, baixo, esquerda ou direita, com passos de roda do mouse na posição do ponteiro. Como uma roda real, uma área rolável sob o ponteiro rola em vez da página — após um clique dentro de tal área, role lá, ou clique fora dela primeiro. Em um perfil macOS, a distância varia alguns por cento em torno de amount\, como uma roda real; o resultado relata os pixels realmente rolados.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
amount | integer | sim | |
direction | string | sim | |
profile_id | string | sim | UUID de um perfil em execução (launch_profile primeiro) |
wait_for_element
Aguarde até que um seletor CSS corresponda a um elemento na página de um perfil em execução (verifica a cada 200 ms; timeout_ms de 1 a 30000, padrão 5000) e retorne seu node_id para click ou type. Use após navigate ou click para aguardar a próxima página.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
profile_id | string | sim | UUID de um perfil em execução (launch_profile primeiro) |
selector | string | sim | Seletor CSS |
timeout_ms | integer | não |
evaluate_js
Execute uma expressão JavaScript na página de um perfil em execução e retorne seu valor como text\, codificado em JSON (strings voltam entre aspas); promises são aguardadas. undefined\ volta como o texto (undefined)\, não JSON null\. Um erro lançado volta como texto começando com [JS Error] — este é um resultado normal de chamada, não uma falha de ferramenta. Resultados acima de 64 KiB são cortados e sinalizados com truncated: true. Um loop síncrono é interrompido PELA PRÓPRIA PÁGINA após cerca de 9 s; seu resultado também volta como texto comum [JS Error]. Uma promise que nunca resolve faz a chamada em si falhar após 10 s com um erro de timeout. Isso NÃO é uma sandbox: executa com todos os direitos da página conectada (lê cookies, envia requisições como o usuário). Um alerta/confirmação/prompt de JavaScript que a ação abre é respondido imediatamente: dialog\ "dismiss" (padrão, ou seja, Cancelar) ou "accept" (OK), com prompt\_text\ como a resposta digitada para um prompt; o resultado diz qual diálogo abriu e como foi respondido.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
dialog | string | não | |
expression | string | sim | |
profile_id | string | sim | UUID de um perfil em execução (launch_profile primeiro) |
prompt_text | string | não |
set_file
Anexe um arquivo a uma entrada de arquivo (, geralmente mostrada como um botão "Escolher Arquivo") da página de um perfil em execução por node_id, em vez de clicar nela — um clique abre o seletor de arquivos do sistema, que não pode ser controlado. Apenas arquivos dentro da pasta de uploads do aplicativo (~/.veilus/data/uploads) são permitidos: passe o nome do arquivo, ou um caminho absoluto dentro dessa pasta; qualquer outra coisa é recusada. Peça ao usuário para copiar o arquivo para lá primeiro.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
node_id | integer | sim | node_id do snapshot ([id=N]) ou wait_for_element |
path | string | sim | nome do arquivo dentro de ~/.veilus/data/uploads |
profile_id | string | sim | UUID de um perfil em execução (launch_profile primeiro) |
Script
list_scripts
Liste todos os scripts, do mais recente para o mais antigo, sem o código-fonte: scriptId\, name\, description\, version\, mode\ (raw\ ou dsl\), origin\ (mcp\ se um agente o escreveu, app\ se o usuário o fez), approved\ e updatedAt\. Verifique aqui antes de save_script para atualizar um script existente em vez de salvar uma duplicata.
save_script
Salve um script Playwright (TypeScript) no Veilus Flow. Sem script_id: cria um novo script; com script_id: substitui o código-fonte. Contrato - violações são rejeitadas com números de linha: (1) conectar com chromium.connectOverCDP(http://127.0.0.1:${process.env.VEILUS\_DEBUG\_PORT}\); (2) sem chromium.launch/launchPersistentContext; (3) usar browser.contexts()[0], não newContext(); (4) sem setUserAgent/setViewportSize - a identidade pertence ao perfil; (5) erros devem sair com código não zero: main().catch((e) => { console.error(e); process.exit(1); }); (6) importar apenas playwright e módulos nativos do Node; (7) terminar main() com await browser.close()\ - ele apenas desconecta do navegador do perfil e permite que o script saia; sem ele, a execução trava. Leia variáveis via process.env.VEILUS_VAR_<NAME> (nomes em UPPER_SNAKE_CASE); imprima o que precisar ver com console.log para stdout. Um script recém-salvo não é aprovado: run_script pode executá-lo (em no máximo 3 perfis), agendamentos aguardam até o usuário aprová-lo no aplicativo. name\ é usado apenas na criação; atualizar (com script_id) não renomeia, e apenas scripts salvos por um agente podem ser atualizados. Retorna scriptId\ (o id deste script — passe como script_id para get_script ou para save_script novamente), version\ e approved\.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
description | string | não | |
name | string | sim | |
script_id | string | não | UUID do script cujo código-fonte será substituído; omita para criar um novo script |
source | string | sim | O código-fonte TypeScript completo |
get_script
Leia o código-fonte e o estado de aprovação de um script Raw, para corrigi-lo e salvá-lo novamente com save_script. Retorna scriptId\, name\, description\, version\, source\, approved\ e origin\.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
script_id | string | sim |
run_script
Execute um script nos perfis fornecidos. Retorna a execução IMEDIATAMENTE, sem aguardar a conclusão; seu id\ é o run_id para get_run_result.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
headless | boolean | não | Inicia os perfis da execução em modo headless, sem janela — a mesma inicialização do launch_profile com headless\ (veja lá): a impressão digital do perfil permanece inalterada. Padrão false. |
profile_ids | string[] | sim | UUIDs dos perfis nos quais executar |
script_id | string | sim | UUID do script |
variables | object | não | Variáveis para o script, lidas no script como process.env.VEILUS_VAR_<NAME> |
compile_script
Compile um script DSL de arrastar e soltar em código executável. Não o executa. Agentes que escrevem scripts devem usar save_script em vez disso.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
dsl | object | sim | Corpo do script DSL |
target | string | não | Alvo da compilação |
Lote
run_batch
Execute um script APROVADO em muitos perfis de verdade. Retorna a execução IMEDIATAMENTE; seu id\ é o run_id para get_run_result. Diferente de run_script (um teste em no máximo 3 perfis, sem necessidade de aprovação), o script deve ter sido aprovado pelo usuário em Veilus → Flow, caso contrário a chamada é recusada. Um id de perfil que não existe é contado como um perfil com falha da execução, não rejeitado (diferente de create_schedule, que recusa ids desconhecidos com 404). concurrency (padrão 3, 1-16, limitado pelo max\ de get_capacity) é quantos perfis executam ao mesmo tempo; stagger_ms (padrão 1500, 0-600000, ou seja, 10 minutos) é a pausa entre inicializações; use get_capacity para escolher.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
concurrency | integer | não | |
profile_ids | string[] | sim | |
script_id | string | sim | UUID de um script aprovado |
stagger_ms | integer | não | |
variables | object | não | Variáveis para esta execução, lidas como process.env.VEILUS_VAR_<NAME> |
get_capacity
Quantos navegadores estão abertos (ativos), aguardando uma vaga (na fila) e permitidos ao mesmo tempo (máximo) nesta máquina. Use para escolher a concorrência do run_batch.
Agendamentos
create_schedule
Crie um agendamento que executa um script APROVADO nos perfis fornecidos em horários definidos. O script já deve ter sido aprovado pelo usuário em Veilus → Flow: um script não aprovado é recusado agora, não ignorado depois. schedule_type: interval (interval_minutes, com interval_unit em minutos ou segundos, pelo menos 5 segundos), daily (daily_hour e daily_minute, horário local do computador), weekly (daily_hour, daily_minute e weekly_day, 0 = domingo), cron (cron_expr, 5 campos) ou once (run_at, um horário futuro RFC 3339 com offset; o agendamento executa uma vez e depois se desativa). concurrency (padrão 1, 1-16) e stagger_ms (padrão 0, 0-600000, ou seja, 10 minutos) se aplicam a cada execução. Retorna o agendamento, incluindo nextRunAt.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
concurrency | integer | não | |
cron_expr | string | não | |
daily_hour | integer | não | |
daily_minute | integer | não | |
enabled | boolean | não | |
headless | boolean | não | Inicia os perfis da execução em modo headless, sem janela — a mesma inicialização do launch_profile com headless\ (veja lá): a impressão digital do perfil permanece inalterada. Padrão false. |
interval_minutes | integer | não | |
interval_unit | string | não | |
name | string | sim | |
profile_ids | string[] | sim | |
run_at | string | não | RFC 3339 com offset, ex.: 2026-10-04T09:00:00+07:00; obrigatório para once |
schedule_type | string | sim | |
script_id | string | sim | UUID de um script aprovado |
stagger_ms | integer | não | |
weekly_day | integer | não |
list_schedules
Liste todos os agendamentos: seu script, perfis alvo, horário, flag de ativação e horários da próxima e última execução.
set_schedule_enabled
Ative ou desative um agendamento. Ativá-lo recalcula a próxima execução a partir de agora e exige que seu script ainda esteja aprovado; desativá-lo mantém o agendamento e seu histórico de execuções.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
enabled | boolean | sim | |
schedule_id | string | sim | UUID do agendamento |
run_schedule_now
Execute um agendamento uma vez agora, sem aguardar o temporizador. Retorna a execução IMEDIATAMENTE; seu id\ é o run_id para get_run_result. Recusado enquanto o agendamento já tiver uma execução em andamento, ou se seu script não estiver aprovado.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
schedule_id | string | sim | UUID do agendamento |
Monitoramento
list_runs
Liste as execuções mais recentes, das mais novas para as mais antigas: status e contagens de perfis, sem detalhes por perfil (get_run_result tem isso). Sem schedule_id, lista execuções de todos os agendamentos e de run_script e run_batch. limit tem padrão 20, no máximo 100.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
limit | integer | não | |
schedule_id | string | não | Apenas execuções deste agendamento |
get_run_result
Resultado de uma execução por run\_id\ — use após chamar run_script.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
run_id | string | sim | UUID retornado por run_script |
Conjuntos de dados
create_dataset
Crie um conjunto de dados: uma tabela armazenada no Veilus que scripts aprovados leem por perfil. Modo fixed\: cada perfil recebe UMA linha para contas boas; suas colunas chegam como process.env.VEILUS_VAR_<COLUMN>. Modo consume\: cada execução pega rows\_per\_run\ (1-50, padrão 1) linhas não utilizadas; uma execução com falha as devolve, uma execução bem-sucedida as marca como usadas; elas chegam como VEILUS_VAR_ROWS (array JSON de {COLUNA: valor}) e, quando rows_per_run é 1, também uma variável por coluna. VEILUS_VAR_ROW_INDEX é o número da linha. Colunas são UPPER_SNAKE_CASE; ROWS, ROW_INDEX, PROFILE_ID, RUN_ID e DEBUG_PORT são reservadas. Marque uma coluna como secret: true\ para senhas: ela é armazenada e fornecida a scripts aprovados, mas nenhuma ferramenta a retorna. Linhas ruins são relatadas em rejected\ por número de linha (a partir de 1). Retorna datasetId\.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
columns | object[] | sim | |
mode | string | sim | |
name | string | sim | |
rows | object[] | não | Um objeto por linha, com chave pelo nome da coluna; todo valor deve ser uma string — converta números e datas em texto antes de enviar |
rows_per_run | integer | não |
append_dataset_rows
Adicione linhas a um conjunto de dados, no mesmo formato do rows\ de create_dataset. Linhas ruins são relatadas em rejected\ por número de linha e não bloqueiam as boas.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
dataset_id | string | sim | UUID do conjunto de dados |
rows | object[] | sim | Um objeto por linha, com chave pelo nome da coluna; todo valor deve ser uma string — converta números e datas em texto antes de enviar |
list_datasets
Liste conjuntos de dados: id, nome, modo, colunas com sua flag de segredo, rowsPerRun, contagens de linhas (total e atribuídas para fixo; disponíveis, reservadas e usadas para consumo) e quantos perfis usam cada um. Nunca retorna valores de linhas.
get_dataset_rows
Leia as linhas de um conjunto de dados em ordem: limit\ linhas (padrão 100, no máximo 500) a partir de offset\. Cada linha tem seu índice, seus valores e, para um conjunto fixo, o perfil ao qual está atribuída; para um conjunto de consumo, seu estado. Colunas secretas são sempre omitidas de values\.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
dataset_id | string | sim | UUID do conjunto de dados |
limit | integer | não | |
offset | integer | não |
assign_dataset
Atribua um conjunto de dados a perfis existentes. Um conjunto fixo vai para o slot de Identidade de cada perfil e dá a ele uma linha não atribuída (menor índice primeiro); perfis sem linha são nomeados em withoutRow\ e não recebem nada — nunca compartilhe uma conta entre perfis. Um conjunto de consumo vai para o slot de Conteúdo. Recusa a chamada inteira se um perfil já tiver um conjunto de dados diferente nesse slot, a menos que force: true; recusa nomes de colunas que também existam no conjunto de dados no outro slot do perfil. Toda execução posterior de um script APROVADO nesses perfis carrega os dados; agendamentos e run_batch não precisam de novo campo.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
dataset_id | string | sim | UUID do conjunto de dados |
force | boolean | não | Substitui um conjunto de dados já no slot. Padrão false |
profile_ids | string[] | sim |
unassign_dataset
Remova um conjunto de dados dos perfis. Para um conjunto fixo, suas linhas voltam a ficar não atribuídas. Ids de perfis que não existem mais são aceitos, para que linhas mantidas por perfis excluídos possam ser liberadas.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
dataset_id | string | sim | UUID do conjunto de dados |
profile_ids | string[] | sim |
reset_dataset_rows
Para um conjunto de consumo: coloque toda linha usada de volta como disponível, para que execuções as peguem novamente. Retorna quantas linhas foram alteradas.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
dataset_id | string | sim | UUID do conjunto de dados |