Message effects
The 13 bubble and full-screen animations, and who actually sees them.
An effect is the animation Messages plays when a message lands — the bubble
slamming in, or confetti falling across the whole conversation. You request one
by adding effect to a rich_text payload.
{
"kind": "rich_text",
"text": "You're in. See you Saturday.",
"effect": "confetti"
}Two constraints follow from that shape. Effects need kind: "rich_text", so a
bare { text } payload cannot carry one — and because rich_text needs a
conversation target, effects are unavailable on a
recipient send. You cannot open a cold thread with
fireworks.
The 13 effects
effect is a closed enum. Four are bubble effects, which animate the
message bubble itself; the other nine are full-screen, taking over the
conversation view while they play.
| Effect | Kind | What it does |
|---|---|---|
impact | Bubble | The bubble slams into the thread hard enough to shake the view. |
loud | Bubble | The bubble swells oversized, shakes, then settles. |
gentle | Bubble | The bubble arrives small and quiet, then eases up to normal size. |
invisibleink | Bubble | The bubble is hidden under shifting static until the reader swipes across it. |
confetti | Full screen | Confetti falls across the conversation. |
lasers | Full screen | Laser beams sweep the screen. |
fireworks | Full screen | Fireworks burst over a darkened screen. |
balloons | Full screen | Balloons rise up the screen. |
sparkles | Full screen | Sparkles cross the screen. |
spotlight | Full screen | The view dims and a spotlight picks the message out. |
echo | Full screen | The message multiplies and floods the screen. |
love | Full screen | A heart grows out of the message and pulses. |
celebration | Full screen | Bursts rise and scatter across the screen. |
The animations themselves are Apple's, not ours. The exact look of any one of them can change between macOS and iOS releases; the names are what is stable.
Those names are Apple's identifiers, and they do not always match the label the
Messages app shows in its effect picker — impact is the one presented as
"Slam". If a particular effect has to be right, send it to yourself once and
look at it before you ship it.
A worked example
An effect is one extra field on a send you were making anyway. Here the message is a confirmation that has a genuine reason to feel celebratory — which is the bar worth holding, because an effect on routine traffic gets old quickly.
curl -X POST $MAPIER_BASE_URL/v1/commands/message.send \
-H "Authorization: Bearer $MAPIER_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: signup-4821-welcome" \
-d '{
"target": {
"kind": "conversation",
"conversationId": "a0000000-0000-4000-8000-000000000001"
},
"payload": {
"kind": "rich_text",
"text": "You are in. See you Saturday.",
"effect": "confetti"
}
}'Keeping the enum in your own type, as above, is worth the four lines it costs.
The API does not validate payload before queueing, so a typo like "confeti"
returns a perfectly ordinary 202 and only fails seconds later on the stream.
Not everyone sees the animation
Effects are an Apple-client feature
The effect plays on iMessage clients — iPhone, iPad, Mac, Apple Watch. A recipient reading over SMS or RCS, or on any non-Apple client, gets the text and nothing else: the animation is absent, with no marker that one was requested.
This is expected iMessage behaviour, not an API failure. The command still
settles succeeded, and there is no field anywhere in the response or on the
stream that reports whether the effect rendered.
Even among Apple clients, full-screen effects can be suppressed by the reader. Apple's accessibility settings include an option to stop message effects auto-playing, and a reader who has turned it on sees the message arrive without the animation.
The practical consequence is that an effect must never carry meaning. If your message only makes sense with confetti attached, write a message that makes sense without it.
Failure modes
Effects add one new way to fail, and it is asynchronous:
- An unrecognised effect name settles
failedon the stream. There is no boundary validation to catch the typo for you. - A connector that has not negotiated rich content settles
failedwithcapability_not_negotiatedorcapability_constraint_violation. Rich content is a capability the Mac advertises at handshake, and there is no endpoint to query it in advance.
Both look identical at the moment you POST — a 202. Watch the stream.