Skip to main content

Overview

Send tapback reactions to messages, just like in the native iMessage app. Available reactions include love, like, dislike, laugh, emphasize, and question.

Basic Reactions

Send a reaction to an existing message:
import { createSDK, handleError } from "./utils";

const CHAT_GUID = process.env.CHAT_GUID || "any;-;+1234567890";
const MESSAGE_GUID = process.env.MESSAGE_GUID;

async function main() {
    const sdk = createSDK();

    sdk.on("ready", async () => {
        try {
            let messageGuid = MESSAGE_GUID;

            // Send a test message if we don't have a GUID
            if (!messageGuid) {
                const testMessage = await sdk.messages.sendMessage({
                    chatGuid: CHAT_GUID,
                    message: "Test message for reactions!",
                });

                messageGuid = testMessage.guid;
                console.log(`sent: ${messageGuid}`);
            }

            // Send a heart reaction
            await sdk.messages.sendReaction({
                chatGuid: CHAT_GUID,
                messageGuid,
                reaction: "love",
            });

            console.log("Sent ❤️ reaction");
        } catch (error) {
            handleError(error, "Failed to send reaction");
        }

        await sdk.close();
        process.exit(0);
    });

    await sdk.connect();
}

main().catch(console.error);

Available Reactions

Love

reaction: "love"
Sends ❤️

Like

reaction: "like"
Sends 👍

Dislike

reaction: "dislike"
Sends 👎

Laugh

reaction: "laugh"
Sends 😂

Emphasize

reaction: "emphasize"
Sends ‼️

Question

reaction: "question"
Sends ❓

Multiple Reactions Example

Send multiple reactions to the same message:
import { createSDK, handleError } from "./utils";

const CHAT_GUID = process.env.CHAT_GUID || "any;-;+1234567890";
const MESSAGE_GUID = process.env.MESSAGE_GUID;

async function main() {
    const sdk = createSDK();

    sdk.on("ready", async () => {
        try {
            let messageGuid = MESSAGE_GUID;

            if (!messageGuid) {
                const testMessage = await sdk.messages.sendMessage({
                    chatGuid: CHAT_GUID,
                    message: "Test message for reactions!",
                });

                messageGuid = testMessage.guid;
                console.log(`sent: ${messageGuid}`);
            }

            // ❤️ = love
            await sdk.messages.sendReaction({
                chatGuid: CHAT_GUID,
                messageGuid,
                reaction: "love",
            });

            await new Promise((resolve) => setTimeout(resolve, 2000));

            // 😂 = laugh
            await sdk.messages.sendReaction({
                chatGuid: CHAT_GUID,
                messageGuid,
                reaction: "laugh",
            });

            await new Promise((resolve) => setTimeout(resolve, 2000));

            // 👎 = dislike
            await sdk.messages.sendReaction({
                chatGuid: CHAT_GUID,
                messageGuid,
                reaction: "dislike",
            });

            await new Promise((resolve) => setTimeout(resolve, 2000));

            // 👍 = like
            await sdk.messages.sendReaction({
                chatGuid: CHAT_GUID,
                messageGuid,
                reaction: "like",
            });
        } catch (error) {
            handleError(error, "Failed to send reaction");
        }

        await sdk.close();
        process.exit(0);
    });

    await sdk.connect();
}

main().catch(console.error);

Parameters

chatGuid
string
required
The GUID of the chat containing the message
messageGuid
string
required
The GUID of the message to react to
reaction
string
required
The reaction type: "love", "like", "dislike", "laugh", "emphasize", or "question"

Auto-React Bot

