← Back to list
🎬

faceswap Checked

Swap faces in a video using AI via the HeyGen API. Use when: (1) Replacing a face in a video with…
🎬 Video & Motion skills By calesthio Version v1.0.0 Added 2026-09-07 Updated 2026-09-07 Source ↗
8.7Overall rating
2Views
6Downloads
56.5kStars

Installation

🤖 Install via AI

Copy the prompt below and send it to your AI assistant (e.g. Claude Code) — it will follow the instructions and install automatically.

Install the "faceswap" skill by following the instructions at https://skill123.me/install/faceswap.
⌨️ Command line install

Run in your terminal — downloads and installs to ~/.claude/skills/.

curl -fsSL https://skill123.me/install/faceswap.sh | bash
📦 Download ZIP

Download the zip and extract it into your skills directory (e.g. ~/.claude/skills/), then restart your session.

⬇ Download v1.0.0 · 2 KB
📊 Static rating
8.7/10
Trigger
6.5
Structure
9.3
Workflow
8.4
Content
9.0
Engineering
10.0
Security
10.0

Six-dimension rubric with reviewer rationale.

View scorecard ↓
🛡 Dynamic test
—

Not live-tested yet — this skill is rated on static analysis only.

About this skill

Swap faces in a video using AI via the HeyGen API. Use when: (1) Replacing a face in a video with another face, (2) Face swapping from a source image onto a target video, (3) Creating personalized videos by swapping in a person's face, (4) Working with HeyGen's /v1/workflows/executions endpoint for face swap processing.

Face Swap (HeyGen API)

Swap a face from a source image into a target video using GPU-accelerated AI processing. The source image provides the face to swap in, and the target video receives the new face.

Documentation

Swap faces in a video using AI via the HeyGen API. Use when: (1) Replacing a face in a video with another face, (2) Face swapping from a source image onto a target video, (3) Creating personalized videos by swapping in a person's face, (4) Working with HeyGen's /v1/workflows/executions endpoint for face swap processing.

Face Swap (HeyGen API)

Swap a face from a source image into a target video using GPU-accelerated AI processing. The source image provides the face to swap in, and the target video receives the new face.

Authentication

All requests require the X-Api-Key header. Set the HEYGEN_API_KEY environment variable.


curl -X POST "https://api.heygen.com/v1/workflows/executions" \
  -H "X-Api-Key: $HEYGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"workflow_type": "FaceswapNode", "input": {"source_image_url": "https://example.com/face.jpg", "target_video_url": "https://example.com/video.mp4"}}'

Default Workflow

1. Call POST /v1/workflows/executions with workflow_type: "FaceswapNode", a source face image, and a target video

2. Receive a execution_id in the response

3. Poll GET /v1/workflows/executions/{id} every 10 seconds until status is completed

4. Use the returned video_url from the output

Execute Face Swap

### Endpoint

POST https://api.heygen.com/v1/workflows/executions

### Request Fields

| Field | Type | Req | Description |

|-------|------|:---:|-------------|

| workflow_type | string | Y | Must be "FaceswapNode" |

| input.source_image_url | string | Y | URL of the face image to swap in |

| input.target_video_url | string | Y | URL of the video to apply the face swap to |

### curl


curl -X POST "https://api.heygen.com/v1/workflows/executions" \
  -H "X-Api-Key: $HEYGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "workflow_type": "FaceswapNode",
    "input": {
      "source_image_url": "https://example.com/face-photo.jpg",
      "target_video_url": "https://example.com/original-video.mp4"
    }
  }'

### TypeScript


interface FaceswapInput {
  source_image_url: string;
  target_video_url: string;
}

interface ExecuteResponse {
  data: {
    execution_id: string;
    status: "submitted";
  };
}

async function faceswap(input: FaceswapInput): Promise<string> {
  const response = await fetch("https://api.heygen.com/v1/workflows/executions", {
    method: "POST",
    headers: {
      "X-Api-Key": process.env.HEYGEN_API_KEY!,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      workflow_type: "FaceswapNode",
      input,
    }),
  });

  const json: ExecuteResponse = await response.json();
  return json.data.execution_id;
}

### Python


import requests
import os
View full documentation

def faceswap(source_image_url: str, target_video_url: str) -> str:

payload = {

"workflow_type": "FaceswapNode",

"input": {

"source_image_url": source_image_url,

"target_video_url": target_video_url,

},

}

response = requests.post(

"https://api.heygen.com/v1/workflows/executions",

headers={

"X-Api-Key": os.environ["HEYGEN_API_KEY"],

"Content-Type": "application/json",

},

json=payload,

)

