How to Integrate Tinymce 5 with Flask (with csrf)

This article shows how to integrate Tinymce 5 with Flask even including csrf protection!

Text area

<textarea id="content"></textarea>


<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/tinymce/5.10.2/tinymce.min.js"></script>
<script type="text/javascript">
    selector: '#content',
    plugins: [
        'advlist autolink link image imagetools lists charmap print preview hr anchor pagebreak spellchecker',
        'searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking',
        'save table contextmenu directionality template paste textcolor codesample'
    imagetools_toolbar: "rotateleft rotateright | flipv fliph | editimage imageoptions",
    toolbar: 'insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | print preview media fullpage | forecolor backcolor emoticons | codesample',
    relative_urls: false,
    images_upload_handler : function(blobInfo, success, failure) {
            var xhr, formData;

            xhr = new XMLHttpRequest();
            xhr.withCredentials = false;
            xhr.open('POST', '{{ url_for('upload_function_name_here') }}'); // change this

            xhr.onload = function() {
                var json;

                if (xhr.status != 200) {
                    failure('HTTP Error: ' + xhr.status);

                json = JSON.parse(xhr.responseText);

                // if (!json || typeof json.file_path != 'string') {
                //     failure('Invalid JSON: ' + xhr.responseText);
                //     return;
                // }


            formData = new FormData();
            formData.append('file', blobInfo.blob(), blobInfo.filename());
            formData.append('csrf_token', '{{csrf_token()}}'); // i add csrf_token

    image_title: true,
    automatic_uploads: true,
    images_reuse_filename: false,
    images_upload_base_path: '/static/gallery/', // i serve from /static/gallery and save to /static/gallery
    codesample_languages: [
        { text: 'HTML/XML', value: 'markup' },
        { text: 'JavaScript', value: 'javascript' },
        { text: 'CSS', value: 'css' },
        { text: 'Processing', value: 'processing' },
        { text: 'Python', value: 'python' }
    width: "100%",

First add to config GALLERY_UPLOAD_PATH with value the absolute path of your static folder


from flask import abort
from flask import current_app
from flask import Response
from flask import request
from flask import url_for
from flask import jsonify

from werkzeug.utils import secure_filename

@module_blueprint.route('/file-upload', methods=['GET', 'POST'])
def file_upload():
    Upload post images from tinyMce editor.
    Save image to path.
    returns: json { location: path }

    # Get the file user has uploaded inside the tinymce editor.
    uploaded_file = request.files.get('file')

    if uploaded_file:
        filename = secure_filename(uploaded_file.filename).lower()

        # Validate the contents of the file.  Check the header of the file is infact an image.
        # valid_img_ext = validate_img(uploaded_file.stream)

        # Split filename and extension, rename & add correct extension.
        # filename = secure_filename(os.path.splitext(filename)[0] + valid_img_ext)

        img_path = os.path.join(current_app.config['GALLERY_UPLOAD_PATH'], filename)

        # Check if user directory exists, create if nessecary.
        if not os.path.exists(current_app.config['GALLERY_UPLOAD_PATH']):
            except OSError as e:
                if e.errno != errno.EEXIST:

        # Save the image.
        location = url_for('static', filename='gallery/' + filename)

        # Return image path back to editor
        return jsonify({'location': location})

    abort(Response('404 - Image failed to upload'))

Flask 2.x

Kevin7’s article was not working, adapted it