Overview
Create interactive polls in iMessage conversations and programmatically vote on them. Polls are a native iMessage feature that work across all Apple devices.
Creating a Poll
Create a poll with multiple choice options:
import { createSDK , handleError } from "./utils" ;
const CHAT_GUID = process . env . CHAT_GUID || "any;-;+1234567890" ;
async function main () {
const sdk = createSDK ();
sdk . on ( "ready" , async () => {
console . log ( "Poll creation example... \n " );
try {
console . log ( "Creating a poll..." );
const pollMessage = await sdk . polls . create ({
chatGuid: CHAT_GUID ,
title: "" ,
options: [
"Option A - First choice" ,
"Option B - Second choice" ,
"Option C - Third choice" ,
"Option D - Fourth choice" ,
],
});
console . log ( " \n ✓ Poll created successfully!" );
console . log ( `Poll message GUID: ${ pollMessage . guid } ` );
console . log ( `Balloon Bundle ID: ${ pollMessage . balloonBundleId } ` );
if ( pollMessage . payloadData ) {
console . log ( ` \n Payload Data: ${ JSON . stringify ( pollMessage . payloadData , null , 2 ) } ` );
}
} catch ( error ) {
handleError ( error , "Failed to create poll" );
}
await sdk . close ();
process . exit ( 0 );
});
await sdk . connect ();
}
main (). catch ( console . error );
Poll Parameters
The GUID of the chat where the poll will be created
Optional poll question/title. Can be an empty string.
Array of poll options (minimum 2, maximum typically 10)
Voting on Polls
Vote on an existing poll by selecting an option:
import { parsePollDefinition } from "../lib/poll-utils" ;
import { createSDK , handleError } from "./utils" ;
const CHAT_GUID = process . env . CHAT_GUID || "any;-;+1234567890" ;
const POLL_MESSAGE_GUID = process . env . POLL_MESSAGE_GUID ;
async function main () {
const sdk = createSDK ();
sdk . on ( "ready" , async () => {
try {
let pollMessageGuid = POLL_MESSAGE_GUID ;
let optionIdentifier : string | undefined ;
// Create a poll if we don't have a GUID
if ( ! pollMessageGuid ) {
const poll = await sdk . polls . create ({
chatGuid: CHAT_GUID ,
title: "Vote test" ,
options: [ "Option A" , "Option B" , "Option C" ],
});
pollMessageGuid = poll . guid ;
console . log ( `created poll: ${ pollMessageGuid } ` );
const pollData = parsePollDefinition ( poll );
optionIdentifier = pollData ?. options ?.[ 0 ]?. optionIdentifier ;
console . log ( `options: ${ pollData ?. options ?. map (( o ) => o . text ). join ( ", " ) } ` );
await new Promise (( resolve ) => setTimeout ( resolve , 2000 ));
}
// Get poll details if needed
if ( ! optionIdentifier ) {
const poll = await sdk . messages . getMessage ( pollMessageGuid ! , { with: [ "payloadData" ] });
const pollData = parsePollDefinition ( poll );
optionIdentifier = pollData ?. options ?.[ 0 ]?. optionIdentifier ;
}
if ( ! optionIdentifier ) {
throw new Error ( "Could not find option identifier" );
}
// Cast vote
const vote = await sdk . polls . vote ({
chatGuid: CHAT_GUID ,
pollMessageGuid: pollMessageGuid ! ,
optionIdentifier ,
});
console . log ( `voted: ${ vote . guid } ` );
} catch ( error ) {
handleError ( error , "Failed to vote" );
}
await sdk . close ();
process . exit ( 0 );
});
await sdk . connect ();
}
main (). catch ( console . error );
Vote Parameters
The GUID of the chat containing the poll
The message GUID of the poll
The unique identifier for the option you’re voting for
Complete Example: Create and Vote
Simple Poll
Question Poll
Rating Poll
const sdk = createSDK ();
sdk . on ( "ready" , async () => {
// 1. Create poll
const poll = await sdk . polls . create ({
chatGuid: CHAT_GUID ,
title: "What's for lunch?" ,
options: [ "Pizza" , "Burgers" , "Salad" , "Sushi" ],
});
console . log ( `Poll created: ${ poll . guid } ` );
// 2. Parse poll data
const pollData = parsePollDefinition ( poll );
console . log ( "Options:" );
pollData ?. options ?. forEach (( opt , i ) => {
console . log ( ` ${ i + 1 } . ${ opt . text } ` );
});
// 3. Vote for first option
const firstOption = pollData ?. options ?.[ 0 ];
if ( firstOption ) {
await sdk . polls . vote ({
chatGuid: CHAT_GUID ,
pollMessageGuid: poll . guid ,
optionIdentifier: firstOption . optionIdentifier ,
});
console . log ( `Voted for: ${ firstOption . text } ` );
}
await sdk . close ();
});
await sdk . connect ();
Listening for Poll Messages
Detect and handle incoming polls:
import { isPollMessage , getPollSummary } from "../lib/poll-utils" ;
sdk . on ( "new-message" , ( message ) => {
const sender = message . handle ?. address ?? "unknown" ;
if ( isPollMessage ( message )) {
const pollSummary = getPollSummary ( message );
console . log ( ` \n ${ sender } created a poll:` );
console . log ( pollSummary );
} else {
console . log ( ` \n ${ sender } : ${ message . text ?? "(no text)" } ` );
}
});
Poll Utils
The SDK includes utility functions for working with polls:
isPollMessage
import { isPollMessage } from "../lib/poll-utils" ;
if ( isPollMessage ( message )) {
console . log ( "This is a poll!" );
}
getPollSummary
import { getPollSummary } from "../lib/poll-utils" ;
const summary = getPollSummary ( message );
console . log ( summary ); // Human-readable poll description
parsePollDefinition
import { parsePollDefinition } from "../lib/poll-utils" ;
const pollData = parsePollDefinition ( message );
if ( pollData ) {
console . log ( `Title: ${ pollData . title } ` );
pollData . options ?. forEach ( opt => {
console . log ( `- ${ opt . text } (ID: ${ opt . optionIdentifier } )` );
});
}
Advanced Examples
Auto-Voter Bot
sdk . on ( "new-message" , async ( message ) => {
if ( ! isPollMessage ( message )) return ;
const chat = message . chats ?.[ 0 ];
if ( ! chat ) return ;
const pollData = parsePollDefinition ( message );
if ( ! pollData ?. options ?. length ) return ;
// Vote for first option automatically
const firstOption = pollData . options [ 0 ];
await sdk . polls . vote ({
chatGuid: chat . guid ,
pollMessageGuid: message . guid ,
optionIdentifier: firstOption . optionIdentifier ,
});
console . log ( `Auto-voted for: ${ firstOption . text } ` );
});
Poll Analytics
const pollStats = new Map ();
sdk . on ( "new-message" , ( message ) => {
if ( ! isPollMessage ( message )) return ;
const pollData = parsePollDefinition ( message );
if ( ! pollData ) return ;
pollStats . set ( message . guid , {
title: pollData . title ,
optionCount: pollData . options ?. length || 0 ,
created: message . dateCreated ,
creator: message . handle ?. address ,
});
console . log ( ` \n Poll Statistics:` );
console . log ( ` Total polls: ${ pollStats . size } ` );
});
Smart Voting
sdk . on ( "new-message" , async ( message ) => {
if ( ! isPollMessage ( message )) return ;
const chat = message . chats ?.[ 0 ];
if ( ! chat ) return ;
const pollData = parsePollDefinition ( message );
if ( ! pollData ?. options ) return ;
// Vote based on keywords in options
const preferredOption = pollData . options . find ( opt =>
opt . text . toLowerCase (). includes ( "pizza" ) ||
opt . text . toLowerCase (). includes ( "yes" )
);
if ( preferredOption ) {
await sdk . polls . vote ({
chatGuid: chat . guid ,
pollMessageGuid: message . guid ,
optionIdentifier: preferredOption . optionIdentifier ,
});
console . log ( `Smart-voted for: ${ preferredOption . text } ` );
}
});
Poll Best Practices
Poll options should be short and clear: // Good
options : [ "Yes" , "No" , "Maybe" ]
// Too long
options : [
"Yes, I definitely want to attend the meeting" ,
"No, I cannot make it to the meeting" ,
]
Too many options make polls hard to read: // Good: 2-6 options
options : [ "Mon" , "Tue" , "Wed" , "Thu" , "Fri" ]
// Too many: > 10 options
Give the poll time to render before voting: const poll = await sdk . polls . create ({ ... });
await new Promise ( r => setTimeout ( r , 2000 )); // Wait 2 seconds
await sdk . polls . vote ({ ... });
You can only vote once per poll. Voting again will change your vote to the new option.
Store poll GUIDs and option identifiers in a database if you need to reference them later.
Changing Your Vote
To change your vote, simply vote again with a different option:
// Initial vote
await sdk . polls . vote ({
chatGuid: CHAT_GUID ,
pollMessageGuid: pollGuid ,
optionIdentifier: option1 ,
});
// Change vote
await sdk . polls . vote ({
chatGuid: CHAT_GUID ,
pollMessageGuid: pollGuid ,
optionIdentifier: option2 , // Different option
});
Troubleshooting
Common issues:
“Could not find option identifier” - Make sure to fetch the poll with payloadData:
const poll = await sdk . messages . getMessage ( guid , { with: [ "payloadData" ] });
Poll not displaying - Ensure recipient is using a compatible iOS version (iOS 14+)
Vote not registering - Wait a moment after creating a poll before voting
Next Steps
Rich Links Send link previews
Group Chats Create polls in groups