Editing the ESP32-CAM Camera Web Server HTML

HEX and HTML diagonal

An easy way to edit or add HTML in the source of the ESP-WHO camera web server example

Using the CyberChef online tool makes it easy to convert from your own HTML to the Gzipped Hex format found in the the index_html_gz variable in the code for Arduino and IDF ESP-WHO libraries.

Where does the HTML come from in the CameraWebServer example?

The third tab from the Sketch  contains some strange looking code assigned to a variable called index_html_gz[]:

index_html_qz Variable

In the app_httpd.cpp tab this variable is used in this code:

index_hander Function

The index_handler function above serves HTML to the browser.

In the video below you can see this strange looking code in the index_html_gz variable magically turning into HTML:

Replacing the HTML

So now we have seen where the HTML comes from. How do we reverse the process so we can edit the HTML or replace it with our own?

Quick version –  Click here to open the CyberChef online tool, edit or paste your HTML in the Input field. The code you need to paste into the Arduino IDE will appear in the Output area. Copy all of it except the first comma.

If you want prefer to manually set it up, go to the https://gchq.github.io/CyberChef/ website on GitHub, drag the following actions from the left menu.

  • From Compression, drag ‘Gzip’
  • From Data Format, drag ‘To Hex’
  • From Utils, drag ‘Split’

Copy the settings as below:


Now you can make your own page by editing or pasting your own HTML code into the Input window and copying the result (minus the first comma) over the existing code in the Arduino IDE.

When the code has uploaded, refresh the browser and you will see the new page. Once set up, it’s very quick to make an edit to the HTML, copy and paste the new Hex into the IDE, upload and preview.

ESP32-CAM Video Playlist

IF you prefer your tutorials in video format you can visit the Robot Zero One YouTube channel and view the ESP32-CAM playlist here: https://www.youtube.com/channel/UCpqVEutU_Jcq34ws4tyUReQ/playlists


Another way of doing this – https://gist.github.com/me-no-dev/f137a950ce6dedb641d427d8db6355d2 if you want to automate it.

