Cómo modificar mensajes WebSocket con Scripting en Proxyman
6 min de lectura
Proxyman ya puede modificar mensajes WebSocket al instante 🎉
Con unas pocas líneas de JavaScript, puedes editar un mensaje, descartarlo o enviar uno nuevo. Funciona con WS y WSS, en ambas direcciones: del cliente al servidor y del servidor al cliente.
En este blog veremos:
- El problema de probar apps WebSocket.
- Qué hace la nueva opción Modify WebSocket Messages.
- Una demostración paso a paso con un servidor WebSocket local que puedes ejecutar tú mismo.
- Plantillas WebSocket listas para usar, y consejos para cuando nada cambia.
Modify WebSocket Messages es nuevo en Proxyman para macOS. Actualiza a la última versión desde la página de descargas para seguir esta guía.
Este es el resultado. El servidor envía un precio real de BTC, pero la app recibe $1. Cuando la app envía una contraseña, Proxyman descarta el mensaje y responde a la app con una advertencia:
1. El problema
Las apps de chat, trading, juegos y paneles en vivo usan WebSocket para recibir datos en tiempo real. Probarlas es difícil:
- No puedes controlar el servidor. Envía datos reales. Para que envíe un caso límite, como un precio de 0 o un mensaje de error, hay que cambiar el código del servidor.
- Algunos casos son difíciles de reproducir. Un mensaje perdido, una respuesta extraña o una conexión caída rara vez ocurren cuando los necesitas.
- Antes, Proxyman solo podía leer los mensajes WebSocket. La función
onWebsocket()de Scripting podía registrar un mensaje, pero no modificarlo.
2. ¿Qué es “Modify WebSocket Messages”?
Es una nueva casilla en una regla de Scripting. Cuando está activada, Proxyman retiene cada mensaje WebSocket hasta que tu función onWebsocket() devuelve un valor. Lo que devuelvas determina lo que ocurre:
En onWebsocket() | Resultado |
|---|---|
return message | Envía el mensaje con tus cambios |
return null | Descarta el mensaje. El otro extremo nunca lo recibe |
| Sin return | Envía el mensaje original |
abort() | Cierra el WebSocket en ambos lados |
sendToClient(data) / sendToServer(data) | Envía un mensaje nuevo. Un String envía un mensaje de texto y un Uint8Array, un mensaje binario |
El objeto message tiene:
| Campo | Valor |
|---|---|
message.from | "client" o "server" |
message.type | "text", "binary", "ping", "pong" o "close" |
message.data | El texto del mensaje. Cámbialo para editar un mensaje de texto |
message.rawData | Los bytes de un mensaje binario, como un Uint8Array |
La opción está desactivada de forma predeterminada. Cuando está desactivada, onWebsocket() funciona como antes: solo lee los mensajes y nunca los retrasa.
3. Paso a paso: modificar un WebSocket en vivo
Vamos a crear la demostración del video: un pequeño servidor que envía precios de BTC y un cliente que se comunica con él a través de Proxyman.
3.1 Inicia un servidor WebSocket
Crea una carpeta nueva e instala el paquete ws:
mkdir websocket-demo && cd websocket-demo
npm init -y
npm install ws
Guárdalo como server.js. Envía un precio cada segundo y reenvía cada mensaje del chat:
// server.js: a WebSocket server on ws://localhost:3456
const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 3456 });
server.on('connection', (socket) => {
// Send a BTC price every second
const timer = setInterval(() => {
const price = Number((67000 + Math.random() * 1000).toFixed(2));
socket.send(JSON.stringify({ type: 'price', symbol: 'BTC', price: price }));
}, 1000);
// Print what the client sends, then echo it back
socket.on('message', (data) => {
console.log('SERVER gets:', data.toString());
socket.send(JSON.stringify({ type: 'echo', text: JSON.parse(data).text }));
});
socket.on('close', () => clearInterval(timer));
});
console.log('WebSocket server on ws://localhost:3456');
Ejecútalo en la Terminal:
node server.js
3.2 Conecta un cliente a través de Proxyman
Node.js no usa la configuración de proxy de macOS, así que el cliente envía su handshake WebSocket directamente a Proxyman. Guárdalo como client.js:
// client.js: connects to the server through Proxyman
const http = require('http');
const WebSocket = require('ws');
// Proxyman's port. You can see it in the Proxyman toolbar
const PROXYMAN_PORT = 9090;
// Sends the WebSocket handshake to Proxyman, like an app that uses an HTTP proxy
class ProxymanAgent extends http.Agent {
addRequest(request, options) {
request.path = 'http://' + options.host + ':' + options.port + request.path;
super.addRequest(request, { ...options, host: '127.0.0.1', port: PROXYMAN_PORT });
}
}
const socket = new WebSocket('ws://localhost:3456/prices', { agent: new ProxymanAgent() });
socket.on('open', () => {
setTimeout(() => socket.send(JSON.stringify({ type: 'chat', text: 'Hello' })), 2000);
setTimeout(() => socket.send(JSON.stringify({ type: 'chat', text: 'my password is hunter2' })), 4000);
});
socket.on('message', (data) => console.log('CLIENT gets:', data.toString()));
Abre Proxyman y luego ejecuta el cliente en una segunda Terminal:
node client.js
Verás ws://localhost:3456/prices en Proxyman. Abre su pestaña Websocket para ver los mensajes. Todavía no se ha modificado nada. Detén el cliente con Ctrl+C.
3.3 Crea una regla de Scripting
- En Proxyman, haz clic con el botón derecho en el flujo
ws://localhost:3456/prices→ Tools → Scripting.... Proxyman crea una regla con la URL ya rellenada. - Deja marcada la opción Request y marca Modify WebSocket Messages.
- Reemplaza el script por el código siguiente y pulsa Save & Activate (⌘S).