data = response.json()

return data["data"]["execution_id"]



### Response Format

{

"data": {

"execution_id": "node-gw-f1s2w3p4",

"status": "submitted"

}

}



## Check Status

### Endpoint

`GET https://api.heygen.com/v1/workflows/executions/{execution_id}`

### curl

curl -X GET "https://api.heygen.com/v1/workflows/executions/node-gw-f1s2w3p4" \

-H "X-Api-Key: $HEYGEN_API_KEY"



### Response Format (Completed)

{

"data": {

"execution_id": "node-gw-f1s2w3p4",

"status": "completed",

"output": {

"video_url": "https://resource.heygen.ai/faceswap/output.mp4"

}

}

}



## Polling for Completion

async function faceswapAndWait(

input: FaceswapInput,

maxWaitMs = 600000,

pollIntervalMs = 10000

): Promise<string> {

const executionId = await faceswap(input);

console.log(Submitted face swap: ${executionId});

const startTime = Date.now();

while (Date.now() - startTime < maxWaitMs) {

const response = await fetch(

https://api.heygen.com/v1/workflows/executions/${executionId},

{ headers: { "X-Api-Key": process.env.HEYGEN_API_KEY! } }

);

const { data } = await response.json();

switch (data.status) {

case "completed":

return data.output.video_url;

case "failed":

throw new Error(data.error?.message || "Face swap failed");

case "not_found":

throw new Error("Workflow not found");

default:

await new Promise((r) => setTimeout(r, pollIntervalMs));

}

}

throw new Error("Face swap timed out");

}



## Usage Examples

### Basic Face Swap

curl -X POST "https://api.heygen.com/v1/workflows/executions" \

-H "X-Api-Key: $HEYGEN_API_KEY" \

-H "Content-Type: application/json" \

-d '{

"workflow_type": "FaceswapNode",

"input": {

"source_image_url": "https://example.com/headshot.jpg",

"target_video_url": "https://example.com/presentation.mp4"

}

}'



### Chain with Avatar Video

Generate an avatar video first, then swap in a custom face:

import time

Step 1: Generate avatar video

avatar_execution_id = requests.post(

"https://api.heygen.com/v1/workflows/executions",

headers={"X-Api-Key": os.environ["HEYGEN_API_KEY"], "Content-Type": "application/json"},

json={

"workflow_type": "AvatarInferenceNode",

"input": {

"avatar": {"avatar_id": "Angela-inblackskirt-20220820"},

"audio_list": [{"audio_url": "https://example.com/speech.mp3"}],

},

},

).json()["data"]["execution_id"]

Step 2: Wait for avatar video to complete

while True:

status = requests.get(

f"https://api.heygen.com/v1/workflows/executions/{avatar_execution_id}",

headers={"X-Api-Key": os.environ["HEYGEN_API_KEY"]},

).json()["data"]

if status["status"] == "completed":

avatar_video_url = status["output"]["video"]["video_url"]

break

time.sleep(10)

Step 3: Swap in a custom face

faceswap_execution_id = faceswap(

source_image_url="https://example.com/custom-face.jpg",

target_video_url=avatar_video_url,

)



## Best Practices

1. **Use a clear, front-facing face photo** — the source image should show a single face with good lighting
2. **Face swap is GPU-intensive** — expect 1-3 minutes processing time, poll every 10 seconds
3. **Source image quality matters** — higher resolution face photos produce better results
4. **One face per source image** — the source should contain exactly one face to swap in
5. **Works with any video** — the target video can be an avatar video, a recording, or any video with visible faces
6. **Chain with other workflows** — generate an avatar video first, then swap in a custom face for personalization

Score breakdown

Trigger
6.5
Four explicit When scenarios and endpoint keyword, but no When-Not and limited synonym variety.
Structure
9.3
Compact 261-line single file, no redundant files, nothing needing offload.
Workflow
8.4
Clear submit-poll-consume workflow, code handles failed, not_found and timeout states, completion status acts as verification.
Content
9.0
Concise imperative docs with runnable curl, TypeScript and Python examples and field tables.
Engineering
10.0
Valid frontmatter with allowed-tools and env metadata; no scripts or file references to verify.
Security
10.0
Official api.heygen.com endpoints only, API key strictly via environment variable, no injection or secrets.
Clean single-file HeyGen API wrapper with numbered workflow, robust polling code handling failed and timeout states; only gaps are missing When-Not boundaries and any local file staging guidance.