
Cómo Reenviar Mensajes de WhatsApp Programáticamente
Reenvía mensajes entre chats de WhatsApp usando sendRawMessage(). Puedes reenviar texto, multimedia, encuestas y cualquier otro tipo de mensaje — con o sin la etiqueta "Reenviado".
Requisitos Previos
- Una sesión vinculada de whatsmeow-node (Cómo Vincular)
Reenviar un Mensaje de Texto
Para reenviar un mensaje recibido a otro chat, pásalo vía sendRawMessage con el flag isForwarded:
const targetJid = "5598765432@s.whatsapp.net";
client.on("message", async ({ info, message }) => {
if (info.isFromMe) return;
const text =
(message.conversation as string) ??
(message.extendedTextMessage as { text?: string } | undefined)?.text;
if (!text) return;
// Forward as a new message with the "Forwarded" label
await client.sendRawMessage(targetJid, {
extendedTextMessage: {
text,
contextInfo: {
isForwarded: true,
forwardingScore: 1,
},
},
});
});
El flag isForwarded: true muestra la etiqueta "Reenviado" en el mensaje. forwardingScore rastrea cuántas veces se ha reenviado el mensaje — WhatsApp muestra "Reenviado muchas veces" cuando llega a 4+.
Reenviar Sin la Etiqueta "Reenviado"
Para retransmitir un mensaje sin la etiqueta de reenvío, simplemente envíalo como mensaje nuevo:
// Send as if it's a new message — no forwarding label
await client.sendMessage(targetJid, { conversation: text });
Reenviar Mensajes Multimedia
Los mensajes multimedia (imágenes, videos, documentos) se pueden reenviar pasando el contenido del mensaje original. La multimedia ya está subida a los servidores de WhatsApp, así que no se necesita re-subir:
client.on("message", async ({ info, message }) => {
if (info.isFromMe) return;
// Forward images
if (message.imageMessage) {
await client.sendRawMessage(targetJid, {
imageMessage: {
...message.imageMessage,
contextInfo: {
isForwarded: true,
forwardingScore: 1,
},
},
});
return;
}
// Forward videos
if (message.videoMessage) {
await client.sendRawMessage(targetJid, {
videoMessage: {
...message.videoMessage,
contextInfo: {
isForwarded: true,
forwardingScore: 1,
},
},
});
return;
}
// Forward documents
if (message.documentMessage) {
await client.sendRawMessage(targetJid, {
documentMessage: {
...message.documentMessage,
contextInfo: {
isForwarded: true,
forwardingScore: 1,
},
},
});
return;
}
});
Reenviar Cualquier Tipo de Mensaje
Una función genérica que reenvía cualquier mensaje detectando su tipo:
const MESSAGE_TYPES = [
"conversation",
"extendedTextMessage",
"imageMessage",
"videoMessage",
"audioMessage",
"documentMessage",
"stickerMessage",
"contactMessage",
"locationMessage",
"pollCreationMessage",
] as const;
async function forwardMessage(
targetJid: string,
message: Record<string, unknown>,
showForwarded = true,
) {
for (const type of MESSAGE_TYPES) {
if (!(type in message)) continue;
if (type === "conversation") {
// Simple text — wrap in extendedTextMessage for contextInfo support
await client.sendRawMessage(targetJid, {
extendedTextMessage: {
text: message.conversation as string,
...(showForwarded && {
contextInfo: { isForwarded: true, forwardingScore: 1 },
}),
},
});
} else {
// Structured message — spread and add contextInfo
const content = message[type] as Record<string, unknown>;
await client.sendRawMessage(targetJid, {
[type]: {
...content,
...(showForwarded && {
contextInfo: {
...(content.contextInfo as Record<string, unknown> ?? {}),
isForwarded: true,
forwardingScore: 1,
},
}),
},
});
}
return;
}
}
Crear un Bot Relay
Reenvía todos los mensajes de un grupo a otro:
const SOURCE_GROUP = "120363XXXXX@g.us";
const TARGET_GROUP = "120363YYYYY@g.us";
client.on("message", async ({ info, message }) => {
if (info.isFromMe) return;
if (info.chat !== SOURCE_GROUP) return;
// Add sender attribution
const attribution = `[${info.pushName}]:\n`;
const text =
(message.conversation as string) ??
(message.extendedTextMessage as { text?: string } | undefined)?.text;
if (text) {
await client.sendMessage(TARGET_GROUP, {
conversation: `${attribution}${text}`,
});
return;
}
// Forward media with caption attribution
await forwardMessage(TARGET_GROUP, message);
});
Ejemplo Completo
Un bot relay que reenvía mensajes entre un chat privado y un grupo:
import { createClient } from "@whatsmeow-node/whatsmeow-node";
const client = createClient({ store: "session.db" });
// Forward messages FROM this chat TO the group
const PRIVATE_CHAT = "5512345678@s.whatsapp.net";
const GROUP_CHAT = "120363XXXXX@g.us";
client.on("message", async ({ info, message }) => {
if (info.isFromMe) return;
const text =
(message.conversation as string) ??
(message.extendedTextMessage as { text?: string } | undefined)?.text;
// Private → Group
if (info.chat === PRIVATE_CHAT && text) {
await client.sendMessage(GROUP_CHAT, {
conversation: `[${info.pushName}]: ${text}`,
});
return;
}
// Group → Private
if (info.chat === GROUP_CHAT && text) {
await client.sendMessage(PRIVATE_CHAT, {
conversation: `[${info.pushName} in group]: ${text}`,
});
return;
}
});
async function main() {
const { jid } = await client.init();
if (!jid) {
console.error("Not paired!");
process.exit(1);
}
await client.connect();
await client.sendPresence("available");
console.log("Relay bot is online!");
process.on("SIGINT", async () => {
await client.sendPresence("unavailable");
await client.disconnect();
client.close();
process.exit(0);
});
}
main().catch(console.error);
Errores Comunes
Si reenvías mensajes de un chat y también escuchas el chat destino, puedes crear un bucle infinito. Siempre verifica el chat de origen y omite tus propios mensajes.
Las URLs de multimedia de WhatsApp expiran después de un tiempo. Si guardas un mensaje e intentas reenviarlo mucho después, la multimedia puede ya no estar disponible. Reenvía la multimedia rápidamente o descárgala primero con downloadAny().
Reenviar muchos mensajes rápidamente va a alcanzar los límites de tasa de WhatsApp. Espacia los envíos, especialmente para operaciones de relay masivo. Consulta Límites de Tasa.





