esp32.diy

ESP32 Camera Example: Step-by-Step Setup Guide

Oct 13, 2026 · 6 min read · Beginner

ESP32 Camera Example: Step-by-Step Setup Guide
TL;DR The espressif/esp32-camera library supports ESP32, ESP32-S2, and ESP32-S3 with sensors like the OV2640. Fill a camera_config_t struct with your board's pin map, call esp_camera_init(), then grab frames with esp_camera_fb_get().
Supported SoCsESP32, ESP32-S2, ESP32-S3
Popular sensorOV2640 — max 1600 × 1200
PSRAM required?Yes, except CIF or lower resolution with JPEG
Arduino installNone — bundled with the arduino-esp32 core
ESP-IDF installidf.py add-dependency "espressif/esp32-camera"
Frame-rate tipUse fb_count ≥ 2 with JPEG only for continuous DMA

What do you need before you start?

Before writing a single line of code, confirm you have all of the following.

Hardware

Software

Knowledge

ESP32-CAM module with integrated camera connector\2

ESP32-CAM module with integrated camera connector Image: Nowforever, CC BY-SA 4.0, via Wikimedia Commons

How do I install the ESP32 camera library?

The approach depends on which build system you are using.

Environment What to do
Arduino IDE (arduino-esp32 core) Nothing — just #include "esp_camera.h"
PlatformIO (ESP-IDF framework) Add esp32-camera to lib_deps in platformio.ini
ESP-IDF CLI Run idf.py add-dependency "espressif/esp32-camera"

For ESP-IDF you can also pull a ready-configured example in one command:

idf.py create-project-from-example "espressif/esp32-camera:camera_example"

This drops the example into a camera_example directory that already has the correct menuconfig settings, making it the fastest route to a first working build.

For PlatformIO, add the following to the env section of platformio.ini:

[env]
lib_deps =
  esp32-camera

Regardless of environment, enable PSRAM in menuconfig and set both Flash and PSRAM frequencies to 80 MHz. With PlatformIO you can add this line directly to sdkconfig instead:

CONFIG_ESP32_SPIRAM_SUPPORT=y
ESP32 development board with camera module attached on breadboard\2

ESP32 development board with camera module attached on breadboard Image: Kansattica, CC BY 4.0, via Wikimedia Commons

How do I configure and initialize the camera?

Initialization comes down to filling a camera_config_t struct and calling esp_camera_init(). Pin numbers differ by board. The table below shows the values for the AI Thinker ESP32-CAM:

Signal GPIO
PWDN 32
RESET -1 (software reset)
XCLK 0
SIOD (SDA) 26
SIOC (SCL) 27
D7 / Y9 35
D6 / Y8 34
D5 / Y7 39
D4 / Y6 36
D3 / Y5 21
D2 / Y4 19
D1 / Y3 18
D0 / Y2 5
VSYNC 25
HREF 23
PCLK 22

Define the pins at the top of your sketch, then fill the config struct using those constants:

#include "esp_camera.h"

// Pin definition for CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27

#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22

Then configure and initialise:

camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
config.frame_size = FRAMESIZE_CIF; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
config.jpeg_quality = 10;
config.fb_count = 2;

esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
  Serial.printf("Camera init failed with error 0x%x", err);
  return;
}

ledc_channel and ledc_timer tell the driver to generate the XCLK signal internally using the LED PWM peripheral — leave them as shown unless you have a conflict with other LEDC users in your project.

How do I capture frames and use the image data?

After esp_camera_init() returns ESP_OK, capturing a frame uses esp_camera_fb_get():

camera_fb_t * fb = NULL;

// Take Picture with Camera
fb = esp_camera_fb_get();
if(!fb) {
  Serial.println("Camera capture failed");
  return;
}

The fb pointer gives you access to the raw byte buffer, its length, and the frame dimensions. Always return the buffer to the driver after you are done with it, or the pool will be exhausted and subsequent captures will fail.

One frame buffer vs. two or more

Pixel format advice

Capturing directly in YUV or RGB puts heavy strain on the chip because writes to PSRAM are slow, and frame data is often incomplete when Wi-Fi is active at the same time. The recommended pattern is to capture in JPEG and then convert using fmt2rgb888() or fmt2bmp() / frame2bmp() from the driver's utility functions.

