Transloadit's Assembly system is genuinely useful for complex file processing pipelines: encode a video, generate a thumbnail, apply a watermark, store to S3, fire a webhook — all defined in one JSON object. If your application does any combination of those things, Transloadit is well-suited.

But many teams have Assemblies that do exactly one thing: convert a file from format A to format B. They're using the Assembly model for simplicity — to avoid running FFmpeg or LibreOffice themselves — not because they need multi-step chaining. For those teams, Transloadit's pricing and Assembly overhead can be replaced by a simpler, cheaper API call.

When migrating from Transloadit makes sense

Your Assemblies do only one conversion step. If you have an Assembly that converts mp4 to webm, or docx to pdf, using Transloadit just to avoid running FFmpeg yourself — ChangeThisFile does the same thing with no Assembly setup and lower cost.

You don't use Uppy. Transloadit's main frontend differentiator is Uppy, an open-source upload widget with Transloadit integration. If you handle file uploads yourself (drag-and-drop, file picker, or backend-to-backend), you're not using Transloadit's signature frontend feature.

You don't need S3/cloud storage output. Transloadit can write processed files directly to S3, GCS, or FTP. If you download the result and store it yourself, you're not using that feature either.

Credit system limits are hitting you. Transloadit's credit system assigns different credit costs to different robots. Complex encoding robots cost more credits than simple conversions. ChangeThisFile charges one unit per conversion regardless of format type.

Who should stay on Transloadit:

  • Multi-step Assemblies (encode + thumbnail + watermark in one job)
  • Uppy upload widget in your frontend
  • Direct S3/GCS output from processing
  • Webhook on Assembly completion
  • Video thumbnail extraction with frame selection
  • Watermarking images or video

Cost comparison

Volume/monthTransloadit (est.)ChangeThisFileMonthly savings
500 conversions~$39/mo (entry plan)$0 (free tier)$39
2,000 conversions~$39–79/mo$29 (Hobby)$10–50
10,000 conversions~$99–199/mo$29–99 (Hobby/Startup)$0–170
50,000 conversions~$299–499/mo$99–499 (Startup/Scale)$0–400

Transloadit's credit system means actual cost depends on your mix of robots. Video encoding costs more credits than document conversion. Estimates above assume a mixed workload. Video-heavy pipelines are at the higher end.

API approach comparison

Transloadit conceptChangeThisFile equivalent
Assembly definition (JSON)Single POST /v1/convert
Robot (e.g., /video/encode, /document/convert)target field ("mp4", "pdf", etc.)
Assembly Steps[] arrayNot needed — one call, one output
Auth header + signature (HMAC)Authorization: Bearer ctf_sk_{key}
Async Assembly + notification_url webhookSynchronous — file in response
GET Assembly result URL (download)Not needed — file in response body
Uppy upload widgetNot included — handle uploads yourself
S3/GCS output robotNot supported — download and store yourself

Code migration: BEFORE and AFTER

# BEFORE: Transloadit (Assembly, HMAC auth, async + polling)
import requests
import hmac
import hashlib
import json
import time

TL_AUTH_KEY = 'your_transloadit_auth_key'
TL_SECRET = 'your_transloadit_secret'

# Build Assembly params
params = json.dumps({
    'auth': {
        'key': TL_AUTH_KEY,
        'expires': '2026-12-31T23:59:59.000Z'
    },
    'steps': {
        'convert': {
            ':use': ':original',
            'robot': '/document/convert',
            'format': 'pdf',
            'result': True
        }
    }
})

# HMAC signature
signature = hmac.new(
    TL_SECRET.encode('utf-8'),
    params.encode('utf-8'),
    hashlib.sha384
).hexdigest()

# Submit Assembly with file
with open('report.docx', 'rb') as f:
    resp = requests.post(
        'https://api2.transloadit.com/assemblies',
        data={'params': params, 'signature': f'sha384:{signature}'},
        files={'file_input': f}
    )
assembly_id = resp.json()['assembly_id']

# Poll for completion
while True:
    status = requests.get(
        f'https://api2.transloadit.com/assemblies/{assembly_id}',
        params={'auth_key': TL_AUTH_KEY}
    ).json()
    if status['ok'] == 'ASSEMBLY_COMPLETED':
        download_url = status['results']['convert'][0]['url']
        break
    if status['ok'] == 'ASSEMBLY_UPLOADING_ERRORED':
        raise Exception('Assembly failed')
    time.sleep(2)