Automatically react to incoming messages:
sdk.on("new-message", async (message) => {
    // Don't react to own messages
    if (message.isFromMe) return;
    
    const chat = message.chats?.[0];
    if (!chat) return;

    const text = message.text?.toLowerCase() || "";
    let reaction: string | null = null;

    // Choose reaction based on message content
    if (text.includes("love") || text.includes("❤️")) {
        reaction = "love";
    } else if (text.includes("funny") || text.includes("😂")) {
        reaction = "laugh";
    } else if (text.includes("great") || text.includes("awesome")) {
        reaction = "like";
    } else if (text.includes("?")) {
        reaction = "question";
    } else if (text.includes("!")) {
        reaction = "emphasize";
    }

    if (reaction) {
        try {
            await sdk.messages.sendReaction({
                chatGuid: chat.guid,
                messageGuid: message.guid,
                reaction,
            });
            console.log(`Reacted with ${reaction} to: ${message.text}`);
        } catch (error) {
            console.error("Failed to react:", error);
        }
    }
});

Removing Reactions

To remove a reaction, send the same reaction type again. iMessage will toggle it off:
// Send love reaction
await sdk.messages.sendReaction({
    chatGuid: CHAT_GUID,
    messageGuid: messageGuid,
    reaction: "love",
});

// Remove love reaction (send it again)
await sdk.messages.sendReaction({
    chatGuid: CHAT_GUID,
    messageGuid: messageGuid,
    reaction: "love",
});

Advanced Examples

Sentiment Analysis Reactions

import { analyzeSentiment } from "./sentiment"; // Your sentiment analysis

sdk.on("new-message", async (message) => {
    if (message.isFromMe || !message.text) return;
    
    const chat = message.chats?.[0];
    if (!chat) return;

    const sentiment = await analyzeSentiment(message.text);
    
    let reaction: string;
    if (sentiment > 0.5) {
        reaction = "love";
    } else if (sentiment > 0) {
        reaction = "like";
    } else if (sentiment < -0.5) {
        reaction = "dislike";
    } else {
        reaction = "question";
    }

    await sdk.messages.sendReaction({
        chatGuid: chat.guid,
        messageGuid: message.guid,
        reaction,
    });
});

Random Reaction Generator

const reactions = ["love", "like", "laugh", "emphasize"] as const;

sdk.on("new-message", async (message) => {
    if (message.isFromMe) return;
    
    const chat = message.chats?.[0];
    if (!chat) return;

    // 20% chance to react
    if (Math.random() < 0.2) {
        const reaction = reactions[Math.floor(Math.random() * reactions.length)];
        
        await sdk.messages.sendReaction({
            chatGuid: chat.guid,
            messageGuid: message.guid,
            reaction,
        });
    }
});

Reaction Counter

const reactionCounts = new Map<string, number>();

sdk.on("new-message", async (message) => {
    if (message.isFromMe) return;
    
    const sender = message.handle?.address;
    if (!sender) return;

    // Count reactions per sender
    const count = reactionCounts.get(sender) || 0;
    reactionCounts.set(sender, count + 1);

    const chat = message.chats?.[0];
    if (!chat) return;

    // Different reaction based on how many messages they've sent
    let reaction: string;
    if (count < 5) {
        reaction = "like";
    } else if (count < 10) {
        reaction = "love";
    } else {
        reaction = "emphasize";
    }

    await sdk.messages.sendReaction({
        chatGuid: chat.guid,
        messageGuid: message.guid,
        reaction,
    });
});

Best Practices

Add delays between reactions to avoid overwhelming the recipient:
await new Promise(resolve => setTimeout(resolve, 2000));
Filter messages before reacting:
if (message.isFromMe) return; // Skip own messages
if (!message.text) return; // Skip media-only messages
Reactions can fail if the message doesn’t exist:
try {
    await sdk.messages.sendReaction({...});
} catch (error) {
    console.error("Reaction failed:", error);
}
You can only react to messages that exist in your message database. You cannot react to messages you haven’t received.

Listening for Reactions

To detect when someone reacts to your messages, listen for message updates:
sdk.on("updated-message", (message) => {
    // Check for reaction-related updates
    if (message.associatedMessageType) {
        console.log(`Someone reacted to message ${message.associatedMessageGuid}`);
    }
});

Next Steps

Edit Messages

Modify sent messages

Message Effects

Add visual effects

Build docs developers (and LLMs) love