Skip to main content
Generate a conversation from message content and pacing settings. The service renders the native iPhone XS / iOS 18.6.2 interface, including its keyboard, bubbles, emoji input, replies, and reactions. It returns a downloadable video or a lossless PNG at a chosen point in the same conversation. Use ugcinc version 4.27.0 or later. Restricted API keys need content:render. Set your organization in the client configuration. This creates a synthetic rendering; it does not send messages to anyone.

Generate and download a video

Submission is asynchronous. The initial response contains a job ID, not a finished video. Poll until completed, failed, or cancelled; only a completed job has an output URL. Production clients can add their own polling deadline or abort controls. The contract is described in the complete input and result reference. For direct HTTP clients, see submit a render, read status, and cancel a render.

Choose message content and pacing

For a direct chat, user is the person operating the phone and recipient is the other person. Messages render in array order. Put preexisting messages first with initial: true; they are already visible when the video begins. timing supplies defaults for the conversation. A message’s own timing overrides only the fields it contains. charactersPerSecond counts complete visible grapheme clusters, so typing never splits a compound emoji or combining character. variation and seed control reproducible pacing variation. pauseBeforeMs controls the wait before the next message begins. Use it to leave more breathing room after an exchange. pauseBeforeSendMs pauses after typing finishes. Native send, reply, and picker transitions also reserve time; a zero pause does not remove those transitions. endHoldMs holds the finished scene. For incoming replies, incomingTypingDurationMs controls the interval from the typing indicator starting to the message arriving. It replaces the calculated incoming duration. showIncomingTyping: false, or a message’s showTyping: false, hides the indicator while retaining the response delay. Outgoing emoji automatically open the native emoji keyboard, select the emoji, and return to letters when subsequent text needs it. Use keyboardSwitchPauseMs and emojiSelectionDelayMs to control those pauses. Outgoing emoji and animated local replies require keyboard: true.

Add replies, receipts, and reactions

Give messages stable IDs and set replyTo to an earlier ID. A local reply shows the native long-press menu, selects Reply, and types in the reply view. Incoming and initial-history replies preserve the association without operating the local controls.
Receipts belong to outgoing messages. receipt: 'read' requires readAt; do not send readAt for other receipt states. receiptDelayMs controls the delay after arrival. The visible native receipt belongs to the latest outgoing message, so an older receipt disappears when a newer outgoing message is sent. Reaction delayMs is relative to its message’s arrival, or video start for initial history. Local actors open the native picker and choose one of six classic reactions: love, like, dislike, laugh, emphasize, or question. menuDurationMs controls the visible selection pause. Native transitions can push a local picker later than its requested earliest opening time. Remote reactions arrive without opening a local menu and also support custom emoji. Use action: 'remove' without a reaction value to remove that actor’s existing reaction; another set replaces it. To display an expanded reply thread for reading, add a threads entry after the conversation has settled. Use plan.events to inspect the last event first; openAtMs must be at least 600 ms after every conversation event and after the conversation’s own reserved transitions. Thread windows cannot overlap. These read-only views do not support simultaneous typing or sending.

Create a group conversation

Provide group instead of contact. Participant IDs identify both message senders and reaction actors; include the local participant in the group.
Set avatarPngBase64 on the contact, group, or individual participants to use a PNG avatar. These are render inputs; they do not create or modify real contacts.

Change the phone appearance and conversation dates

statusBar controls the phone clock, Wi-Fi and cellular visibility/strength, battery fill, charging, and low-power appearance. Battery percentage controls the fill level; it does not enable a numerical percentage label. unreadCount controls the back-button badge. The conversation’s message count comes from messages.length. The phone clock and message dates are independent. timestampText sets the first conversation separator. Use each message’s sentAt for actual chronology; when used, every message needs a chronological ISO timestamp with a timezone. Native date-gap rules insert later separators. Set a message’s timestampText to force a separator before it with explicit text. Message dates do not make playback wait through that real-world time gap.

Include image messages

An individual message contains either text or imagePngBase64. Load a PNG as base64 without the data:image/png;base64, prefix. Image captions and mixed text/image message bodies are rejected.
Avatars must fit within 512 × 512 and 65,536 base64 characters. Message images must fit within 2048 × 2048 and 8 MiB of base64 characters. PNGs must be valid, single-frame images. The total request is limited to 16 MiB, with a combined message-image budget of 16,777,216 pixels. The worker validates decoded images in addition to the SDK’s local input validation.

Export a PNG from the same scene

Select an exact millisecond with output: {kind: 'png', atMs: ...}. Omit atMs to select the final authored frame. The timestamp must fit within the locally compiled durationMs.
Poll each job exactly as for video. PNG uses the native scene directly; it is not extracted from a lossy MP4. Video is 60 fps H264 at 1126 × 2436; PNG is 1125 × 2436. The video has one background-colored padding column for codec compatibility. Neither output accepts a custom resolution or frame rate.

Cancel or retry a job

Cancellation can be asynchronous. Continue polling until a terminal status; cancelRequested: true alone does not mean cleanup is complete. If the render already completed, its result is retained. For safe submission retries, supply an idempotencyKey. Repeating the same body and key in the same organization returns the same job. Changing any part of the body while reusing that key returns HTTP 409. Use a different key when changing the output kind or timestamp, or when requesting a fresh retry of a failed job. Job ownership records are retained for seven days.

Use Create DM in a workflow

In the automation builder, add Create DM, choose iMessage and its native conversation mode, and enter the conversation. The editor exposes common controls; Advanced JSON accepts the complete IMessageConversationInput object described here. Apply the JSON, verify the visible fields, and use the native preview before saving or running. For programmatic workflow definitions, configure the existing Create DM node with static platform: 'imessage', platformInputType: 'static', imessageRenderMode: 'conversation', and imessageConversation containing the input. Use imessageConversationInputType: 'variable' to connect the conversation object input instead. The output port is output: static video settings produce video, static PNG settings produce an image, and variable conversation settings expose an image-or-video output. The older still-image mode remains available for existing iMessage and Instagram workflows. Native conversation mode uses the same native service for preview and export. See the automation data structure for workflow graph fields and run an automation for submission.

Current boundaries

  • This profile provides the iPhone XS / iOS 18.6.2 appearance, not a newer iOS design.
  • Up to 30 messages, 6,000 animated grapheme clusters, 6,100 compiled events, and 120,000 ms of authored duration. Long content or slow pacing can exceed the limit.
  • No full-screen or bubble-send effects, custom fonts or coordinates, carrier name/network-type selection, numerical battery label, custom output dimensions, non-60fps video, or arbitrary low-level animation scripts.
  • Local reaction selection currently supports the six classic picker options; custom emoji reactions are for remote participants. Unsupported emoji input sequences reject instead of silently substituting another emoji.
  • Seeded timing plans are repeatable. Some reaction animation frames can still differ at the pixel level across independent renders; full pixel-identical reaction replay is not guaranteed.