Node.js ou Python. Define o interpretador usado no runtime.
Código Inline
Escreva Node.js ou Python direto no editor da etapa de Regra Customizada: a API do Mini SDK (bm) e o que está disponível em cada linguagem.
bm.get('{nome}'). Veja Manipulação de Variáveis → Locais. Reserve o script para o que realmente pede lógica. O mesmo vale para uma pausa simples: o Timer de Espera da etapa faz o processo aguardar alguns segundos depois do script, sem setTimeout nem time.sleep(). Veja Timers → Timer de Espera.
Configurando a etapa

O editor abre expandido quando a etapa já tem script. Sem script, ele fica recolhido: clique em ▼ Mostrar para abrir.
No bloco Código Customizado da etapa de 🔢 Regra Customizada:
- Inline: O código é escrito diretamente no campo Script Customizado abaixo.
- Projeto: O código é um projeto ZIP enviado via Projetos e SDK. Neste caso, selecione o projeto em Projeto de Script.
O código a ser executado (apenas no modo Inline). O editor aceita Node.js ou Python conforme a linguagem selecionada acima.
Visível apenas no modo Projeto. Selecione o projeto ZIP previamente enviado no Menu, na opção Codebase. Veja Projetos e SDK.
Por quantos segundos este script pode rodar antes de ser encerrado. Vale igual para Node.js e Python, no modo Inline e no modo Projeto. Padrão de 3600 (1 hora), com atalhos de 2 minutos, 10 minutos, 1 hora e 8 horas, e qualquer valor entre 10 segundos e 8 horas.
Ao estourar, a etapa é encerrada e conta como erro, entrando na Gestão de Erros da etapa. É assim que um travamento vira nova tentativa em vez de uma execução perdida, então prefira o menor tempo que a etapa realmente precisa: 120 para cálculo puro, 600 quando há arquivo, API, banco ou aplicativo envolvido, 3600 quando a etapa processa um lote inteiro de uma vez.
O campo aparece quando a etapa tem código escrito ou um projeto selecionado. Etapa que só itera listas não roda script, e o Script de Sessão não passa por esse limite. Detalhes e a razão de não existir "sem limite" aqui em Timers.
Erros de sintaxe e avisos: o aviso vem antes da execução
Uma chave a mais, uma aspa aberta ou uma indentação fora do lugar derrubam o script inteiro, e sem aviso o erro só apareceria no meio da execução, depois de outras etapas já terem rodado. Por isso o browserMate confere o código do Script Inline e do Script de Sessão, e separa o que encontra em dois níveis:
- Erro (vermelho): o script não roda. Além do sublinhado no editor, a etapa entra no indicador de pendências, na categoria Script com erro de sintaxe, com a linha e a descrição. Enquanto houver pendência, o botão de publicar não aparece (veja Pendências). Salvar continua liberado: dá para guardar um script pela metade e voltar depois. No Debug, ao clicar em Debugar com um erro desses, o browserMate mostra a lista e pergunta se você quer rodar mesmo assim.
- Aviso (amarelo): o código é válido, mas alguma coisa nele vai falhar se aquela linha executar, como uma variável que nunca foi declarada. Aparece só no editor e não impede publicar, porque o script pode estar certo de um jeito que o editor não consegue enxergar.
No editor, a linha fica sublinhada e uma faixa abaixo dele mostra Linha N com a descrição, mais o número de outros achados. Clique na faixa para ir até a linha. A conferência acontece alguns instantes depois de você parar de digitar.
O que é erro (vermelho)
| O que é conferido | Node.js | Python |
|---|---|---|
| Chave, parêntese ou colchete a mais, faltando ou trocado. O aviso aponta a linha onde o símbolo sobrou ou onde foi aberto | Sim | Sim |
| Aspas não fechadas | Sim | Sim |
| Aspas curvas, traço especial e caractere invisível colados de uma página ou documento (o olho não distingue do certo) | Sim. Exceção: o espaço especial (NBSP), que o Node aceita como espaço comum | Sim, inclusive o espaço especial |
| Indentação errada, inclusive tab misturado com espaço | Não se aplica | Sim |
: esquecido no fim de if, for, def e similares | Não se aplica | Sim |
| Erro de digitação em palavra ou operador | Sim (retrun, x = = 1) | Em parte: palavra-chave escrita errada (retrun x, iff x:) e dois valores colados sem nada entre eles (x 5, print "a"). Erros como x = = 1 só aparecem quando o script roda |
const sem valor inicial, nome declarado duas vezes e await solto no nível de cima | Sim | Não se aplica |
bm antes do seu código, então const bm = require('./browsermate') repete a declaração e o script não roda (já foi declarado). E await solto no nível de cima do script também não roda no Script Inline: envolva o código numa função assíncrona (veja Código assíncrono, mais abaixo). Os dois aparecem em vermelho no editor.
O que é aviso (amarelo)
| O que o aviso diz | Node.js | Python |
|---|---|---|
Nome usado e nunca declarado ou definido, com sugestão quando parece um erro de digitação (totl, você quis dizer total) | Sim | Sim: só quando o nome não é definido em lugar nenhum do script |
const que recebe outro valor mais adiante | Sim | Não se aplica |
| Variável usada antes da linha em que é declarada | Sim | Não |
Texto que parece um JSON e não é válido (} a mais, vírgula sobrando, lista sem fechar). O aviso aponta o ponto do texto onde o JSON quebra | Sim | Sim |
= por ; (let a ; 5) é código válido: declara a e depois avalia um 5. O problema é a ficar sem valor, e isso não se distingue de um script legítimo, então não há aviso. O mesmo vale para um nome montado em tempo de execução, e, no Python, para um nome que só é definido dentro de outra função e usado fora dela. Só o Debug mostra esses casos.
A conferência vale só para o modo Inline. O código de um Projeto ZIP não fica no cadastro da etapa e não é conferido.
Node.js inline
O código roda em Node.js 24, embarcado no runtime. Veja Versões de Node.js e Python.
O código é executado em um contexto Node.js com o Mini SDK bm já disponível (o runtime injeta const bm = require('./browsermate') automaticamente antes do seu código). As variáveis do processo vivem no globalData e são acessadas pela chave no formato {variavel}, com chaves.
Acesso a variáveis
// Ler variável do processo. A chave usa o formato {variavel}
const valor = bm.get('{nome_variavel}');
// com valor padrão caso não exista
const tipo = bm.get('{tipo_documento}', 'NFe');
// todas as variáveis de uma vez (somente leitura)
const todas = bm.globalData;
// Escrever variáveis: SEMPRE via bm.done() ao final do script
bm.done('ok', {
'{resultado}': 'texto calculado',
'{total}': 1500.75,
'{lista}': [1, 2, 3]
});
bm.get() devolve o valor como ele está no fluxo: texto, número, lista (array) ou objeto. Uma variável com tipo declarado chega no tipo dela (uma Moeda chega como número). No bm.done(), número, array e objeto são gravados como estão. Texto capturado da tela chega como texto: para fazer conta com ele, converta com Number().
bm.done(result, updates). Sem essa chamada ao final, nenhuma variável é atualizada e o log indica que o script não produziu output.
bm.done() passam a aparecer no botão { } das etapas seguintes, no autocomplete dos outros scripts e no Copilot, sem nada a declarar. Vale para Node.js e Python. Os detalhes, e o que não entra na lista, estão em Manipulação de Variáveis: Script.
Módulos disponíveis
O runtime Node.js suporta require() para módulos nativos e para dependências pré-instaladas:
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const https = require('https');
const Buffer = require('buffer').Buffer;
const xml2js = require('xml2js'); // parsing XML
const xlsx = require('xlsx'); // Excel
const moment = require('moment'); // datas
Logging
Use bm.bmLog() para registrar mensagens nos logs oficiais de execução, que aparecem no Control Room:
bm.bmLog('Processando item: ' + bm.get('{item_atual}'));
bm.bmLog('Total de itens: ' + lista.length);
bm.bmLog('Erro ao processar: ' + err.message);
Código assíncrono
O runtime suporta async/await. Envolva o código em uma função assíncrona auto-executável e chame bm.done() ao final:
(async () => {
const axios = require('axios');
// Buscar dados de uma API externa
const id = bm.get('{id}');
const resp = await axios.get(`https://api.exemplo.com/item/${id}`);
bm.bmLog('Item carregado: ' + resp.data.nome);
bm.done('ok', {
'{nome_item}': resp.data.nome,
'{preco_item}': resp.data.preco
});
})();
Python inline
O código roda em Python 3.14, embarcado no runtime, com pip disponível. Veja Versões de Node.js e Python.
O código é executado em um ambiente Python 3 com o Mini SDK bm já disponível (o runtime injeta import browsermate as bm automaticamente antes do seu código). As variáveis usam o mesmo formato de chave {variavel}.
Acesso a variáveis
# Ler variável do processo. A chave usa o formato {variavel}
valor = bm.get('{nome_variavel}')
lista = bm.get('{lista}', [])
# Escrever variáveis: SEMPRE via bm.done() ao final do script
bm.done('ok', {
'{resultado}': 'texto calculado',
'{total}': 1500.75,
'{lista}': [1, 2, 3]
})
bm.get() devolve o valor como ele está no fluxo: str, int/float, bool, list ou dict. Uma variável com tipo declarado chega no tipo dela (uma Moeda chega como número). No bm.done(), número, list e dict são gravados como estão. Texto capturado da tela chega como texto: para fazer conta com ele, converta com int() ou float().
Bibliotecas disponíveis
import json, re, os, sys, math, datetime
import base64, hashlib, hmac
import csv, io
import xml.etree.ElementTree as ET
import urllib.request, urllib.parse
import pandas as pd # análise de dados
import openpyxl # Excel
import PyPDF2 # PDF
Logging em Python
Use bm.bmLog() para registrar mensagens nos logs oficiais de execução, que aparecem no Control Room:
bm.bmLog('Processando...')
bm.bmLog('Total de itens: ' + str(len(lista)))
API de contexto do processo
Além das variáveis, o runtime expõe outras utilidades:
| Objeto / Função | Linguagem | Descrição |
|---|---|---|
bm.get('{var}', default) | Node.js e Python | Lê uma variável do processo (chave no formato {variavel}) |
bm.globalData | Node.js e Python | Objeto/dict somente leitura com todas as variáveis do processo |
bm.bmLog(mensagem) | Node.js e Python | Registra mensagem nos logs oficiais de execução (visível no Control Room) |
bm.done(result, updates) | Node.js e Python | Obrigatório ao final. Finaliza o script e escreve as variáveis de updates de volta ao processo |
bm.secret(), não de {vault.CHAVE}
Dentro de um script ninguém substitui {...}, então a referência do Cofre de Senhas que funciona no resto do produto não vale aqui. Use bm.secret('CHAVE'), com a chave crua. A chave pode ser montada em tempo de execução, e chave inexistente levanta erro listando as disponíveis. Veja Mini SDK, credenciais do Cofre.
bm.get('{var}') devolve o valor real, mesmo de uma variável marcada como Dado sensível. A marca esconde o valor do log e do estado guardado, não do seu código. Não escreva esse valor em bm.bmLog(): o que o script cria por conta própria não é marcado sozinho.
Exemplos práticos
Calcular impostos sobre um valor
const valor_bruto = parseFloat(bm.get('{valor_bruto}')) || 0;
const aliquota_iss = 0.05; // 5%
const aliquota_pis = 0.0065;
const valor_iss = valor_bruto * aliquota_iss;
const valor_pis = valor_bruto * aliquota_pis;
bm.done('calculado', {
'{valor_iss}': valor_iss.toFixed(2),
'{valor_pis}': valor_pis.toFixed(2),
'{valor_liquido}': (valor_bruto - valor_iss - valor_pis).toFixed(2)
});
Parsear XML de NF-e
const xml2js = require('xml2js');
const xml_nfe = bm.get('{xml_nfe}', '');
(async () => {
const resultado = await xml2js.parseStringPromise(xml_nfe, { explicitArray: false });
const nfe = resultado.nfeProc?.NFe?.infNFe;
const numero = nfe?.ide?.nNF || '';
bm.bmLog('NF-e parseada: ' + numero);
bm.done('ok', {
'{numero_nf}': numero,
'{valor_total}': nfe?.total?.ICMSTot?.vNF || '0',
'{cnpj_emitente}': nfe?.emit?.CNPJ || ''
});
})();
Gerar CSV e salvar em variável
import csv, io, base64
itens = bm.get('{lista_itens}', [])
output = io.StringIO()
writer = csv.DictWriter(output, fieldnames=['produto', 'qty', 'preco'])
writer.writeheader()
writer.writerows(itens)
csv_texto = output.getvalue()
# Codifica em base64 para armazenar na variável
bm.done('csv gerado', {
'{csv_base64}': base64.b64encode(csv_texto.encode()).decode()
})
