Wan 2.2 is an open video model, and a LoRA is the cheapest way to make it produce your style, character or product. On fal you do not need a GPU or a training script. You send a zip file to a trainer endpoint, get back a LoRA file, and pass that file to the Wan 2.2 inference endpoint. Both steps use the same queue API, so you can call them with cURL or Python.
This guide trains a text-to-video LoRA. The image-to-video trainer uses the same API flow, but requires video training data; image-only datasets are supported only by the text-to-video trainer.
What you need
- A fal account and an API key from the keys page, exported as
FAL_KEY. - 10 or more images or short video clips that show the style or subject you want.
- For Python, the client library:
pip install fal-client.
export FAL_KEY="your-api-key"The endpoints this guide uses
| Step | Endpoint ID | What it does |
|---|---|---|
| Train | fal-ai/wan-22-trainer/t2v-a14b | Trains a Wan 2.2 text-to-video LoRA |
| Train | fal-ai/wan-22-trainer/i2v-a14b | Trains a Wan 2.2 image-to-video LoRA |
| Inference | fal-ai/wan/v2.2-a14b/text-to-video/lora | Generates video with your LoRA loaded |
| Inference | fal-ai/wan/v2.2-a14b/image-to-video/lora | Animates an image with your LoRA loaded |
The trainers are listed on the model pages as "T2V 14B 480P" and "I2V 14B 480P".
Step 1: Prepare the dataset
The trainer takes one zip archive. Put your images or videos in it, and add an optional caption file for each one. A caption file is a .txt file with the same name as the media file it describes. The trainer captions any file that has no .txt file with a vision-language model.
The trainer reads .jpg, .jpeg, .png, .gif and .mp4 files, up to 1,000 per archive. It skips other formats, so convert .mov or .webp files before you zip them.
dataset.zip
├── 01.mp4
├── 01.txt
├── 02.mp4
├── 02.txt
├── 03.jpg
├── 03.txt
└── ...
Guidelines from the trainer's input schema, plus what usually helps:
- Use at least 10 files. The schema asks for at least 10 images or videos, and more is better.
- Keep the set consistent. Every file should show the style or subject you want the LoRA to learn. Mixed styles teach a mixed result.
- Write one caption per file. Describe the subject, action, setting and camera. Captions let the model learn what is your style and what is just content.
- Pick a trigger phrase. Use a rare token such as
sks_stylein every caption you supply, so you can switch the style on in prompts later. Settrigger_phraseto the same token if any captions will be auto-generated; it prefixes generated captions but does not modify captions you provide. - Normalize your clips. Wan 2.2 generates 81 frames at 16 fps by default, which is about 5 seconds. Set
auto_scale_input: trueto have the trainer resample each video to 81 frames at 16 fps. Resampling changes the speed of the motion: a 10-second clip plays twice as fast. Trim clips to about 5 seconds so the LoRA learns motion at its real speed. - Keep clips at least 4 seconds long if you leave
auto_scale_inputoff. The trainer skips videos that are shorter than 65 frames at 16 fps. If it skips every file, the job fails with "No trainable media was found". - Do not upscale your source. The trainer resizes all media to a small training resolution, so files above 720p only make the upload larger.
Zip the folder:
cd my-dataset && zip -r ../dataset.zip . && cd ..Step 2: Upload the dataset
The trainer reads the dataset from a URL. With Python, upload the zip to fal storage:
import fal_client
dataset_url = fal_client.upload_file("dataset.zip")
print(dataset_url)With cURL, any HTTPS URL that the trainer can download works, such as a pre-signed link from your own object storage.
Step 3: Start training
The trainer accepts five inputs:
| Input | Default | Notes |
|---|---|---|
training_data_url | required | URL of the zip from step 2 |
number_of_steps | 400 | More steps learn more detail and cost more. Scale it with dataset size |
learning_rate | 0.0002 | Higher values train faster but overfit sooner |
trigger_phrase | "" | Prefixes auto-generated captions; captions you supply are left as-is |
auto_scale_input | false | Rescales videos to 81 frames at 16 fps |
Training runs on the fal queue. Submit the job, then check its status until it completes.
cURL:
curl -X POST "https://queue.fal.run/fal-ai/wan-22-trainer/t2v-a14b" \
-H "Authorization: Key $FAL_KEY" \
-H "Content-Type: application/json" \
-d '{
"training_data_url": "https://your-bucket.example.com/dataset.zip",
"number_of_steps": 400,
"learning_rate": 0.0002,
"trigger_phrase": "sks_style",
"auto_scale_input": true
}'The response contains a request_id, a status_url and a response_url. Save the two URLs as STATUS_URL and RESPONSE_URL, and use them exactly as returned, because they can differ from the path you submitted to.
# Check progress (add ?logs=1 to include training logs)
curl "$STATUS_URL?logs=1" -H "Authorization: Key $FAL_KEY"
# When the status is COMPLETED, fetch the result
curl "$RESPONSE_URL" -H "Authorization: Key $FAL_KEY"Python:
import fal_client
def on_update(status):
if isinstance(status, fal_client.InProgress):
for log in status.logs or []:
print(log["message"])
result = fal_client.subscribe(
"fal-ai/wan-22-trainer/t2v-a14b",
arguments={
"training_data_url": dataset_url,
"number_of_steps": 400,
"learning_rate": 0.0002,
"trigger_phrase": "sks_style",
"auto_scale_input": True,
},
with_logs=True,
on_queue_update=on_update,
)
lora_url = result["lora_file"]["url"]
print(lora_url)For long jobs, use fal_client.submit(...) instead and keep the request ID, or pass a webhook_url so fal calls your server when training finishes.
The result has two files:
lora_file: the trained LoRA weights (.safetensors).config_file: a small JSON file with training metadata. The endpoints in this guide do not need it.
Step 4: Know the training cost and time
The trainer bills per training step, not per GPU-hour. As published on the trainer's model page on October 15, 2026:
| Trainer | Price per step | Minimum charge | 400 steps (default) | 1,000 steps |
|---|---|---|---|---|
fal-ai/wan-22-trainer/t2v-a14b | $0.004 | 100 steps | $1.60 | $4.00 |
fal-ai/wan-22-trainer/i2v-a14b | $0.005 | 100 steps | $2.00 | $5.00 |
Because the cost is linear in number_of_steps, you can price a run before you start it. Check the model page for the current rate.
The model page does not publish a training duration. Duration depends on the step count and the size of your dataset. Watch the request status and logs to see how long your runs take, and use a webhook rather than holding a connection open.
Step 5: Call your LoRA as an API
Pass the lora_file URL in the loras array of the Wan 2.2 LoRA endpoint. Start the prompt with your trigger phrase.
Each entry in loras takes:
path: the URL of your.safetensorsfile.scale: the LoRA strength. The default is 1.transformer: which Wan 2.2 transformer loads the LoRA. Wan 2.2 A14B has a high-noise and a low-noise transformer, and the options arehigh(the endpoint default),lowandboth. This trainer fine-tunes only the low-noise transformer, so set this tolowfor the LoRA trained above.
cURL:
curl -X POST "https://queue.fal.run/fal-ai/wan/v2.2-a14b/text-to-video/lora" \
-H "Authorization: Key $FAL_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "sks_style, a lighthouse on a cliff at dusk, waves crashing below, slow dolly-in",
"loras": [
{
"path": "https://v3.fal.media/files/.../your_lora.safetensors",
"scale": 1.0,
"transformer": "low"
}
],
"resolution": "720p",
"aspect_ratio": "16:9",
"num_frames": 81,
"frames_per_second": 16
}'Python:
video = fal_client.subscribe(
"fal-ai/wan/v2.2-a14b/text-to-video/lora",
arguments={
"prompt": "sks_style, a lighthouse on a cliff at dusk, waves crashing below, slow dolly-in",
"loras": [{"path": lora_url, "scale": 1.0, "transformer": "low"}],
"resolution": "720p",
"aspect_ratio": "16:9",
"num_frames": 81,
"frames_per_second": 16,
},
)
print(video["video"]["url"])The response contains video (the generated file) and seed. Reuse the seed to compare the same prompt with and without your LoRA. Set scale to 0 for the "without" run so that everything else stays the same.
By default, the endpoint adds one interpolated frame between each pair of generated frames and doubles the frame rate. A request for 81 frames at 16 fps therefore returns a video of about 161 frames at 32 fps. The video is still about 5 seconds long. Set num_interpolated_frames to 0 to get the raw 16 fps output.
The LoRA endpoint is billed at $0.10 per second of video at 720p, as shown on its model page on October 15, 2026. The billed length is num_frames divided by 16, so the default 81 frames costs about $0.51. Lower resolutions cost less: 580p is billed at 0.75 times the 720p rate and 480p at half the rate, about $0.25 for 81 frames. Interpolated frames are not billed.
Your LoRA file is a plain URL, so one endpoint can serve any number of LoRAs. Store the URL with your user or project, and pass the right one on each request. There is nothing to deploy and no GPU to keep warm.
Tips for a better LoRA
- Start with the defaults. Run 400 steps at a learning rate of 0.0002 first, then change one setting at a time.
- Scale steps with the dataset. A small dataset overfits with too many steps, and a large one needs more steps to learn.
- Compare with the same seed. Generate the same prompt and seed at
scale0 and atscale1 to see what the LoRA changes. - Test at 480p. A 480p video costs half as much as a 720p one. Compare LoRAs and scales at 480p, then render the final video at 720p.
- Load the LoRA into the right transformer. This trainer trains the low-noise transformer only. The endpoint default is
high, which loads the LoRA into the high-noise transformer that it was not trained for, so always settransformertolow. - Lower the scale if outputs look burned in. A scale between 0.6 and 0.9 often keeps the style while giving the prompt more control.
FAQ
How many images or videos do I need to fine-tune Wan?
The trainer's schema asks for at least 10 images or videos, and more is better. Consistency matters more than volume. Ten clean, on-style examples beat fifty mixed ones.
How much does it cost to fine-tune Wan 2.2 on fal?
Both trainers bill per step, with a 100-step minimum. At the rates published on October 15, 2026, the default 400-step run costs $1.60 on the text-to-video trainer ($0.004 per step) and $2.00 on the image-to-video trainer ($0.005 per step). After training, each 81-frame 720p video costs about $0.51 on the LoRA endpoint.
Can I use the LoRA with image-to-video?
Train with fal-ai/wan-22-trainer/i2v-a14b if you plan to animate still images. A LoRA learns under the conditioning it was trained with, so match the trainer to how you will run inference. The image-to-video trainer needs video clips in the dataset; it rejects image-only datasets. To run the LoRA, call fal-ai/wan/v2.2-a14b/image-to-video/lora with an image_url and the same loras array, with transformer set to low.
Why does training fail with "No trainable media was found"?
The trainer did not find a file that it can train on. Check that the archive contains .jpg, .jpeg, .png, .gif or .mp4 files. If you use video clips and leave auto_scale_input off, check that the clips are at least 65 frames (about 4 seconds at 16 fps) long, or set auto_scale_input to true.
Do I have to deploy anything to use my LoRA?
No. The trained LoRA is a file URL. You pass it in the loras array of the Wan 2.2 LoRA endpoint on each request, and fal loads it for you.