How do I verify the camera is working?

Run these checks in order before building anything more complex.

  1. Open Serial Monitor at 115200 baud right after flashing. Confirm there is no Camera init failed line — a clean start means the sensor is responding over I2C.
  2. Add a one-shot capture call immediately after init and confirm fb is not null before accessing the buffer. A null pointer means the sensor is not producing image data.
  3. Return the buffer after inspection and capture a second frame to confirm the buffer pool recycles correctly.
  4. If you used idf.py create-project-from-example, the bundled example already prints basic frame statistics to the console — no extra code needed to confirm capture is healthy.
  5. For streaming projects, print WiFi.localIP() to Serial after connecting, then open that address in a browser to confirm your MJPEG or snapshot endpoint responds.

What are the most common mistakes?

Wrong pin numbers for your board Pin assignments differ between the AI Thinker ESP32-CAM, WROVER-KIT, and other camera boards. Always verify your board's schematic before filling camera_config_t. Pasting pins from the wrong board is the leading cause of init failed errors.

PSRAM not enabled in menuconfig Forgetting this step causes a crash immediately after esp_camera_init(). Enable PSRAM and set Flash and PSRAM frequencies to 80 MHz. Without PSRAM, only CIF or lower with JPEG is possible.

Capturing YUV or RGB with Wi-Fi active PSRAM write bandwidth cannot keep up with raw pixel data while the Wi-Fi radio is running. Frames will be incomplete or corrupt. Capture JPEG and convert to the color format you need afterward.

python: executable file not found in $PATH on Linux The ESP32 build toolchain calls python, not python3. On Ubuntu 20.04 and later, python is not symlinked by default even though python3 is installed. The fix is to install a package that creates the python → python3 link:

sudo dpkg -i python-is-python3_3.8.2-4_all.deb

You can confirm Python is found by typing python in a terminal and seeing a version prompt.

Not returning the frame buffer Every esp_camera_fb_get() call must be paired with a corresponding return call. Skipping the return exhausts the pool and causes the next capture attempt to block or return null.

Resolution above CIF with PSRAM disabled This combination will fail at init or produce garbage. Either enable PSRAM or drop resolution to CIF or lower when working with JPEG on a board that truly has no PSRAM.

Frequently asked questions

Which ESP32 chips work with the esp32-camera library?

The library officially supports ESP32, ESP32-S2, and ESP32-S3.

Is PSRAM required for the ESP32-CAM?

Yes in most cases. It is required for resolutions above CIF when not using JPEG, and strongly recommended for all JPEG streaming use cases.

What image sensors are compatible with esp32-camera?

Supported sensors include OV2640 (1600×1200), OV5640 (2592×1944), OV3660 (2048×1536), OV7670 (640×480), OV7725, GC2145, GC032A, NT99141, SC101IOT, HM1055, and several others listed in the repository.

Can I stream video from the ESP32-CAM to a browser or server?

Yes. One approach is to capture JPEG frames in a loop and send them as base64-encoded data over a WebSocket or Socket.IO connection to a Node.js relay, which then forwards them to browser clients. The ESP32 connects to Wi-Fi, acquires frames with esp_camera_fb_get(), encodes them, and emits them as Socket.IO events.

Why does my build fail with 'python: executable file not found in $PATH'?

The ESP32 toolchain looks for 'python', but Ubuntu 20.04 and later only install 'python3'. Install a package that creates the python→python3 symlink, such as python-is-python3, to fix it.

Bottom line

Getting an ESP32 camera example running reliably comes down to three things: matching your pin map exactly to your physical board, enabling PSRAM in menuconfig, and sticking to JPEG capture whenever Wi-Fi is active. Start with the bundled example from the component registry to rule out wiring issues, then build streaming or image-processing features on top of that confirmed baseline.

Sources

stackoverflow.com"exec: "python": executable file not found in $PATHstackoverflow.comESP32-CAM fastest way to stream video output to nodejs server with socketIOgithub.comespressif/esp32-camera (GitHub README)

This guide summarises the public sources listed above in our own words. Check the original documentation before relying on exact figures.