26 Replies to “Editing the ESP32-CAM Camera Web Server HTML”

  1. aelorenzo says:


    I am trying to start the streaming web server in the Camerawebserver example in a task for multitask purpose (just run the streaming process in one core and the other task in the second ESP32 core), but I am having issues…

    I think that it is related with the heap size for the task. If a put a low value, ESP32 is rebooting all the time, if a I put a high value, it doesn’t start.

    Do you know if it is possible to calcule the heap size for this tast? I am defining the task code just with the subroutine call startCameraServer().

    Maybe that’s the problem.

    Thank you!

    1. WordBot says:

      Hi, Which camera device are you using?

    2. Ugbana Awortu says:

      I’m working on a project and would also like to achieve this, streaming on only one core, did you find a solution and how did you come about it

  2. Cyril says:

    How to do the reverse?

    1. WordBot says:

      The top video shows the hex to html if that’s what you wanted.

  3. Aminu says:

    Hi WordBot thank you very much for all the guides they are very helpful sir, pls how can I change the webserver setting so that I can access the server from anywhere in the world, I want to change the port from 80 to WiFiSever server(8888).
    Thank you

    1. WordBot says:

      You need to do port forwarding. You can change the port numbers in the sketch: https://github.com/espressif/arduino-esp32/issues/2492

  4. GG says:

    Thank you for your tutorial, but I have a problem when I put the file “camera_index.h” in the IDE after modification. Everything is going well for decompression and recompression, but my program is not working as it should. Nothing happens when I want to start streaming video. I even tried to decompress the file and recompress it without changing anything, to find that it did not work after this manipulation.
    Do you have an idea of what is causing this problem, please?
    I search again and again, but I do not know what to do.
    I would like to translate the texts of a menu into French, and also to delete some of them.
    Mer ci tell me what you think please, I’m really lost …

    1. WordBot says:

      Hi, It should work the same. Does it work when you use the example in the IDE? Here’s a video in case you missed something in the tutorial – https://www.youtube.com/watch?v=bIJoVyjTf7g

  5. GG says:

    I really thank you very much, I did well to contact you !!!
    I had just forgotten to note the length of the data to enter them in the IDE, it’s really a stupidity on my part!
    So it works very, very well …
    Thank you, thank you, thank you very much, and congratulations for your work and for your quick response !!!
    I am happy

    1. Stephen Green says:

      Change app_httpd.cpp in index_handler from
      return httpd_resp_send(req, (const char *)index_ov2640_html_gz, index_ov2640_html_gz_len);

      return httpd_resp_send(req, (const char *)index_ov2640_html_gz, sizeof(index_ov2640_html_gz));

      Then you don’t need to know the size of the data, it’s automatic.

      1. Stephen Green says:

        Sorry a more accurate way is sizeof(index_ov2640_html_gz)/sizeof(index_ov2640_html_gz[0])

  6. Dani says:

    To obtain the original html code do the following:
    – copy the hex values of index_ov2640_html_gz[] from camera_index.h to input section of CyberChef
    – in Recipe section use only “From Charcode”, delimiter Comma, Base 16
    – save output to index_ov2640.html.gz

  7. ed says:

    Dani, thanks that helps a bit…but I am not there yet. Seems to be converted to a kind of zip format. In he video I see the last step being clicking unzip…….but I dont see that option anywhere.
    Any pointers?

    1. WordBot says:

      What are you trying to do? Convert your own code to the format needed, or read the code from the camera_index.h file?

  8. ed says:

    OK: this is how to get HTML.
    Use the decoded file as input.
    Clear your recipe by clicking the wastebin
    find and select “From Hex” delimiter auto
    let it convert
    then find and select Gunzip
    let it convert

  9. Robert says:

    how I get the length of the new website?
    The length of CybertChef doesn’t seems to match.

    1. WordBot says:

      I’m not sure the correct way but I just gave it a higher number if there was more HTML. You can tell when it’s too low because the HTML source gets truncated.

      1. Ugo says:

        Thank you so much for the great tutorial.
        I was lead to this tutorial from your “ESP32-CAM RC Car” tutorial. I wish to stream from the ESP32 cam, but I do not want the include the controller interface. I just want the only the steam to load on the browser. I have tried removing the part of the code that sends the index_html_gz to the browser, but the it did not work. I have also tried to edit the index_html_gz using this tutorial, by replacing the entire body of the HTML code with a word. But only the word showed on the browser while testing it. I know very little to nothing about HTML. I will be grateful if you could help me with a guide on how to go about it.
        Thank you in advance.

        1. WordBot says:

          Easiest way if you just want the video stream is to upload the CameraWebServer example (explained here: https://robotzero.one/esp32-cam-arduino-ide/) and then just go to http://your-ip-address:81/stream in the browser and you will see the stream.

  10. Neutral vibes says:

    Get the length by converting the output to a convention array.

    Browser console (F12)

    > arr = [ 0xf5, 0x41, 0x29, etc.. ] // Copy & paste adding square brackets>
    > arr.length // Will print the length

  11. Tom Chalabi says:

    I’m having trouble converting the ESP32-CAM webpage with the CyberChef.. The Start Stream button does not work.

    As a test, I took the original index_ov2640_html_gz[] values thru a decode/encode recipe which converts the values from Hex to HTML and back to Hex. The resulting hex values and length are different.

    Transformation Recipe: [Find Replace] –> [Remove Whitespace] –> [From Hex] –> [Gunzip] –> [GZip] –> [To Hex] –> [Split]. I used the exact parameters specified.

    The resulting transformation Hex code was different. The ESP32-CAM webpage rendered, but the Start Stream button would not work. Additionally, the original length was 26164. The resulting length became 26390.

    Any suggestions?



    1. WordBot says:

      Hi. Take a look at the HTML in the browser by viewing the source of the pages. I’m guessing the one that doesn’t work is missing a bit of the code at the bottom. I would just increase the length until it works.

  12. Tom Chalabi says:

    Thanks! Increasing the length worked.

  13. John Blacker says:

    Great job…I’ve been tearing what little hair I have left trying to figure out where that HTML was! Now for my new question: what takes the “compressed bytes” and turns them to pure html on the esp32? Is it the webserver? If not, what then?

    1. WordBot says:

      As I understand it the index_handler function sends the data as is to the browser with a header telling the browser that it’s GZIP encoded. You can send it as normal HTML but it’s a pain escaping all the ” symbols.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

scroll to top