LTX-2.3: ID LoRA
Generate personalized videos with synchronized audio from a text prompt, reference image, and short audio clip. Use ID-LoRA to adapt a person's appearance and voice in a single generative model.
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_id_lora",
"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": 859064592499272
},
"_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": False,
"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:306": {
"class_type": "CLIPTextEncode",
"inputs": {
"clip": [
"340:318",
0
],
"text": [
"340:319",
0
]
},
"_meta": {
"title": "CLIP Text Encode (Prompt)"
}
},
"340:307": {
"class_type": "LTXVConditioning",
"inputs": {
"frame_rate": [
"340:304",
0
],
"negative": [
"340:349",
2
],
"positive": [
"340:349",
1
]
},
"_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:349",
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": "[VISUAL]: A medium close-up of the woman with the chin-length black bob and mustard-yellow turtleneck, seated in a warm, softly lit studio with an olive and terracotta backdrop. The camera slowly pushes in toward her face. She looks straight into the lens, raises her eyebrows with a small knowing smile, speaks naturally with clear, relaxed lip movement, tilts her head slightly to one side on the last line and lets out a short, soft laugh.\n[SPEECH]: You know what? I've been thinking about it all week, and I'm finally ready to say it out loud. Let's do it. Let's actually go.\n[SOUNDS]: Warm, confident and slightly playful tone, moderate volume, close to the microphone, quiet room tone, no music."
},
"_meta": {
"title": "Prompt"
}
},
"340:323": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 25
},
"_meta": {
"title": "Frame Rate"
}
},
"340:324": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 720
},
"_meta": {
"title": "Height"
}
},
"340:325": {
"class_type": "LTXVImgToVideoInplace",
"inputs": {
"bypass": False,
"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:348",
0
],
"video_latent": [
"340:325",
0
]
},
"_meta": {
"title": "Concat AV Latent"
}
},
"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: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:346": {
"class_type": "LoraLoaderModelOnly",
"inputs": {
"lora_name": "ltx-2.3-id-lora-talkvid-3k.safetensors",
"model": [
"340:293",
0
],
"strength_model": 1
},
"_meta": {
"title": "Load LoRA"
}
},
"340:348": {
"class_type": "LTXVEmptyLatentAudio",
"inputs": {
"audio_vae": [
"340:335",
0
],
"batch_size": 1,
"frame_rate": [
"340:304",
1
],
"frames_number": [
"340:329",
1
]
},
"_meta": {
"title": "Empty LTXV Latent Audio"
}
},
"340:349": {
"class_type": "LTXVReferenceAudio",
"inputs": {
"audio_vae": [
"340:335",
0
],
"end_percent": 1,
"identity_guidance_scale": 3,
"model": [
"340:346",
0
],
"negative": [
"340:314",
0
],
"positive": [
"340:306",
0
],
"reference_audio": [
"276",
0
],
"start_percent": 0
},
"_meta": {
"title": "LTXV Reference Audio (ID-LoRA)"
}
}
})
workflow.set_input("276", "audio", client.assets.from_url("https://comfy.org/catalog-media/2772b54a-6108-4ec3-a76b-773a45315b2c/29fe5499-d563-4b33-8cb1-cd6781844da9"))
workflow.set_input("269", "image", client.assets.from_url("https://comfy.org/catalog-media/92d08eb8-7bfe-46d5-8763-998fd1e87571/9333bfba-4ff2-4496-a5e1-17cb0c41f904"))
# 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 builds personalized, lip-synced video clips by conditioning LTX-2.3 on three inputs: a reference image (appearance), a short audio clip (timing and vocal style), and a structured prompt (scene, transcript, and sound context). The core logic is encapsulated in a subgraph (the custom node with ID 98ee9e5b-467b-40aa-a534-36033f27d0b4), which orchestrates LTX-2.3 generation with ID-LoRA identity conditioning. LoadImage provides the face/pose reference, LoadAudio or RecordAudio supplies your speech, and SaveVideo writes the final video.
A MarkdownNote in the canvas summarizes the structured prompt format and links to the LTX-2.3 and ID-LoRA resources.
Technically, ID-LoRA injects a lightweight identity adapter into the LTX-2.3 video diffusion process so the generated person matches the reference image without a full fine-tune. The prompt is split into three tags the subgraph expects: [VISUAL] (scene and appearance), [SPEECH] (the exact words to say), and [SOUNDS] (speaker style and ambient cues). The audio drives mouth shapes and timing, while [SPEECH] helps the model resolve phoneme-level detail for clearer lip articulation.
The result is a short video of your subject speaking the provided line, visually aligned to the reference image and temporally synced to the audio.
Questions & answers
No full training is required. The workflow uses ID-LoRA as a lightweight identity adapter applied at generation time. Provide a high-quality reference image to improve likeness.
Use three tags: [VISUAL] for scene and appearance details, [SPEECH] for the exact words to say (match your audio), and [SOUNDS] for the speaker’s vocal style and any ambient room tone. A precise [SPEECH] section helps produce clearer lip shapes.
Use a clean, dry voice recording (no background music), speak at a steady pace, and ensure the [SPEECH] transcript matches the audio exactly. Choose a front-facing, well-lit reference image so the mouth region is clear.
The workflow drives visual sync from your audio. Whether the final video file contains an embedded audio track depends on the SaveVideo configuration in your setup. If you get a silent video, you can mux the original audio in a video editor or unpack the subgraph to integrate audio muxing.