A Browser API entrega sessões de navegador headless (Chromium) rodando na infraestrutura da Veloz, com stealth garantido em toda sessão, prontas para você controlar via Playwright com chromium.connectOverCDP(...). Use para automação, scraping, testes end-to-end, geração de PDFs/screenshots ou qualquer fluxo que precise de um navegador real e isolado, sem manter Chromium na sua própria infraestrutura.
Você cria uma sessão, recebe uma connectUrl (um endpoint CDP sobre WebSocket) e conecta com o seu próprio playwright/playwright-core. A Veloz cuida do provisionamento, do isolamento e do encerramento.
Nota: a Browser API está em early access (acesso antecipado) e é liberada por organização. Se a seção Sessões de navegador ainda não aparece no seu dashboard, peça acesso ao suporte: abra um chamado em Suporte no dashboard ou rode
veloz support create --subject "Acesso à Browser API" --message "Quero testar a Browser API na minha organização.".
Comece em 2 minutos
O caminho mais curto até um navegador rodando na Veloz: sem escolher engine e sem opção nenhuma.
1. Crie uma chave
No dashboard, abra Sessões de navegador → Chaves de API, crie uma chave e copie (ela aparece uma única vez). No terminal:
export VELOZ_BROWSER_TOKEN=bk_live_sua_chave2. Rode o primeiro navegador
npm install @onveloz/browser playwright-coreSalve como inicio.mjs:
import { Onveloz } from "@onveloz/browser";
import { chromium } from "playwright-core";
const ov = new Onveloz(); // lê VELOZ_BROWSER_TOKEN do ambiente
const browser = await chromium.connectOverCDP(await ov.connect());
const page = await browser.contexts()[0].newPage();
await page.goto("https://example.com");
console.log(await page.title());
await page.waitForTimeout(30_000); // 30 s para assistir no dashboard
await browser.close(); // ao desconectar, a sessão é encerradanode inicio.mjs
# Example Domain3. Assista ao vivo
Enquanto o script espera, abra Sessões de navegador no dashboard. A sessão aparece como Ativa: clique em Ao vivo para ver a tela do navegador em tempo real. Quando o script fecha o navegador, a sessão é encerrada.
Pronto. As seções abaixo detalham o SDK, a API REST, a CLI, a escolha do navegador e as opções de cada sessão.
Chaves de API
Toda chamada usa uma chave bk_live_* no cabeçalho Authorization:
Authorization: Bearer bk_live_sua_chave
Gere e revogue chaves na seção Sessões de navegador → Chaves de API do dashboard. A chave é vinculada à sua organização e concede acesso para criar e controlar sessões.
Segurança: a chave é exibida uma única vez na criação. Copie nesse momento, trate como senha, defina em variável de ambiente (
VELOZ_BROWSER_TOKEN) e nunca commite no Git.
SDK @onveloz/browser
A forma recomendada de integrar a partir de Node. O SDK não embute o Playwright: ele entrega a connectUrl e você conecta com o seu próprio cliente.
npm install @onveloz/browser playwright-coreDefina o token no ambiente:
VELOZ_BROWSER_TOKEN=bk_live_sua_chave
Conectar para acordar (uma linha)
Nenhuma sessão é criada de antemão: um navegador quente é provisionado quando você abre o socket CDP e encerrado quando você desconecta. O limite de simultaneidade é checado no momento da conexão.
import { Onveloz } from "@onveloz/browser";
import { chromium } from "playwright-core";
const ov = new Onveloz(); // lê VELOZ_BROWSER_TOKEN do ambiente
const browser = await chromium.connectOverCDP(await ov.connect());
const page = await browser.contexts()[0].newPage();
await page.goto("https://exemplo.com");
console.log(await page.title());
await browser.close(); // ao desconectar, o navegador é encerradoSessão explícita
Quando você precisa do ciclo de vida na mão (criar agora, conectar depois, listar, encerrar):
import { Onveloz } from "@onveloz/browser";
import { chromium } from "playwright-core";
const ov = new Onveloz();
// O provisionamento roda fora da requisição, então a sessão nasce PENDING.
const session = await ov.sessions.create();
// Aguarda ficar RUNNING com connectUrl disponível (polling interno).
const ready = await ov.sessions.waitUntilReady(session.id);
const browser = await chromium.connectOverCDP(ready.connectUrl!);
const page = await browser.contexts()[0].newPage();
await page.goto("https://exemplo.com");
await browser.close();
await ov.sessions.close(session.id);Métodos disponíveis no namespace ov.sessions:
| Método | Descrição |
|---|---|
create(config?, opts?) |
Cria uma sessão (nasce PENDING, connectUrl: null). opts.idempotencyKey evita duplicar |
get(id) |
Busca uma sessão e seu connectUrl quando RUNNING |
list({ activeOnly? }) |
Lista as sessões da organização |
close(id) |
Encerra uma sessão |
liveView(id) |
Gera a URL de visualização ao vivo (sob demanda) |
waitUntilReady(id, opts?) |
Faz polling até RUNNING ou lança em estado terminal/timeout |
No namespace ov.engines:
| Método | Descrição |
|---|---|
list() |
Lista os engines e se cada um já inicia sessões (available) |
options(id) |
Configurações que um engine aceita em settings e suas listas |
E no cliente ov:
| Método | Descrição |
|---|---|
connect(config?) |
Gera uma connectUrl de conectar-para-acordar (sem criar sessão) |
token(config?) |
Alias de connect() |
Para apontar a um ambiente alternativo, passe { apiUrl } ou defina VELOZ_BROWSER_API.
API REST
Para linguagens fora de Node, fale direto com a API. Base: https://platform.onveloz.com/api/browser. Todas as chamadas exigem o cabeçalho Authorization: Bearer bk_live_*.
| Método e rota | Descrição |
|---|---|
POST /v1/sessions |
Cria uma sessão (provisionamento roda em segundo plano) |
GET /v1/sessions |
Lista as sessões da organização (?activeOnly=true) |
GET /v1/sessions/:id |
Busca uma sessão e seu connectUrl |
GET /v1/sessions/:id/live-view |
Gera a URL de visualização ao vivo (sob demanda) |
DELETE /v1/sessions/:id |
Encerra uma sessão |
POST /v1/connect-token |
Gera uma connectUrl de conectar-para-acordar |
GET /v1/engines |
Lista os engines e se cada um já inicia sessões |
GET /v1/engines/:id/options |
Configurações que um engine aceita em settings e suas listas |
Criar e conectar
# 1) Cria a sessão: ela nasce PENDING.
curl -X POST https://platform.onveloz.com/api/browser/v1/sessions \
-H "Authorization: Bearer bk_live_sua_chave" \
-H "Content-Type: application/json" \
-d '{ "timeoutSec": 300 }'
# → { "id": "...", "status": "PENDING", "connectUrl": null, "expiresAt": "..." }
# 2) Faça polling até connectUrl aparecer (sessão RUNNING).
curl https://platform.onveloz.com/api/browser/v1/sessions/SESSION_ID \
-H "Authorization: Bearer bk_live_sua_chave"
# → { ..., "status": "RUNNING", "connectUrl": "wss://.../v1/connect?token=...",
# "liveViewPath": "/v1/sessions/SESSION_ID/live-view" }Depois, conecte ao connectUrl com qualquer cliente CDP (Playwright, Puppeteer, ou o protocolo cru).
Estados da sessão
| Status | Descrição |
|---|---|
PENDING |
Provisionando, ainda sem connectUrl |
RUNNING |
Pronta, com connectUrl disponível para conectar |
RELEASED |
Encerrada (por você ou por inatividade) |
EXPIRED |
Atingiu o TTL e foi encerrada |
FAILED |
Falhou ao provisionar |
Pelo terminal e por agentes de IA
A CLI da Veloz cobre o mesmo fluxo. Os comandos usam o login da CLI (veloz login), sem chave bk_live_*:
| Comando | O que faz |
|---|---|
veloz browser engines |
Lista os engines e se cada um já inicia sessões |
veloz browser options <engine> |
Mostra as configurações que o engine aceita |
veloz browser create |
Cria uma sessão (--proxy-id usa um proxy salvo) |
veloz browser list |
Lista as sessões da organização |
veloz browser stop <id> |
Encerra uma sessão |
veloz browser connect-url |
Gera uma URL de conexão para o seu cliente CDP |
veloz browser proxies |
Lista, mostra, salva, altera e exclui proxies salvos (list, get, create, update, delete) |
Rode veloz browser <comando> --help para ver as flags de cada comando.
Para agentes de IA, veloz mcp add registra a CLI como servidor MCP no Claude Code, no Cursor e em outros editores. As mesmas operações viram ferramentas: browser_engines, browser_options, browser_create, browser_list, browser_stop, browser_connect_url e, para os proxies salvos, browser_proxies_list, browser_proxies_get, browser_proxies_create, browser_proxies_update e browser_proxies_delete. A senha de um proxy nunca é argumento de ferramenta: ela vem de VELOZ_BROWSER_PROXY_PASSWORD no ambiente do servidor MCP ou do prompt da CLI. Veja MCP & Agentes IA.
Stealth
Toda sessão já roda com as proteções anti-detecção ativas: fingerprint coerente (locale e timezone alinhados com a geo de saída), WebGL funcional via a stack GL nativa do Linux (Mesa/llvmpipe) e supressão de vazamentos do protocolo. O stealth é garantido e não configurável: não há nada para ligar, e não é possível desligar.
Sobre o WebGL: as sessões rodam em máquinas sem GPU dedicada, então a renderização é por software. Isso é proposital. O UNMASKED_RENDERER reportado é o mesmo de qualquer servidor Linux sem GPU, que é justamente o que somos, em vez do SwiftShader que denuncia um Chrome headless. Desligar o WebGL seria pior: getContext("webgl") retornaria null, um sinal muito mais chamativo.
Use o seu próprio proxy
Por padrão o egresso é direto. Para sair por um proxy, traga o seu: informe o gateway em proxyServer (e credenciais, se houver). O proxyCountry mantém o fingerprint de stealth coerente com a geo de saída do seu proxy.
const session = await ov.sessions.create({
proxyServer: "http://gateway.seu-proxy.com:8080", // http, https ou socks5
proxyUsername: "usuario", // opcional (omita para proxy autorizado por IP)
proxyPassword: "senha", // opcional
proxyCountry: "US", // opcional: país de saída do seu proxy
});As credenciais são criptografadas em repouso e nunca retornadas nas respostas da API. O proxy próprio vale em create() e em connect(). Em connect(), as credenciais ficam guardadas no servidor até a URL expirar, e a URL só leva uma referência a elas.
Proxies salvos
Salve um proxy uma vez, com um nome, e use pelo id em proxyId. O id vale em create() e em connect(), sem mandar as credenciais em cada requisição.
const proxy = await ov.proxies.create({
name: "residencial-us", // único na organização
server: "http://gateway.seu-proxy.com:8080", // http, https ou socks5, sem usuário e senha
username: "usuario", // opcional
password: "senha", // opcional
country: "US", // opcional: país de saída do proxy
});
const session = await ov.sessions.create({ proxyId: proxy.id });
const browser = await chromium.connectOverCDP(await ov.connect({ proxyId: proxy.id }));No SDK, ov.proxies tem list(), get(id), create(input), update(id, patch) e delete(id). Na API REST:
| Método | Rota | O que faz |
|---|---|---|
GET |
/v1/proxies |
Lista os proxies salvos da organização ({ "proxies": [ ... ] }) |
POST |
/v1/proxies |
Salva um proxy |
GET |
/v1/proxies/:id |
Lê um proxy salvo |
PATCH |
/v1/proxies/:id |
Altera só os campos enviados; null em username, password ou country limpa |
DELETE |
/v1/proxies/:id |
Exclui o proxy salvo |
curl -X POST https://platform.onveloz.com/api/browser/v1/proxies \
-H "Authorization: Bearer bk_live_sua_chave" \
-H "Content-Type: application/json" \
-d '{ "name": "residencial-us", "server": "http://gateway.seu-proxy.com:8080", "username": "usuario", "password": "senha", "country": "US" }'
# → { "id": "...", "name": "residencial-us", "server": "http://gateway.seu-proxy.com:8080",
# "username": "usuario", "hasPassword": true, "country": "US", "lastCheck": null, ... }- A senha nunca volta. As credenciais são criptografadas em repouso. As respostas trazem
serversem credenciais,usernameehasPassword, nunca a senha. - Um ou outro.
proxyIdnão vai junto comproxyServer,proxyUsername,proxyPasswordouproxyCountry: a requisição volta400. O país da sessão vem do proxy salvo. - Só a sua organização. Um id de outra organização volta
404, igual a um id que não existe. Um nome repetido volta409, assim como passar de 100 proxies salvos. - Último teste. Cada sessão aberta por um proxy salvo guarda em
lastChecko que o navegador viu na saída (IP, país, cidade, latência) e a hora emlastCheckedAt. Quando o proxy falha,lastChecktraz{ "ok": false, "cause": "proxy_failed" }. Trocar servidor, usuário ou senha apaga o último teste. - Alterar e excluir. Uma URL de
connect()usa o proxy como ele estiver na hora de conectar. Excluir o proxy faz essas URLs pararem de funcionar; sessões já criadas com ele seguem até o fim.
Escolher o navegador
Cada sessão roda um engine: o navegador e a camada de automação que o controla. Sem engine, a sessão usa o engine padrão (patchright), como no Comece em 2 minutos.
A lista de engines cresce com o tempo. Só iniciam sessões os engines que GET /v1/engines marca com available: true. Os marcados com available: false aparecem no catálogo, mas ainda não podem ser criados: o pedido volta 400 com o código unavailable.
Descobrir engines
curl https://platform.onveloz.com/api/browser/v1/engines \
-H "Authorization: Bearer bk_live_sua_chave"
# → { "engines": [ { "id": "...", "label": "...", "available": true, ... } ] }const engines = await ov.engines.list();
const prontos = engines.filter((engine) => engine.available).map((engine) => engine.id);Cada engine traz:
| Campo | Descrição |
|---|---|
id |
O valor de engine ao criar a sessão |
label |
Nome de exibição |
available |
true quando o engine já inicia sessões (sem opções) |
experimental |
Engine em fase experimental |
limitations |
O que o engine não faz que os outros fazem, em uma frase; null quando não há limite. Aparece também no dashboard, ao escolher o engine |
protocol |
Como o cliente controla a sessão: cdp (Chrome DevTools Protocol, use connectOverCDP) ou playwright (protocolo do Playwright) |
capabilities |
Um booleano por recurso que o engine aceita, como headful, headless, locale, timezoneId, userAgent, flags, extensions, initScripts, geolocation e proxy |
headlessDefault |
O modo do navegador quando você omite options.headless |
os |
Valores aceitos em options.os |
proxySchemes |
Esquemas de proxy aceitos (http, https, socks5); vazio quando o engine não aceita proxy |
browser |
Navegador padrão e versão (version pode ser null) |
executables |
Builds que options.executable escolhe, o padrão primeiro; vazio quando o engine tem um só |
license |
Licença do engine |
Engines experimentais
Os engines com experimental: true iniciam sessões, mas têm limites que os outros não têm. O campo limitations de cada um resume esses limites:
cloakbrowseré controlado por CDP (connectOverCDP) e não repassa ao cliente as mensagens do console da página, por decisão do fabricante do navegador. Por issopage.setContentnão termina e os eventospage.on('console')epage.on('pageerror')não disparam. Navegar, ler e preencher elementos, executar scripts e capturar a tela funcionam. Os substitutos estão logo abaixo da lista.camofoxroda o Camoufox, um Firefox, pelo protocolo do Playwright (protocol: "playwright"). Conecte comfirefox.connect()do Playwright 1.59.x. Com outra versão, a conexão é recusada na hora com uma mensagem que diz qual versão usar. A visualização ao vivo não está disponível para ele.obscurasó roda em headless e é controlado por CDP (connectOverCDP). Navegar (page.goto), executar scripts (page.evaluate) e capturar a tela (Page.captureScreenshot) funcionam.page.setContente a visualização ao vivo não estão disponíveis.
No cloakbrowser, troque page.setContent por document.write e leia o console por um script que roda antes da página:
// Registre antes de navegar: guarda o console de cada página em window.__logs
await page.addInitScript(() => {
window.__logs = [];
for (const level of ["log", "error"]) {
const original = console[level];
console[level] = (...args) => {
window.__logs.push(`${level}: ${args.join(" ")}`);
return original.apply(console, args);
};
}
});
await page.goto("https://example.com");
console.log(await page.evaluate(() => window.__logs));
// No lugar de page.setContent(html)
const html = "<h1>Olá</h1>";
await page.evaluate((content) => {
document.open();
document.write(content);
document.close();
}, html);
await page.waitForLoadState("load");
console.log(await page.locator("h1").textContent()); // OláCriar com engine e opções
O exemplo usa o engine padrão com locale e timezoneId:
curl -X POST https://platform.onveloz.com/api/browser/v1/sessions \
-H "Authorization: Bearer bk_live_sua_chave" \
-H "Content-Type: application/json" \
-d '{
"engine": "patchright",
"options": { "locale": "pt-BR", "timezoneId": "America/Sao_Paulo" },
"timeoutSec": 300
}'
# → { "id": "...", "status": "PENDING", "connectUrl": null, "expiresAt": "..." }const session = await ov.sessions.create({
engine: "patchright",
options: { locale: "pt-BR", timezoneId: "America/Sao_Paulo" },
timeoutSec: 300,
});Um locale ou timezoneId informado em options vale sobre o que o stealth derivaria de proxyCountry.
Opções aceitas em options:
| Opção | Tipo | Regras |
|---|---|---|
headless |
boolean | Roda sem janela. Omitida, vale headlessDefault. O engine precisa aceitar o modo pedido |
locale |
string | Locale BCP 47 da lista locales (ex: "pt-BR"), até 64 caracteres |
timezoneId |
string | Fuso IANA da lista timezones (ex: "America/Sao_Paulo"), até 128 caracteres |
userAgent |
string | User agent da sessão, até 1024 caracteres |
os |
string | "windows", "macos" ou "linux", entre os que o engine lista em os |
flags |
string[] | Flags extras do Chromium: até 32, com até 256 caracteres cada. Cada engine aceita só a sua lista |
settings |
object | Configurações do engine por id (veja abaixo) |
extensions |
object[] | Até 5, cada uma { "webStoreId": "..." } (id de 32 letras da Chrome Web Store) ou { "url": "https://..." } |
initScripts |
string[] | Até 10 scripts não vazios, 256 KiB no total, que toda página roda antes do próprio código |
executable |
string | Id de um build em executables. Só em engines com mais de um build |
geolocation |
object | { "latitude": -23.55, "longitude": -46.63, "accuracy": 50 }: latitude de -90 a 90, longitude de -180 a 180, accuracy em metros (opcional, maior que zero) |
Cada opção depende de uma capacidade do engine (capabilities). Textos não aceitam caracteres de controle, e uma chave fora desta tabela volta unknown_option. Com extensions e sem executable, roda o primeiro build que carrega extensões.
Uma opção que o engine descreve ainda pode ser recusada com o código unavailable enquanto não estiver liberada para ele. O issues da resposta diz qual opção foi recusada (veja Erros).
Configurações do engine (settings)
Além das opções da tabela, cada engine publica as próprias configurações. Os ids seguem o formato mecanismo:chave (por exemplo, context-option:viewport) e mudam de um engine para outro. Consulte os de cada engine:
curl https://platform.onveloz.com/api/browser/v1/engines/patchright/options \
-H "Authorization: Bearer bk_live_sua_chave"
# → { "engine": { ... }, "settings": [ ... ], "lists": { "locales": [ ... ], "timezones": [ ... ], ... } }const { settings, lists } = await ov.engines.options("patchright");Um id de engine que não existe responde 404 (no SDK, BrowserAccessError com status: 404). Cada item de settings traz:
| Campo | Descrição |
|---|---|
id |
A chave em options.settings |
label |
Nome de exibição |
type |
boolean, number, string, enum, string[] ou object |
category |
Grupo da configuração |
choices |
Valores sugeridos (value, label, recommended). value: null significa deixar a configuração de fora |
choicesFrom |
Lista em lists cujos valores a configuração também aceita, ou null |
custom |
true quando a configuração aceita valores fora de choices, desde que do tipo certo |
deprecated |
Configuração obsoleta |
lists traz as listas de valores: locales e timezones (para as opções locale e timezoneId) e as listas citadas em choicesFrom.
Para usar, passe o id e o valor em options.settings:
{
"engine": "patchright",
"options": {
"settings": { "context-option:viewport": { "width": 1366, "height": 768 } }
}
}Limites de settings: até 256 configurações e até 65.536 caracteres de JSON no total. O valor não pode ser null. Fora de choices, textos e enum têm de 1 a 2048 caracteres, listas até 128 itens e objetos até 16.384 caracteres de JSON. Algumas configurações são controladas pela Veloz e voltam fixed ou controlled_switch. A opção geolocation e uma configuração de geolocalização não podem ir juntas.
Opções em conectar-para-acordar
ov.connect() e POST /v1/connect-token aceitam engine, options, region e timeoutSec, como uma criação:
const browser = await chromium.connectOverCDP(
await ov.connect({
engine: "patchright",
options: { locale: "pt-BR", timezoneId: "America/Sao_Paulo" },
}),
);curl -X POST https://platform.onveloz.com/api/browser/v1/connect-token \
-H "Authorization: Bearer bk_live_sua_chave" \
-H "Content-Type: application/json" \
-d '{ "engine": "patchright", "options": { "locale": "pt-BR" } }'
# → { "connectUrl": "wss://.../v1/connect?token=..." }- A checagem acontece ao gerar a URL. Engine ou opção recusada volta
400antes de você conectar. - A URL carrega as opções assinadas, mas não cifradas. Quem tem a URL consegue lê-las e abrir uma sessão na sua organização. Trate a URL como segredo e não coloque segredos em
initScripts. - A URL tem no máximo 8 KiB. Acima disso, a resposta é
400comoption: "options"ecode: "invalid". Reduza as opções (initScriptscostuma ser o maior) ou crie a sessão antes de conectar. - O proxy fica no servidor. Um proxy próprio (
proxyServere credenciais) ou salvo (proxyId) é guardado ao gerar a URL, que só leva uma referência a ele. Envie um ou outro, não os dois.
Repetir com segurança (Idempotency-Key)
POST /v1/sessions aceita o cabeçalho Idempotency-Key. Com ele, repetir a mesma criação (por exemplo, depois de um timeout de rede) devolve a sessão que já existe em vez de abrir outra.
curl -X POST https://platform.onveloz.com/api/browser/v1/sessions \
-H "Authorization: Bearer bk_live_sua_chave" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pedido-123" \
-d '{ "timeoutSec": 300 }'const session = await ov.sessions.create({ timeoutSec: 300 }, { idempotencyKey: "pedido-123" });- A chave tem de 1 a 255 caracteres ASCII visíveis (sem espaço). Outro valor volta
400com"error": "O cabeçalho Idempotency-Key deve ter de 1 a 255 caracteres ASCII visíveis.". - A chave vale dentro da organização. Use uma chave nova para cada sessão nova.
- Mesma chave, mesmo pedido: a resposta traz a sessão original (
id,statusatual econnectUrl: null). Busque oconnectUrlcomGET /v1/sessions/:id. A repetição não conta de novo no limite de sessões simultâneas. - Mesma chave, pedido diferente:
409com"error": "Esta chave de idempotência já foi usada com uma requisição diferente.". No SDK,BrowserErrorcomcode: "browser/idempotency-conflict".
O Idempotency-Key vale só na criação de sessões, não em POST /v1/connect-token.
Erros
Engine ou opções recusadas respondem 400 com error (o texto completo) e issues (um item por problema):
{
"error": "O valor da opção locale não está entre os permitidos. O valor da opção timezoneId não está entre os permitidos.",
"issues": [
{
"option": "locale",
"code": "not_allowed",
"message": "O valor da opção locale não está entre os permitidos."
},
{
"option": "timezoneId",
"code": "not_allowed",
"message": "O valor da opção timezoneId não está entre os permitidos."
}
]
}option é o nome da opção (locale), o id da configuração (context-option:viewport), engine, proxy ou options (a URL de conexão inteira). Os códigos:
| Código | Quando |
|---|---|
unknown_engine |
O engine não existe no catálogo |
unknown_option |
Opção ou configuração que o engine não conhece |
invalid |
Valor fora do formato ou dos limites |
not_allowed |
Valor fora da lista permitida (por exemplo, locale fora de locales) |
unsupported |
O engine não tem a capacidade (por exemplo, headless: true sem modo headless) |
fixed |
Configuração controlada pela Veloz |
controlled_switch |
Configuração que usa uma flag do Chromium controlada pela Veloz |
unavailable |
Engine ou opção ainda não liberada para iniciar sessões |
No SDK, esse 400 vira BrowserOptionsError (code: "browser/invalid-options"), com a mesma lista em error.issues. Um 400 sem issues vem de outro campo, como o proxy ou o Idempotency-Key, e vira BrowserError.
Configuração da sessão
Os campos abaixo valem em ov.sessions.create() e ov.connect(), e no corpo JSON de POST /v1/sessions e POST /v1/connect-token. O stealth é sempre garantido (não é um campo).
| Campo | Tipo | Descrição |
|---|---|---|
engine |
string | Id do engine (veja GET /v1/engines). Omitido, usa o engine padrão |
options |
object | Opções do navegador, checadas contra o engine (veja Escolher o navegador) |
proxyServer |
string | Seu gateway de proxy (scheme://host:porta: http, https ou socks5) |
proxyUsername |
string | Usuário do seu proxy (opcional; omita para proxy autorizado por IP) |
proxyPassword |
string | Senha do seu proxy (opcional). Criptografada em repouso; nunca retornada |
proxyCountry |
string | País de saída do seu proxy (ISO de 2 letras, ex: "US"), alinha o fingerprint |
proxyId |
string | Id de um proxy salvo (veja Proxies salvos), no lugar dos outros campos de proxy |
region |
string | Região de provisionamento (servidor escolhe o padrão) |
timeoutSec |
number | TTL máximo da sessão em segundos (limitado ao teto do seu plano) |
Um region, timeoutSec ou proxyCountry inválido é ignorado, e a sessão segue com o padrão. Já engine e options inválidos são recusados com 400 (veja Erros), assim como proxyId junto de qualquer outro campo de proxy, mesmo inválido.
Visualização ao vivo
No dashboard, abra uma sessão para ver o console Sessão ao vivo: a tela do navegador transmitida em tempo real enquanto a sessão roda, útil para acompanhar automações e depurar. A mesma transmissão é o screencast CDP padrão (Page.startScreencast), então você também pode consumi-la a partir do seu próprio cliente CDP.
Visualização ao vivo pela API
A liveView devolve a URL de uma página de live view hospedada pela Veloz: uma
página HTML completa, com a marca Veloz, pronta para abrir numa aba
(window.open) ou embutir num <iframe> no seu produto. Ela renderiza o console
interativo (assistir e dirigir: clique, digitação, navegação) sem exigir login,
porque o token na URL é a credencial. Não é o socket wss:// bruto: a página
resolve o próprio socket no servidor.
const url = await ov.sessions.liveView(session.id);
// https://app.onveloz.com/live/SESSION_ID?token=...Ou via REST:
curl -H "Authorization: Bearer $VELOZ_BROWSER_TOKEN" \
https://platform.onveloz.com/api/browser/v1/sessions/SESSION_ID/live-view
# → { "liveViewUrl": "https://app.onveloz.com/live/SESSION_ID?token=..." }Use isso para embutir a tela da sessão no seu próprio produto, mostrar ao usuário final o que a automação está fazendo, ou abrir uma janela de depuração sob demanda.
Quatro pontos importantes:
- Nada é transmitido até você abrir a URL. O token em si é inerte: o
screencast só começa quando o WebSocket conecta. Gerar a URL e nunca usá-la não
consome recurso nenhum, e por isso ela fica numa rota própria em vez de vir em
get, que é chamado em polling. - É interativo, não somente-leitura. Os quadros são transmitidos para você e
cliques e teclas voltam como CDP
Input.*, então quem estiver assistindo também pode assumir o controle. - É uma capacidade separada do
connectUrl. Um token de visualização não abre o socket CDP bruto, então você pode entregá-lo a alguém sem dar controle total sobre a automação. Ainda assim, ele permite dirigir a sessão: trate-o como um segredo. - Expira junto com a sessão e só existe enquanto ela está
RUNNING. Em qualquer outro estado a rota responde404.
Limites
As cotas dependem do seu plano:
| Plano | Sessões simultâneas | TTL padrão | TTL máximo |
|---|---|---|---|
| Padrão | 2 | 60s | 300s (5min) |
| SCALE | 10 | 300s | 900s (15min) |
Estourar o limite de sessões simultâneas retorna 429 (no SDK, BrowserQuotaError). Precisa de cotas maiores? Fale com o suporte.
Boas práticas
Importante: conecte assim que a
connectUrlaparecer. Uma sessãoRUNNINGsem nenhum cliente CDP conectado é liberada por inatividade em poucos segundos. Crie e conecte no mesmo processo, em vez de buscar aconnectUrlem um passo e conectar em outro muito depois.
- Encerre o que você abre. Chame
close()(ouDELETE) ao terminar para liberar a cota; não dependa só do TTL. - Use conectar-para-acordar para tarefas curtas. É o caminho mais simples: uma
connectUrl, conecta, trabalha, desconecta. - Use
timeoutSecpara tarefas longas. Suba o TTL até o teto do seu plano quando a automação leva mais que o padrão. - Trate
429com backoff. Ao bater no limite de simultaneidade, aguarde uma sessão liberar antes de tentar de novo. - Envie
Idempotency-Keyquando repetir criações. Um retry depois de timeout devolve a mesma sessão em vez de ocupar outra vaga. - Confira
GET /v1/enginesantes de fixar um engine. Só os marcados comavailable: trueiniciam sessões.
Próximos passos
- Variáveis de Ambiente, para guardar
VELOZ_BROWSER_TOKENcom segurança - Segurança, boas práticas de chaves e segredos
- MCP & Agentes IA, para controlar sessões pelo Claude Code ou pelo Cursor