function onWebsocket(context, url, request, response, message) {
// Only change text messages. Binary, ping, pong, and close messages pass through
if (message.type !== "text") {
return message;
}
const json = JSON.parse(message.data);
// 1. Server → client: every BTC price becomes $1
if (message.from === "server" && json.type === "price") {
json.price = 1;
json.note = "edited by Proxyman";
message.data = JSON.stringify(json);
return message;
}
// 2. Client → server: drop a message with a password, and warn the client
if (message.from === "client" && json.text.includes("password")) {
sendToClient(JSON.stringify({ type: "warning", text: "Proxyman blocked a password" }));
return null;
}
// 3. Everything else: send it as it is
return message;
}
3.4 Ejecútalo de nuevo y revisa el resultado
Ejecuta node client.js de nuevo. Proxyman decide si aplica la opción cuando se conecta el WebSocket, así que vuelve a conectar siempre después de guardar una regla.
Ahora el cliente recibe "price": 1 con la nota "edited by Proxyman". El mensaje con la contraseña nunca llega al servidor: la Terminal del servidor solo imprime Hello, y el cliente recibe en su lugar la advertencia del script.

En Proxyman, la pestaña Websocket muestra los precios editados, la advertencia enviada por el script y el mensaje con la contraseña que se descartó.

4. Más ejemplos
Reemplaza texto en ambas direcciones, por ejemplo, para cambiar el nombre de un host:
const FIND_REGEX = /staging\.example\.com/g;
const REPLACE_WITH = "api.example.com";
function onWebsocket(context, url, request, response, message) {
if (message.type === "text") {
message.data = message.data.replace(FIND_REGEX, REPLACE_WITH);
}
return message;
}
Simula una conexión perdida tras 10 mensajes, para probar cómo se reconecta tu app. El código fuera de la función se ejecuta una vez por conexión, así que cada conexión cuenta sus propios mensajes:
const CLOSE_AFTER_MESSAGES = 10;
let messageCount = 0;
function onWebsocket(context, url, request, response, message) {
messageCount += 1;
if (messageCount === CLOSE_AFTER_MESSAGES) {
console.log("Closing the WebSocket after " + messageCount + " messages");
abort();
}
return message;
}
Cambia un mensaje binario asignando nuevos bytes:
function onWebsocket(context, url, request, response, message) {
if (message.type === "binary" && message.from === "server") {
message.rawData = new Uint8Array([1, 2, 3]);
}
return message;
}
5. Empieza más rápido con plantillas WebSocket
No hace falta escribir el script desde cero. En el editor de scripts, haz clic en Templates y busca “websocket”:
- Log WebSocket Messages: imprime cada mensaje en el Console Log. Solo lee los mensajes.
- Modify JSON WebSocket Messages: cambia un campo de los mensajes JSON enviados por el servidor.
- Replace Text in WebSocket Messages: busca y reemplaza texto en ambas direcciones.
- Drop WebSocket Messages: descarta los mensajes que coincidan con una expresión regular, por ejemplo, los eventos de analítica.
- Reply to a WebSocket Message: responde a un mensaje del cliente con
sendToClient(). El servidor nunca lo recibe. - Simulate a WebSocket Disconnect: cierra el WebSocket después de unos pocos mensajes.
Haz clic en Replace para usar una plantilla. Proxyman también marca las casillas necesarias, incluida Modify WebSocket Messages.

6. Problemas y soluciones
Los mensajes no cambian
- Marca Modify WebSocket Messages y luego pulsa Save & Activate (⌘S).
- Vuelve a conectar el WebSocket. La opción se lee cuando el WebSocket se conecta, no en cada mensaje.
- Mantén marcada Request o Response. Una regla con ambas desmarcadas no se ejecuta en absoluto, ni siquiera
onWebsocket(). - Abre el Console Log del editor de scripts. Si tu script produce un error, Proxyman envía el mensaje original e imprime el error allí.
No veo mi WebSocket en Proxyman
- Para
wss://, activa SSL Proxying para el dominio, igual que para HTTPS. - Muchas apps y bibliotecas omiten el proxy para
localhost. Envía el tráfico a Proxyman como lo haceclient.js, o sigue la documentación de WebSocket para tu plataforma.
Bueno saber
- Solo el WebSocket que coincide con la regla espera al script. El resto del tráfico sigue fluyendo.
- Un mensaje de más de 16 MB se envía tal cual, sin pasar por el script.
- Si usas un agente de IA, Proxyman MCP puede crear la misma regla:
create_scripting_ruleaceptamodify_websocket_messages: true.
Más información
- Documentación de Scripting
- Fragmentos de código para Scripting
- Documentación de WebSocket
- Cómo capturar WebSocket y decodificar mensajes Protobuf
- Cómo interceptar y depurar WebSocket en iOS con Proxyman
- Proxyman vs mitmproxy: decodificar mensajes Protobuf de WebSocket
- Cómo cambiar el código de estado, el encabezado o el cuerpo de una respuesta HTTP para pruebas
- Cómo usar Proxyman MCP con Codex y Claude Code
