Support reactions in your app built with XMTP
Use the reaction content type to support reactions in your app. A reaction is a quick and often emoji-based way to respond to a message. Reactions are usually limited to a predefined set of emojis or symbols provided by the messaging app.
You're welcome to provide feedback by commenting on the Proposal for emoji reactions content type XIP idea.
Use a local database for performance
Use a local database to store reactions. This will enable your app to performantly display a reaction with its referenced message when rendering message lists.
To learn more about using a local database, see Use local-first architecture.
Configure the content type
In some SDKs, the ReactionCodec
is already included in the SDK. If not, you can install the package using the following command:
- JavaScript
- React
- Kotlin
- Swift
- Dart
- React Native
In the JavaScript SDK, you need to import this package first.
npm i @xmtp/content-type-reaction
After importing the package, you can register the codec.
import {
ContentTypeReaction,
ReactionCodec,
} from "@xmtp/content-type-reaction";
// Create the XMTP client
const xmtp = await Client.create(signer, { env: "dev" });
xmtp.registerCodec(new ReactionCodec());
The React SDK supports all current standards-track content types, but only text messages are enabled out of the box. Adding support for other standards-track content types requires a bit of configuration.
import {
XMTPProvider,
reactionContentTypeConfig,
} from "@xmtp/react-sdk";
const contentTypeConfigs = [
reactionContentTypeConfig,
];
createRoot(document.getElementById("root") as HTMLElement).render(
<StrictMode>
<XMTPProvider contentTypeConfigs={contentTypeConfigs}>
<App />
</XMTPProvider>
</StrictMode>,
);
import org.xmtp.android.library.codecs.ReactionCodec
Client.register(codec = ReactionCodec())
Client.register(ReactionCodec());
import 'package:xmtp/src/content/codec_registry.dart';
import 'package:xmtp/src/content/decoded.dart';
import 'package:xmtp/src/content/text_codec.dart';
import 'package:xmtp/src/content/reaction_codec.dart';
// Registering
var registry = CodecRegistry()..registerCodec(TextCodec());
var codec = ReactionCodec();
codec.setRegistry(registry);
const client = await Client.create(signer, {
env: "production",
codecs: [new ReactionCodec()],
});
Send a reaction
With XMTP, reactions are represented as objects with the following keys:
reference
: ID of the message being reacted toaction
: Action of the reaction (added or removed)content
: String representation of the reaction (smile, for example) to be interpreted by clientsschema
: Schema of the reaction (Unicode, shortcode, or custom)
- JavaScript
- React
- Kotlin
- Swift
- Dart
- React Native
const reaction = {
reference: someMessageID,
action: "added",
content: "smile",
};
await conversation.send(reaction, {
contentType: ContentTypeReaction,
});
const { sendMessage } = useSendMessage();
const handleClick = useCallback(
(emoji: string) => {
void sendMessage<Reaction>(
conversation,
{
content: emoji,
schema: "unicode",
reference: message.xmtpID,
action: "added",
},
ContentTypeReaction,
);
},
[conversation, message.xmtpID, sendMessage],
);
import org.xmtp.android.library.codecs.Reaction
import org.xmtp.android.library.codecs.ReactionAction
import org.xmtp.android.library.codecs.ReactionSchema
import org.xmtp.android.library.codecs.ContentTypeReaction
import org.xmtp.android.library.SendOptions
val reaction = Reaction(
reference = messageToReact.id, // the ID of the message you're reacting to
action = ReactionAction.Added, // the action of the reaction
content = "U+1F603", // the content of the reaction
schema = ReactionSchema.Unicode // the schema of the reaction
)
conversation.send(
content = reaction,
options = SendOptions(contentType = ContentTypeReaction)
)
let reaction = Reaction(
reference: messageToReact.id,
action: .added,
content: "U+1F603",
schema: .unicode
)
try await conversation.send(
content: reaction,
options: .init(contentType: ContentTypeReaction)
)
val reaction = Reaction(
reference = messageToReact.id,
action = ReactionAction.added,
content = "U+1F603",
schema = ReactionSchema.unicode
)
conversation.send(
content = reaction,
options = SendOptions(contentType = ContentTypeReaction),
)
// Assuming you have a conversation object and the ID of the message you're reacting to
const reactionContent = {
reaction: {
reference: messageId, // ID of the message you're reacting to
action: "added", // Action can be 'added' or 'removed'
schema: "unicode", // Schema can be 'unicode', 'shortcode', or 'custom'
content: "👍", // Content of the reaction
},
};
await conversation.send(reactionContent);
Receive a reaction
Now that you can send a reaction, you need a way to receive a reaction. For example:
- JavaScript
- React
- Kotlin
- Swift
- Dart
- React Native
if (message.contentType.sameAs(ContentTypeReaction)) {
// We've got a reaction.
const reaction: Reaction = message.content;
}
if (message.contentType === ContentTypeReaction.toString()) {
const reactionContent = message.content as Reaction;
// Use reactionContent...
}
useReactions
Use to fetch all reactions for a specific message. It takes a CachedMessage
as a parameter and returns an array of CachedReaction
objects.
import { useReactions } from "@xmtp/react-sdk";
const reactions = useReactions(message);
getReactionsByXmtpID
Use to retrieve all reactions associated with a specific XMTP ID from the database.
import { getReactionsByXmtpID } from "@xmtp/react-sdk";
const reactions = await getReactionsByXmtpID("testXmtpId1", db);
hasReaction
Use to check if a message has any reactions. It takes a CachedMessage
as a parameter and returns a boolean indicating whether the message has reactions.
import { hasReaction } from "@xmtp/react-sdk";
const messageHasReaction = hasReaction(originalMessage!);
if (message.contentType == ContentTypeReaction) {
// The message is a reaction
val reactionCodec = ReactionCodec()
val reaction: Reaction = reactionCodec.decode(message.content)
}
let content: Reaction = try message.content()
var decodedContent = await registry.decode(encoded);
if (decodedContent.contentType == ContentTypeReaction) {
// The message is a reaction.
Reaction receivedReaction = decodedContent.content;
}
if (message.contentTypeId === "xmtp.org/reaction:1.0") {
const reaction = message.content();
return reaction;
//reaction.reference = id of the message being reacted to,
//reaction.action = 'added',
//reaction.schema = 'unicode',
//reaction.content = '💖',
}
To handle unsupported content types, refer to the fallback section.
Display the reaction
Generally, reactions should be interpreted as emoji. So, "smile" would translate to 😄 in UI clients. That being said, how you ultimately choose to render a reaction in your app is up to you.
Notifications and reactions
Reactions have shouldPush
set to false
, which means that reactions do not trigger push notifications as long as the notification server respects this flag.