LTX-2.3: Image Audio to Video
Upload an image and an audio file to generate a high-quality video with synchronized lip movements using LTX-2.3.
Inside the workflow
A read-only preview of the source template. Open it in Cloud to explore the nodes and make changes.
Loading the graph
Open full-size workflow preview- Output
- Video
- Author
- ComfyUI
Call this model from your code
The request below uses the same prepared graph and settings as the Playground. Each submission can start a paid run; do not automatically retry a submission whose outcome is unknown.
What you need
- Runs on
- Comfy Cloud
- Key
- COMFY_API_KEY
- Your files
- Uploaded by the code from their urls
Needs a paid Cloud plan and credits.
# Python 3.10+: pip install comfy-sdk==0.4.0
import os
from comfy_sdk import Comfy
api_key = os.environ.get("COMFY_API_KEY", "").strip()
if not api_key: raise RuntimeError("Set COMFY_API_KEY")
os.environ.setdefault("COMFY_BASE_URL", "https://cloud.comfy.org")
client = Comfy(api_key=api_key)
workflow = client.workflows.from_json({
"269": {
"class_type": "LoadImage",
"inputs": {
"image": "UPLOADED_image_FILENAME"
},
"_meta": {
"title": "Load Image"
}
},
"276": {
"class_type": "LoadAudio",
"inputs": {
"audio": "UPLOADED_audio_FILENAME"
},
"_meta": {
"title": "Load Audio"
}
},
"341": {
"class_type": "SaveVideo",
"inputs": {
"filename_prefix": "video/LTX_2.3_ia2v",
"format": "auto",
"format.codec": "auto",
"video": [
"340:312",
0
]
},
"_meta": {
"title": "Save Video"
}
},
"340:285": {
"class_type": "RandomNoise",
"inputs": {
"noise_seed": 42
},
"_meta": {
"title": "RandomNoise"
}
},
"340:286": {
"class_type": "RandomNoise",
"inputs": {
"noise_seed": 923652788975261
},
"_meta": {
"title": "RandomNoise"
}
},
"340:287": {
"class_type": "LTXVConcatAVLatent",
"inputs": {
"audio_latent": [
"340:309",
1
],
"video_latent": [
"340:296",
0
]
},
"_meta": {
"title": "Concat AV Latent"
}
},
"340:288": {
"class_type": "KSamplerSelect",
"inputs": {
"sampler_name": "euler_cfg_pp"
},
"_meta": {
"title": "KSamplerSelect"
}
},
"340:289": {
"class_type": "ManualSigmas",
"inputs": {
"sigmas": "0.85, 0.7250, 0.4219, 0.0"
},
"_meta": {
"title": "ManualSigmas"
}
},
"340:290": {
"class_type": "CFGGuider",
"inputs": {
"cfg": 1,
"model": [
"340:293",
0
],
"negative": [
"340:292",
1
],
"positive": [
"340:292",
0
]
},
"_meta": {
"title": "CFG Guider"
}
},
"340:291": {
"class_type": "SamplerCustomAdvanced",
"inputs": {
"guider": [
"340:315",
0
],
"latent_image": [
"340:326",
0
],
"noise": [
"340:286",
0
],
"sampler": [
"340:298",
0
],
"sigmas": [
"340:308",
0
]
},
"_meta": {
"title": "SamplerCustomAdvanced"
}
},
"340:292": {
"class_type": "LTXVCropGuides",
"inputs": {
"latent": [
"340:309",
0
],
"negative": [
"340:307",
1
],
"positive": [
"340:307",
0
]
},
"_meta": {
"title": "LTXVCropGuides"
}
},
"340:293": {
"class_type": "LoraLoaderModelOnly",
"inputs": {
"lora_name": "ltx-2.3-22b-distilled-lora-384.safetensors",
"model": [
"340:317",
0
],
"strength_model": 0.5
},
"_meta": {
"title": "Load LoRA"
}
},
"340:294": {
"class_type": "ResizeImagesByLongerEdge",
"inputs": {
"images": [
"340:297",
0
],
"longer_edge": 1536
},
"_meta": {
"title": "Resize Images by Longer Edge (DEPRECATED)"
}
},
"340:295": {
"class_type": "LTXVLatentUpsampler",
"inputs": {
"samples": [
"340:309",
0
],
"upscale_model": [
"340:313",
0
],
"vae": [
"340:317",
2
]
},
"_meta": {
"title": "LTXVLatentUpsampler"
}
},
"340:296": {
"class_type": "LTXVImgToVideoInplace",
"inputs": {
"bypass": [
"340:305",
0
],
"image": [
"340:334",
0
],
"latent": [
"340:295",
0
],
"strength": 1,
"vae": [
"340:317",
2
]
},
"_meta": {
"title": "LTXVImgToVideoInplace"
}
},
"340:297": {
"class_type": "ResizeImageMaskNode",
"inputs": {
"input": [
"269",
0
],
"resize_type": "scale dimensions",
"resize_type.crop": "center",
"resize_type.height": [
"340:324",
0
],
"resize_type.width": [
"340:330",
0
],
"scale_method": "lanczos"
},
"_meta": {
"title": "Resize Image/Mask"
}
},
"340:298": {
"class_type": "KSamplerSelect",
"inputs": {
"sampler_name": "euler_ancestral_cfg_pp"
},
"_meta": {
"title": "KSamplerSelect"
}
},
"340:299": {
"class_type": "ComfyMathExpression",
"inputs": {
"expression": "a/2",
"values.a": [
"340:330",
0
]
},
"_meta": {
"title": "Math Expression"
}
},
"340:301": {
"class_type": "ComfyMathExpression",
"inputs": {
"expression": "a/2",
"values.a": [
"340:324",
0
]
},
"_meta": {
"title": "Math Expression"
}
},
"340:302": {
"class_type": "EmptyLTXVLatentVideo",
"inputs": {
"batch_size": 1,
"height": [
"340:301",
1
],
"length": [
"340:329",
1
],
"width": [
"340:299",
1
]
},
"_meta": {
"title": "Empty LTXV Latent Video"
}
},
"340:303": {
"class_type": "LTXVAudioVAEDecode",
"inputs": {
"audio_vae": [
"340:335",
0
],
"samples": [
"340:311",
1
]
},
"_meta": {
"title": "LTXV Audio VAE Decode"
}
},
"340:304": {
"class_type": "ComfyMathExpression",
"inputs": {
"expression": "a",
"values.a": [
"340:323",
0
]
},
"_meta": {
"title": "Math Expression"
}
},
"340:305": {
"class_type": "PrimitiveBoolean",
"inputs": {
"value": False
},
"_meta": {
"title": "Switch to Text to Video?"
}
},
"340:306": {
"class_type": "CLIPTextEncode",
"inputs": {
"clip": [
"340:318",
0
],
"text": [
"340:342",
0
]
},
"_meta": {
"title": "CLIP Text Encode (Prompt)"
}
},
"340:307": {
"class_type": "LTXVConditioning",
"inputs": {
"frame_rate": [
"340:304",
0
],
"negative": [
"340:314",
0
],
"positive": [
"340:306",
0
]
},
"_meta": {
"title": "LTXVConditioning"
}
},
"340:308": {
"class_type": "ManualSigmas",
"inputs": {
"sigmas": "1.0, 0.99375, 0.9875, 0.98125, 0.975, 0.909375, 0.725, 0.421875, 0.0"
},
"_meta": {
"title": "ManualSigmas"
}
},
"340:309": {
"class_type": "LTXVSeparateAVLatent",
"inputs": {
"av_latent": [
"340:291",
0
]
},
"_meta": {
"title": "Separate AV Latent"
}
},
"340:310": {
"class_type": "SamplerCustomAdvanced",
"inputs": {
"guider": [
"340:290",
0
],
"latent_image": [
"340:287",
0
],
"noise": [
"340:285",
0
],
"sampler": [
"340:288",
0
],
"sigmas": [
"340:289",
0
]
},
"_meta": {
"title": "SamplerCustomAdvanced"
}
},
"340:311": {
"class_type": "LTXVSeparateAVLatent",
"inputs": {
"av_latent": [
"340:310",
0
]
},
"_meta": {
"title": "Separate AV Latent"
}
},
"340:312": {
"class_type": "CreateVideo",
"inputs": {
"audio": [
"340:303",
0
],
"bit_depth": "auto",
"codec": "none",
"color_space": "sRGB",
"fps": [
"340:304",
0
],
"images": [
"340:316",
0
]
},
"_meta": {
"title": "Create Video"
}
},
"340:313": {
"class_type": "LatentUpscaleModelLoader",
"inputs": {
"model_name": "ltx-2.3-spatial-upscaler-x2-1.1.safetensors"
},
"_meta": {
"title": "Load Latent Upscale Model"
}
},
"340:314": {
"class_type": "CLIPTextEncode",
"inputs": {
"clip": [
"340:318",
0
],
"text": "pc game, console game, video game, cartoon, childish, ugly"
},
"_meta": {
"title": "CLIP Text Encode (Prompt)"
}
},
"340:315": {
"class_type": "CFGGuider",
"inputs": {
"cfg": 1,
"model": [
"340:293",
0
],
"negative": [
"340:307",
1
],
"positive": [
"340:307",
0
]
},
"_meta": {
"title": "CFG Guider"
}
},
"340:316": {
"class_type": "VAEDecodeTiled",
"inputs": {
"overlap": 64,
"samples": [
"340:311",
0
],
"temporal_overlap": 4,
"temporal_size": 4096,
"tile_size": 768,
"vae": [
"340:317",
2
]
},
"_meta": {
"title": "VAE Decode (Tiled)"
}
},
"340:317": {
"class_type": "CheckpointLoaderSimple",
"inputs": {
"ckpt_name": "ltx-2.3-22b-dev-fp8.safetensors"
},
"_meta": {
"title": "Load Checkpoint"
}
},
"340:318": {
"class_type": "LTXAVTextEncoderLoader",
"inputs": {
"ckpt_name": "ltx-2.3-22b-dev-fp8.safetensors",
"device": "default",
"text_encoder": "gemma_3_12B_it_fp4_mixed.safetensors"
},
"_meta": {
"title": "Load LTXV Audio Text Encoder"
}
},
"340:319": {
"class_type": "PrimitiveStringMultiline",
"inputs": {
"value": "A black and white film-noir scene in one continuous medium close-up with no cuts. The woman sits still in a dark, bare room, looking straight into the camera as she speaks in a low, measured voice, her lips moving clearly with every word. Slatted light from unseen window blinds lies across her face, shoulders and the wall behind her, and the bars of light slowly crawl upward as if a car is passing outside. She pauses, glances briefly to her side, then looks back into the lens and lowers her voice for the last words. The camera holds steady at chest height with only a very slow, subtle push-in toward her face. Heavy film grain, a soft light flicker, quiet room tone, no music."
},
"_meta": {
"title": "Prompt"
}
},
"340:323": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 24
},
"_meta": {
"title": "Frame Rate"
}
},
"340:324": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 720
},
"_meta": {
"title": "Height"
}
},
"340:325": {
"class_type": "LTXVImgToVideoInplace",
"inputs": {
"bypass": [
"340:305",
0
],
"image": [
"340:334",
0
],
"latent": [
"340:302",
0
],
"strength": 0.7,
"vae": [
"340:317",
2
]
},
"_meta": {
"title": "LTXVImgToVideoInplace"
}
},
"340:326": {
"class_type": "LTXVConcatAVLatent",
"inputs": {
"audio_latent": [
"340:327",
0
],
"video_latent": [
"340:325",
0
]
},
"_meta": {
"title": "Concat AV Latent"
}
},
"340:327": {
"class_type": "SetLatentNoiseMask",
"inputs": {
"mask": [
"340:333",
0
],
"samples": [
"340:328",
0
]
},
"_meta": {
"title": "Set Latent Noise Mask"
}
},
"340:328": {
"class_type": "LTXVAudioVAEEncode",
"inputs": {
"audio": [
"340:332",
0
],
"audio_vae": [
"340:335",
0
]
},
"_meta": {
"title": "LTXV Audio VAE Encode"
}
},
"340:329": {
"class_type": "ComfyMathExpression",
"inputs": {
"expression": "a * b + 1",
"values.a": [
"340:331",
0
],
"values.b": [
"340:323",
0
]
},
"_meta": {
"title": "Math Expression"
}
},
"340:330": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 1280
},
"_meta": {
"title": "Width"
}
},
"340:331": {
"class_type": "PrimitiveFloat",
"inputs": {
"value": 10
},
"_meta": {
"title": "Duration"
}
},
"340:332": {
"class_type": "TrimAudioDuration",
"inputs": {
"audio": [
"276",
0
],
"duration": [
"340:331",
0
],
"start_index": 0
},
"_meta": {
"title": "Trim Audio Duration"
}
},
"340:333": {
"class_type": "SolidMask",
"inputs": {
"height": [
"340:324",
0
],
"value": 0,
"width": [
"340:330",
0
]
},
"_meta": {
"title": "Create Solid Mask"
}
},
"340:334": {
"class_type": "LTXVPreprocess",
"inputs": {
"image": [
"340:294",
0
],
"img_compression": 18
},
"_meta": {
"title": "LTXV Preprocess"
}
},
"340:335": {
"class_type": "LTXVAudioVAELoader",
"inputs": {
"ckpt_name": "ltx-2.3-22b-dev-fp8.safetensors"
},
"_meta": {
"title": "Load LTXV Audio VAE"
}
},
"340:342": {
"class_type": "TextGenerateLTX2Prompt",
"inputs": {
"clip": [
"340:344",
1
],
"image": [
"340:297",
0
],
"max_length": 256,
"mtp": "auto",
"prompt": [
"340:319",
0
],
"sampling_mode": "on",
"sampling_mode.min_p": 0.05,
"sampling_mode.repetition_penalty": 1.05,
"sampling_mode.seed": 0,
"sampling_mode.temperature": 0.7,
"sampling_mode.top_k": 64,
"sampling_mode.top_p": 0.95,
"thinking": False,
"use_default_template": True
},
"_meta": {
"title": "Generate LTX2 Prompt"
}
},
"340:343": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"340:342",
0
]
},
"_meta": {
"title": "Preview as Text"
}
},
"340:344": {
"class_type": "LoraLoader",
"inputs": {
"clip": [
"340:318",
0
],
"lora_name": "gemma-3-12b-it-abliterated_lora_rank64_bf16.safetensors",
"model": [
"340:317",
0
],
"strength_clip": 1,
"strength_model": 1
},
"_meta": {
"title": "Load LoRA (Model and CLIP)"
}
}
})
workflow.set_input("276", "audio", client.assets.from_url("https://comfy.org/catalog-media/b4b5b899-f01d-4073-aa7d-1b917d4e824c/e34f2188-1f07-41c4-b703-6d0c8498f5c9"))
workflow.set_input("269", "image", client.assets.from_url("https://comfy.org/catalog-media/1995606e-723b-4e08-973a-c04e4233a91b/1202f39f-be96-4b13-98cd-c054f6456f36"))
# run() also passes api_key to the partner nodes in this workflow.
job = client.run(workflow, api_key=api_key)
for output in job.get_outputs("341"):
output.to_file(output.name)Try an example
About this workflow
This ComfyUI workflow turns a single image and a voice recording into a lip-synced talking video using the LTX-2.3 model. You load a portrait with LoadImage and provide speech via LoadAudio or capture it live with RecordAudio. Both streams feed the LTX-2.3 generator node (98ee9e5b-467b-40aa-a534-36033f27d0b4), which synthesizes a sequence of frames where the subject speaks in time with the audio. The resulting frames are encoded to an MP4 using SaveVideo.
Under the hood, LTX-2.3 conditions on the visual identity from your reference image and the temporal features of the provided audio to drive mouth shapes and subtle facial motions over time. The node typically exposes settings like output resolution and FPS, and many builds also include a seed for reproducibility and an optional text prompt to guide motion or style. The MarkdownNote in the graph documents quick tips and links to the official Lightricks model repositories so you can download the required weights.
Questions & answers
Use a front-facing portrait with good lighting and the mouth unobstructed (no hands, mics, or heavy objects covering lips). Center the face and use a reasonable resolution (e.g., 512–1024 px on the short side). Avoid extreme angles and busy backgrounds.
Clean, speech-focused audio produces the most accurate mouth movements. WAV or high-bitrate MP3 typically work; mono voice tracks are preferred. Minimize reverb and background noise to improve alignment and realism.
That depends on your SaveVideo node build. Some variants can mux audio; others export a silent MP4. If yours is silent, combine the output video with the same audio in an editor or a separate muxing step.
Start with a clear, centered portrait and clean audio. Match FPS to your target platform (e.g., 24–30). If a prompt field is available, describe subtle motions (blinks, small head turns) to avoid a static look. Try different seeds for variety, and consider cropping the face tighter if the mouth region appears too small.