Burned-in captions are part of the video pixels. If you are replacing captions in footage you own or are authorized to edit, you need a processing step before adding the new text. If your subtitles are a separate SRT, VTT, or subtitle track, remove or disable that track instead.
This walkthrough connects n8n to an asynchronous video-processing API. The interesting parts are the boundaries: validating inputs before spending money, separating preview from execution, waiting for an import to finish, and recovering from a timeout without blindly creating another paid job.
Disclosure: I’m the maker of UnMarkAI, the API used in this example.
What you will build
The workflow takes one directly downloadable HTTPS video URL and returns a temporary result URL. It uses 19 executable built-in n8n nodes, with Sticky Notes explaining setup. You do not need a community node, webhook, or schedule.
The route is:
Validate the configuration.
If paid execution is disabled, return a preview and stop.
Import the video URL and poll the upload.
Create a text-removal job only after the upload is ready.
Poll that job, then return its result URL.
The supplied JSON starts in preview mode. That branch makes zero UnMarkAI API requests. This is a statement about the workflow branch, not n8n's own background network activity.
1 Import the workflow
Open the public n8n template: Remove burned-in video captions from HTTPS videos with UnMarkAI
Use the template page to open or copy the workflow into your n8n instance. If you have exported the workflow as JSON, use n8n’s Import from File option. Keep the workflow manual while you test.
The workflow uses built-in n8n nodes and was imported and run in n8n Cloud. Review the imported nodes in your own n8n version before enabling paid execution.
2 Configure the example then preview it
Open Configure Video. Its JSON is:
{
"source_url": "https://unmarkai.net/videos/text-removal-cases/tutorial-captions/before.mp4",
"filename": "tutorial-captions.mp4",
"mode": "sel_area",
"source_width": 1280,
"source_height": 720,
"rect": {"x1": 44, "y1": 520, "x2": 1236, "y2": 708},
"execute_paid_job": false,
"request_key": "CHANGE_ME_FOR_EACH_NEW_VIDEO_AND_SETTINGS",
"upload_max_polls": 60,
"upload_timeout_seconds": 300,
"job_max_polls": 180,
"job_timeout_seconds": 1800
}
Leave execute_paid_job as the JSON boolean false, not the string "false". Execute the workflow manually. Preview Only should return status: "preview_only" and api_requests_made: 0, together with the proposed import and job request bodies.
Preview validates the local configuration and shows the intended requests. It does not test your API key, download the source, confirm the wallet balance, or predict the output quality. Some n8n versions may require credentials on HTTP nodes before allowing a complete workflow run; if so, complete the credential step below and keep the paid flag false.
The example is a 12-second, 1280 × 720 video. Its rectangle uses coordinates in the original source frame: top-left (44, 520), bottom-right (1236, 708). It covers a 1192 × 188 pixel band, about 24% of the frame. These coordinates should not be reused for a different video without checking its dimensions and caption position.
For other sources:
sel_area takes one rectangle and this workflow limits it to half the frame.
multi_area takes an array of one to three non-overlapping rectangles.
all_area requires rect: null.
Validate Settings rejects inverted or out-of-bounds rectangles, invalid dimensions, unsupported modes, and malformed settings before reaching an HTTP node. It trusts the dimensions you provide; it does not measure the video for you.
Use a direct HTTPS video file, not a YouTube page, TikTok page, or player page. A URL that works in your logged-in browser may not be publicly fetchable by the API. Do not expose confidential footage merely to fit this example. A private-source integration needs a separately designed upload path and appropriate access controls.
3 Store your own API key in n8n
Use your own UnMarkAI account and API wallet. In the API console, create or select an API key with jobs:read and jobs:write. If you separately call the balance endpoint, use a key with the required balance-read permission too.
In n8n, create a Header Auth credential:
Header name: Authorization
Header value: Bearer YOUR_API_KEY, replacing YOUR_API_KEY with your key and keeping the space after Bearer
Select it on these four nodes:
Import Video URL
Get Upload
Create Remove Text Job
Get Job
They are configured for Generic Credential Type → Header Auth. n8n’s credential documentation explains the name/value fields.
Enter the secret only in the credential interface. Do not add it to Configure Video, exported JSON, screenshots, source control, or a browser-side application. Before sharing an export, inspect it for credential names, IDs, and any manually entered authentication headers.
4 Understand the two asynchronous operations
The API base is https://api.unmarkai.net/v1. The workflow first submits:
POST /v1/url-uploads
{
"source_url": "https://unmarkai.net/videos/text-removal-cases/tutorial-captions/before.mp4",
"filename": "tutorial-captions.mp4"
}
Keep Upload ID saves the response’s upload_id. Get Upload reads /v1/uploads/{upload_id}. The upload loop continues for pending or importing, stops with an error for failed or expired, and proceeds only for uploaded.
That distinction matters: accepting an import request does not mean the video is ready for processing.
Build Job Request then constructs:
{
"type": "remove_text",
"input": {"upload_id": "<the completed upload_id>"},
"mode": "sel_area",
"rect": {"x1": 44, "y1": 520, "x2": 1236, "y2": 708}
}
Create Remove Text Job sends this to POST /v1/jobs. Keep Job ID saves the returned id, and Get Job reads /v1/jobs/{id}.
The job loop accepts validating, queued, and processing as ongoing states. It reports failed or canceled as errors. On succeeded, it checks that the response belongs to the expected job and contains an HTTPS result.url before continuing.
You can compare this sequence with the official REST examples. The workflow adds bounded waiting and a preview branch around that API lifecycle.
5 Enable one paid run deliberately
Before running, check your current API wallet balance and rates in the console or the documented GET /v1/balance endpoint. API USD billing is separate from website points. The workflow does not implement a spending cap or automatically check the balance.
Set request_key to a new stable identifier for this exact source and settings, for example caption-demo-20261008-001. Then change execute_paid_job to true and run once manually.
The workflow derives two separate idempotency keys:
caption-demo-20261008-001:upload
caption-demo-20261008-001:remove-text
Each POST sends its key in an Idempotency-Key header. Keep the key and identical request body when recovering an ambiguous request. If the source or settings intentionally change, treat that as a new operation. Idempotency has a limited server-side retention window; it is not permanent deduplication.
Do not respond to an uncertain outcome by repeatedly clicking Execute with new keys. Inspect the existing upload or job first.
What the real test established
On October 7, 2026, a real n8n run using this 12-second selected-area example reached API status succeeded. The final settled API charge was US$0.045. That is one historical transaction, not a quote for your account or future work. See the API overview and check live rates before spending.
The returned MP4 from that run was not visually reviewed, so that test establishes end-to-end execution and settlement. Two separate 12-second cleanup tests on October 8 received visual review and showed some local smoothing or smearing. They do not establish flawless output or guarantee quality on a different source.
After testing, restore execute_paid_job to false and save the workflow.
6 Recover safely when waiting stops
Both polling loops begin with a five-second wait and increase up to 30 seconds, with shorter waits near the elapsed limit. Defaults allow up to 60 upload polls with a 300-second elapsed limit, and 180 job polls with an 1800-second elapsed limit. On a nonterminal response, either bound can stop local waiting.
Each HTTP request has a 30-second timeout. Elapsed limits are checked after responses; they are not exact wall-clock deadlines. Your n8n host or plan may end an execution earlier, so check its execution limits before processing longer videos.
Automatic HTTP retries are off. The workflow stops on HTTP errors and rejects unfamiliar status values rather than guessing what happened.
Authentication or scope error: check the credential selected on the failing node and the key’s permissions.
Insufficient balance: inspect the API wallet and decide whether to fund it. The workflow does not recharge it.
Import failure: inspect Get Upload and confirm that the source is a supported, reachable video file.
Invalid rectangle: compare the configured coordinates with the actual original frame dimensions.
Rate limit or transient error: wait and inspect the existing operation before retrying. Do not create a replacement paid job merely because a GET failed.
Polling or execution timeout: retain the upload/job ID. Read that same resource to learn its current state.
Stopping the n8n execution does not cancel the remote processing job. It may still finish and be billed. If a POST may have succeeded but its response was lost, preserve the original body and idempotency key, check the API console, and reconcile the result before starting another operation.
7 Download review and retain the result
Result URL returns result_url, job_id, upload_id, request_key, and job_idempotency_key, together with result details. Download the output promptly. The signed URL is temporary; reading the same job can refresh a link while the result is still retained. Do not create another paid job just to refresh a download URL.
Watch the complete output alongside the original. Check caption changes, scene cuts, fast motion, faces, fine edges, and background texture. Text removal reconstructs pixels, so a successful API response cannot tell you whether that reconstruction is acceptable for your use case. Store an approved output in your own durable storage.
Execution data can expose source URLs and signed download links. Limit access and set an appropriate execution-data retention policy.
For a production extension, persist the operation key, exact request body, upload ID, and job ID in durable storage before adding automatic triggers or batch processing. Add a human review step before publishing processed footage.
Example footage and editing rights
The existing before/after case is a separate published demonstration, not the visually unreviewed output from the October 7 n8n test. Its source credits Sururi Ballıdağ Director on Pexels; the demonstration captions were added by UnMarkAI. See the Pexels License.
Only process footage you own, license for editing, or have permission to modify. Preserve required attribution, provenance, and disclosures. This workflow prepares a result for review; publishing that result is a separate decision.
Top comments (0)