Debugging & Troubleshooting

django-tinymce: Stop URL Rewriting and Base64 Image Bloat in HTMLField

django-tinymce rewrites your URLs to relative paths and stores pasted images as base64 by default. Here's the config that stops both when saving HTML descriptions.

Long Nguyen Avatar

Long Nguyen

Fullstack Developer · AI Engineer · Researcher

3 min read

When you store rich HTML — like a product description — in a django-tinymce HTMLField, two default TinyMCE behaviors will quietly change your content: it rewrites URLs to relative paths, and it embeds pasted images as base64 data URIs. Both are fixable in TINYMCE_DEFAULT_CONFIG, but only if you understand which setting actually does the work.

Problem 1: TinyMCE rewrites your URLs

By default TinyMCE converts URLs in your content. An absolute link you entered as https://example.com/page can come back as a relative path like ../../page. That breaks links the moment the stored HTML is rendered somewhere other than the page it was authored on — a different route, an email, an API response, a feed.

The URL settings, and which one matters

Three settings govern this, and they're layered — the order matters:

  • convert_urls (default true) is the master switch. When true, TinyMCE converts URLs at all. When false, it leaves every URL exactly as entered — no conversion, relative or absolute.
  • relative_urls (default true) only takes effect when convert_urls is true. True makes URLs relative; false forces them absolute.
  • remove_script_host (default true) also only applies when converting to absolute — it controls whether the protocol and host are stripped.

So the decisive setting is convert_urls: False. Set that, and URLs are preserved as-is; relative_urls and remove_script_host become moot. If instead you want conversion left on but always absolute URLs with full host, you'd keep convert_urls: True and set relative_urls: False, remove_script_host: False. Don't expect relative_urls: False alone to help while convert_urls is still true and you want no rewriting at all — the clean "leave my URLs alone" answer is convert_urls: False.

TINYMCE_DEFAULT_CONFIG = {
    # ... your other options ...
    "convert_urls": False,        # decisive: no URL rewriting at all
    "relative_urls": False,       # only relevant if convert_urls is True
    "remove_script_host": False,  # only relevant when producing absolute URLs
}

Problem 2: pasted images become base64

By default, when you paste or drag an image directly into the TinyMCE editor and no upload handler is configured, TinyMCE embeds the image inline as a base64 data URI right in the HTML. The description still looks fine in the editor, but the stored markup now carries the entire image encoded as text.

That's a real problem for a stored description: the HTML field balloons in size (a single image can be hundreds of KB of base64), it can hit database column limits, it slows queries and page loads, the image can't be served from a CDN or cached separately, and it's duplicated everywhere the description is reused.

How to stop base64 embedding

The fix is to give TinyMCE somewhere to upload images to, so it replaces the base64 blob with a real URL:

  1. Configure an upload endpoint via images_upload_url (or a custom images_upload_handler). With automatic_uploads on (the default), TinyMCE POSTs the image blob to your endpoint and swaps in the returned URL instead of base64.
  2. Have that endpoint save the file (to your media storage or object storage) and return the public URL in the JSON shape TinyMCE expects ({ "location": "https://..." }).
  3. If you'd rather reject inline images entirely, set paste_data_images: False so data-URI pastes are dropped instead of embedded.

Rule of thumb: if a description will be stored and reused, never let images live as base64 — route them through an upload handler so the field holds a URL, not a payload.

These are the kinds of quiet defaults that don't error out — they just corrupt your stored data until something downstream breaks. I build and debug Django backends and content pipelines as part of my work. If you need a hand with backend or custom software, check out Netalith's services or reach out to me directly on LinkedIn.

FAQ

Frequently asked questions

Which setting stops TinyMCE from making URLs relative?

convert_urls: False is the decisive one — it disables all URL conversion, so URLs stay exactly as entered. relative_urls and remove_script_host only take effect when convert_urls is True.

Does relative_urls: False on its own prevent URL rewriting?

Not fully. relative_urls only applies when convert_urls is True, where False forces absolute URLs. To leave URLs untouched entirely, set convert_urls: False.

Why does TinyMCE store pasted images as base64?

By default, with no upload handler configured, TinyMCE embeds pasted or dragged images inline as base64 data URIs. The editor looks fine, but the stored HTML now carries the whole image encoded as text.

How do I stop base64 image embedding in django-tinymce?

Configure images_upload_url (or images_upload_handler) so TinyMCE uploads the image and replaces the base64 with the returned URL. To reject inline images outright, set paste_data_images: False.

Stay updated with Netalith

Get coding resources, product updates, and special offers directly in your inbox.