# Download result
result = requests.get(download_url)
with open('report.pdf', 'wb') as f:
    f.write(result.content)

# AFTER: ChangeThisFile (static Bearer token, synchronous)
import requests

response = requests.post(
    'https://changethisfile.com/v1/convert',
    headers={'Authorization': 'Bearer ctf_sk_your_key'},
    files={'file': open('report.docx', 'rb')},
    data={'target': 'pdf'}
)
with open('report.pdf', 'wb') as f:
    f.write(response.content)

Key differences: HMAC signature generation is replaced by a static Bearer token; the Assembly JSON definition is replaced by a single target field; the polling loop and download URL step are eliminated.

Auth migration: HMAC to Bearer token

Transloadit uses HMAC-SHA384 request signing — your auth key + secret are used to sign each request's params JSON. This is secure but requires signing logic in every language you use. ChangeThisFile uses a static Bearer token in the Authorization header.

  1. Get your CTF key: changethisfile.com/v1/keys/free. Free, no card. Format: ctf_sk_....
  2. Remove HMAC signing logic: Delete the hmac.new() / hashlib.sha384 code and the expiry timestamp generation. Replace the entire auth block with headers={'Authorization': f'Bearer {CTF_KEY}'}.
  3. Remove Assembly definition code: Delete the steps JSON, robot configuration, and params object. The target format is now a simple multipart field: data={'target': 'pdf'}.
  4. Update environment variables: Replace TRANSLOADIT_AUTH_KEY and TRANSLOADIT_SECRET with a single CTF_API_KEY.

Webhook migration

Transloadit fires a notification_url webhook when an Assembly completes. ChangeThisFile is synchronous — the converted file is in the HTTP response, so there's no need for a webhook.

If you used Transloadit webhooks for completion notification: Remove the webhook handler. The code that ran inside it should run after the response = requests.post(...) call returns.

If you used Transloadit webhooks for error handling: Use a try/except block around the ChangeThisFile call. response.raise_for_status() throws on 4xx/5xx. Add retry logic if needed:

try:
    response = requests.post(
        'https://changethisfile.com/v1/convert',
        headers={'Authorization': f'Bearer {CTF_KEY}'},
        files={'file': open('doc.docx', 'rb')},
        data={'target': 'pdf'},
        timeout=120
    )
    response.raise_for_status()
except requests.HTTPError as e:
    # Handle error — no webhook needed
    print(f'Conversion failed: {e.response.status_code}')

Rollback plan

Keep your Transloadit account active during the migration period:

  1. Abstract conversion calls behind a function with a backend parameter. Toggle CONVERTER_BACKEND=transloadit or CONVERTER_BACKEND=ctf to switch instantly.
  2. If your Assembly uses multiple steps (e.g., convert + thumbnail), identify which steps can move to ChangeThisFile individually and which must stay as a pipeline.
  3. Run parallel for 48–72 hours comparing outputs before switching all traffic.
  4. Cancel your Transloadit plan after 30 days of clean operation.

Common migration questions

My Assembly uses multiple steps — can I migrate partially?
Yes. Migrate the simple single-step Assemblies to ChangeThisFile and keep complex multi-step ones on Transloadit. You'll reduce your Transloadit credit usage (and cost) while keeping the features that need the pipeline model.

I use Uppy for file uploads. Does ChangeThisFile integrate with it?
ChangeThisFile doesn't have an Uppy plugin. If Uppy sends files to Transloadit, that integration stays on Transloadit. If you can decouple the upload from the conversion, handle uploads with a standard file picker and send completed uploads to ChangeThisFile's API.

Transloadit supports 100+ robots. Does ChangeThisFile cover all of them?
No. Transloadit has robots for watermarking, thumbnail generation, audio normalization, video clip extraction, CDN store, and more. ChangeThisFile covers format conversion only. Audit which robots you actually use — many teams use 1–2 robots despite having access to 100+.

What's the file size limit for ChangeThisFile?
Free tier: 25MB. Paid plans support larger files. Transloadit handles larger files and long-running encoding jobs better than ChangeThisFile's synchronous model for large video files.

Transloadit is the right tool for multi-step processing pipelines. ChangeThisFile is the right tool when your Assembly does exactly one thing — convert a file's format. Identify your single-step Assemblies, get a free API key, and migrate those first. Keep the rest on Transloadit.