arkennemasis fal · ElevenLabs TTS Eleven v4 · $0.08/1k chars
The narration node, and the audio tags are the fun part
- audio
- audio_path
- timestamps
- info
Every serious video workflow hits the same wall: the picture is done and there's nothing to say over it. Local TTS has closed most of the gap - Chatterbox is genuinely competitive and cloneable from five seconds of audio - but the node here is the other side of that trade: you're paying per character to skip the setup, and you get the delivery control that open models still mostly make you fight for.
Eleven v4 is current, it's the cheapest of the newer ElevenLabs tiers in this pack at $0.08 per 1,000 characters, and it does the thing that makes narration feel written rather than read: brackets.
How it works
The node is generated from fal's elevenlabs/tts/eleven-v4 schema, so what you see is what the endpoint accepts, in the endpoint's own order. On Run it reads FAL_KEY from the install's .env, checks the text length, estimates the cost from your character count, submits one request, polls, and writes the audio into output/fal/elevenlabs_tts_eleven-v4/. The request id and full fal answer end up in the ledger and in the info output - which matters, because when a take is good you want to know exactly what you paid for.
The inputs that matter
text - up to 5,000 characters, and this is where the audio tags live. [whispering], [excited], [sighs] inline, the way you'd bracket a stage direction. It also accepts IPA pronunciation wrapped in forward slashes, which is the escape hatch for a name the model keeps mangling.
voice - a plain string, defaulting to Rachel. It's not a dropdown, so you type the voice name you want; leave it empty to fall back to the model's own choice.
stability (0–1, default 0.5) trades expressiveness for consistency - the tooltip's own framing is that lower is more expressive, higher is more consistent. Drop it for a character performance, raise it for a 40-line documentary read where you don't want a line to go rogue. similarity_boost (default 0.75) pulls the output closer to the reference voice at some cost to naturalness.
The rest: seed (best-effort, not a guarantee), language_code (ISO 639-1, empty lets it infer), output_format (mp3_44100_128 by default, with PCM and Opus options if you're feeding something fussy), apply_text_normalization (auto / on / off - decides whether "1987" gets read as a year or as digits), and timestamps, which returns character-level timing with the audio.
Outputs: audio, audio_path, timestamps, info. The timestamps string is the one to reach for if you're burning captions with real timing rather than estimating them from word length - that's the whole reason the pack has more than one way to get word timings.
Money
$0.08 per 1,000 characters, which is about 40 seconds of speech. A 1,500-character narration is twelve cents. The max_cost_usd cap defaults to $20, so you'd need a book before it intervened - the useful guardrail here is run_mode and the pack's branch-gating around it, not the cap.
Install
Manager → search comfyui-arkennemasis, or:
cd ComfyUI/custom_nodes
git clone https://github.com/Hishamahmer/comfyui-arkennemasis
Restart, then FAL_KEY=your-key in the .env beside run_nvidia_gpu.bat. Nothing to download model-wise. httpx in the pack's requirements is for the Codex nodes; the fal provider uses the standard library, and the FAL_KEY line is the only configuration this node has.
Common issues & troubleshooting
An audio tag came out as spoken words. Not every tag is supported, and unsupported brackets can be read literally. Test the delivery tags you actually plan to use before writing a script around them.
A name or acronym is mispronounced. Spell it phonetically in the text, or use the IPA-in-slashes syntax the tooltip advertises. Re-rolling the seed rarely fixes pronunciation.
"1987" read as digits when you wanted a year. apply_text_normalization - on forces normalization, off skips it, auto guesses. Force it when it matters.
An empty or refused character-list error. text is required and must be non-empty.
Text over 5,000 characters. The endpoint rejects it, and the node's own check catches it before submission - so split the script into chunks, and consider the multilingual v2 node instead, whose previous_text/next_text fields exist precisely to keep chunky narration continuous.
Inputs (13)
| Name | Type | Default | Description |
|---|---|---|---|
| text | STRING | The text to convert to speech. Supports audio tags such as [whispering] and IPA pronunciation enclosed in forward slashes. | |
| voice | COMBO | Rachel | The voice to use for speech generation (fal's default Rachel plus the 20 voices fal lists for Eleven v4). |
| stability | FLOAT | 0.500–1 | Voice stability. Lower values allow more expressive delivery; higher values make delivery more consistent. |
| similarity_boost | FLOAT | 0.750–1 | How closely the output follows the reference voice. Higher values increase similarity but may reduce naturalness. |
| seed | INT | -1-1–4294967295 | Seed for best-effort reproducibility. Identical output is not guaranteed. -1 leaves it to the model. |
| language_code | STRING | Language code (ISO 639-1) for speech generation and text normalization. Empty leaves it out. | |
| output_format | COMBO | mp3_44100_128 | Output format of the generated audio. Formatted as codec_sample_rate_bitrate. |
| apply_text_normalization | COMBO | auto | Whether to normalize text such as numbers and dates before generation. |
| timestamps | BOOLEAN | false | Whether to return character-level timing information with the generated audio. |
| max_cost_usdopt | FLOAT | 20.00–100000 | Safety cap. If the estimated cost of this run is above this many US dollars the node stops BEFORE sending anything to fal. 0 = no cap. |
| reuse_identical_runopt | BOOLEAN | true | If these exact inputs (the settings AND the same pictures/clips/audio) were already paid for and the files are still in output/fal, return them instead of paying again - also after a ComfyUI restart. Turn off for a fresh take with the same settings. |
| extra_jsonopt | STRING | Advanced: a JSON object merged into the request last, for any fal field this node has no box for. Example: {"seed": 7}. Leave empty normally. | |
| max_concurrentopt | INT | 11–32 | How many paid fal calls may run at the same time in one run, across every fal node. 1 (default) = one after another. This node starts its paid part only while fewer than this many fal calls are running. Once any fal node fails, the ones still waiting are not started, so nothing more is billed. |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| audio | AUDIO | — |
| audio_path | STRING | — |
| timestamps | STRING | — |
| info | STRING | JSON: request id, cost estimate, saved files and fal's full answer. |