In this guide, you’ll learn how to setup an ESP32 as a Wi-Fi scanner with ESP-IDF (Espressif IoT Development Framework). The Wi-Fi scanner code allows you to find nearby network access points that your ESP can establish a Wi-Fi connection.
It collects some information about each network, such as RSSI (Received Signal Strength Indicator) to indicate if the ESP32 can establish a connection with a good signal strength. It also returns the Wi-Fi channel, authentication mode (like WPA2/WPA3), and encryption cipher types.

Prerequisites
Before following this guide, you need to install the ESP-IDF extension on VS Code IDE (Microsoft Visual Studio Code). Follow the next guide to install it, if you haven’t already:
You will also need an ESP32 development board model of your choice.
Creating an ESP-IDF Template App Project for the ESP32
The ESP-IDF extension provides an easy way to create a project from scratch with all the required files and configurations generated automatically.
To create a new ESP-IDF project on VS Code, follow these steps:
- Open the ESP-IDF Espressif extension
- Expand the “Advanced” menu
- Click the “New Project Wizard” option
- Choose the “Use ESP-IDF v5.4.1” to select the framework version

A new window opens, you need to fill in these fields:
- Project Name: type the desired project name;
- Enter Project Directory: click the folder icon and select the target folder to save all your project files. You can use any directory. Note: do NOT use a Google Drive / One Drive / Dropbox folder, because it will write/create many files during the building process—if it’s on a cloud folder, this process might be extremely slow;
- ESP-IDF Target: select the target device chip, I’m using an ESP32 with the esp32s3 chip;
- ESP-IDF Board: for the esp32s3 chip, I also need to select the configuration: ESP32-S chip (via builtin USB-JTAG);
- Serial Port: while having your ESP32 board connected to your computer, select the correct COM port number that refers to your ESP32;
- Choose Template: click the blue button to create a new project using a template.

In the menu, select the “ESP-IDF“, scroll down to the “wifi” section and open the “scan” example. Finally, press the “Create project using template sample project” button.

Opening the ESP-IDF Project on VS Code
After a few seconds, a notification will appear on a new window on VS Code. You can click “Open Project” to open the newly created ESP-IDF sample project template.

IMPORTANT: if you didn’t see the notification that allows you to automatically open the ESP-IDF project on VS Code, you can easily do it by following these instructions:
Go to File > Open Folder…

Browse on your computer for the esp-idf-project folder (your project folder name that you’ve previously defined) and “Select Folder“.

That’s it! Your new ESP-IDF project example has been successfully created and opened.
The scanner code is in the scan.c file. To open it, follow these instructions:
- Open the project explorer by clicking the first icon on the left sidebar and select your project.
- Expand the “main” folder.
- Open the “scan.c” file.
- Your main.c file should load

Code: ESP32 Wi-Fi Scanner using ESP-IDF
The ESP32 can scan nearby Wi-Fi networks within its Wi-Fi range. This can be useful to check if the Wi-Fi network you’re trying to connect is within the range of your board or other applications. Your Wi-Fi project may not often work because it may not be able to connect to your router due to insufficient Wi-Fi strength.

Copy the following code to the main.c file. This code scans for all nearby Wi-Fi networks and indicates their corresponding RSSI.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
https://RandomNerdTutorials.com/esp-idf-esp32-wi-fi-scanner/
This example code is in the Public Domain (or CC0 licensed, at your option.) Unless required by applicable law or agreed to in writing, this software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "regex.h"
#define DEFAULT_SCAN_LIST_SIZE CONFIG_EXAMPLE_SCAN_LIST_SIZE
#ifdef CONFIG_EXAMPLE_USE_SCAN_CHANNEL_BITMAP
#define USE_CHANNEL_BITMAP 1
#define CHANNEL_LIST_SIZE 3
static uint8_t channel_list[CHANNEL_LIST_SIZE] = {1, 6, 11};
#endif /*CONFIG_EXAMPLE_USE_SCAN_CHANNEL_BITMAP*/
static const char *TAG = "scan";
static void print_auth_mode(int authmode)
{
switch (authmode) {
case WIFI_AUTH_OPEN:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_OPEN");
break;
case WIFI_AUTH_OWE:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_OWE");
break;
case WIFI_AUTH_WEP:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WEP");
break;
case WIFI_AUTH_WPA_PSK:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA_PSK");
break;
case WIFI_AUTH_WPA2_PSK:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_PSK");
break;
case WIFI_AUTH_WPA_WPA2_PSK:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA_WPA2_PSK");
break;
case WIFI_AUTH_ENTERPRISE:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_ENTERPRISE");
break;
case WIFI_AUTH_WPA3_PSK:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA3_PSK");
break;
case WIFI_AUTH_WPA2_WPA3_PSK:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_WPA3_PSK");
break;
case WIFI_AUTH_WPA3_ENTERPRISE:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA3_ENTERPRISE");
break;
case WIFI_AUTH_WPA2_WPA3_ENTERPRISE:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_WPA3_ENTERPRISE");
break;
case WIFI_AUTH_WPA3_ENT_192:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA3_ENT_192");
break;
default:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_UNKNOWN");
break;
}
}
static void print_cipher_type(int pairwise_cipher, int group_cipher)
{
switch (pairwise_cipher) {
case WIFI_CIPHER_TYPE_NONE:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_NONE");
break;
case WIFI_CIPHER_TYPE_WEP40:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_WEP40");
break;
case WIFI_CIPHER_TYPE_WEP104:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_WEP104");
break;
case WIFI_CIPHER_TYPE_TKIP:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_TKIP");
break;
case WIFI_CIPHER_TYPE_CCMP:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_CCMP");
break;
case WIFI_CIPHER_TYPE_TKIP_CCMP:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_TKIP_CCMP");
break;
case WIFI_CIPHER_TYPE_AES_CMAC128:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_AES_CMAC128");
break;
case WIFI_CIPHER_TYPE_SMS4:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_SMS4");
break;
case WIFI_CIPHER_TYPE_GCMP:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_GCMP");
break;
case WIFI_CIPHER_TYPE_GCMP256:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_GCMP256");
break;
default:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_UNKNOWN");
break;
}
switch (group_cipher) {
case WIFI_CIPHER_TYPE_NONE:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_NONE");
break;
case WIFI_CIPHER_TYPE_WEP40:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_WEP40");
break;
case WIFI_CIPHER_TYPE_WEP104:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_WEP104");
break;
case WIFI_CIPHER_TYPE_TKIP:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_TKIP");
break;
case WIFI_CIPHER_TYPE_CCMP:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_CCMP");
break;
case WIFI_CIPHER_TYPE_TKIP_CCMP:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_TKIP_CCMP");
break;
case WIFI_CIPHER_TYPE_SMS4:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_SMS4");
break;
case WIFI_CIPHER_TYPE_GCMP:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_GCMP");
break;
case WIFI_CIPHER_TYPE_GCMP256:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_GCMP256");
break;
default:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_UNKNOWN");
break;
}
}
#ifdef USE_CHANNEL_BITMAP
static void array_2_channel_bitmap(const uint8_t channel_list[], const uint8_t channel_list_size, wifi_scan_config_t *scan_config) {
for(uint8_t i = 0; i < channel_list_size; i++) {
uint8_t channel = channel_list[i];
scan_config->channel_bitmap.ghz_2_channels |= (1 << channel);
}
}
#endif /*USE_CHANNEL_BITMAP*/
/* Initialize Wi-Fi as sta and set scan method */
static void wifi_scan(void)
{
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
assert(sta_netif);
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
uint16_t number = DEFAULT_SCAN_LIST_SIZE;
wifi_ap_record_t ap_info[DEFAULT_SCAN_LIST_SIZE];
uint16_t ap_count = 0;
memset(ap_info, 0, sizeof(ap_info));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start());
#ifdef USE_CHANNEL_BITMAP
wifi_scan_config_t *scan_config = (wifi_scan_config_t *)calloc(1,sizeof(wifi_scan_config_t));
if (!scan_config) {
ESP_LOGE(TAG, "Memory Allocation for scan config failed!");
return;
}
array_2_channel_bitmap(channel_list, CHANNEL_LIST_SIZE, scan_config);
esp_wifi_scan_start(scan_config, true);
free(scan_config);
#else
esp_wifi_scan_start(NULL, true);
#endif /*USE_CHANNEL_BITMAP*/
ESP_LOGI(TAG, "Max AP number ap_info can hold = %u", number);
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count));
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info));
ESP_LOGI(TAG, "Total APs scanned = %u, actual AP number ap_info holds = %u", ap_count, number);
for (int i = 0; i < number; i++) {
ESP_LOGI(TAG, "SSID \t\t%s", ap_info[i].ssid);
ESP_LOGI(TAG, "RSSI \t\t%d", ap_info[i].rssi);
print_auth_mode(ap_info[i].authmode);
if (ap_info[i].authmode != WIFI_AUTH_WEP) {
print_cipher_type(ap_info[i].pairwise_cipher, ap_info[i].group_cipher);
}
ESP_LOGI(TAG, "Channel \t\t%d", ap_info[i].primary);
}
}
void app_main(void)
{
// Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK( ret );
wifi_scan();
}
Change the Scan List Size
By default, the scan example tries to find a maximum of 10 networks. Follow these steps to change it:
- Click the gear icon to open the SDK Configuration Editor (menu config)
- Search for “Max size of scan list“
- You can edit max size of scan list with another number to show more/less results
- Press the “Save” button to apply the changes

How the Code Works
In this section, we’ll do a quick breakdown of the ESP-IDF Wi-Fi scanner code.
Header Includes and Global Configuration Variables
Starting by including the necessary libraries and global configuration variables. As described in the previous section, you can change the DEFAULT_SCAN_LIST_SIZE in the SDK Configuration Editor.
print_auth_mode() and print_cipher_type
There are two helper functions that print info in a readable format:
- print_auth_mode(int authmode): uses a switch statement to map to values to the authentication mode used by the access point (example: WIFI_AUTH_OPEN, WIFI_AUTH_WPA3_PSK, etc…);
- print_cipher_type(int pairwise_cipher, int group_cipher): displays both pairwise and group cipher suites used by the access point (example: WIFI_CIPHER_TYPE_CCMP for TKIP).
wifi_scan()
The wifi_scan() function runs once and it’s called in the app_main. It initializes the network interface, default event loop, creates a station interface, and starts the Wi-Fi driver with default configuration.
It uses the ESP_ERROR_CHECK() when executing each function to check for potential errors during the Wi-Fi interface initialization and scan process:
ESP_ERROR_CHECK(esp_wifi_start());
Finally, it loops and logs all the key information in the Terminal window: how many Access Points (APs) were scanned, their SSID, RRSI, authentication mode, encryption cipher types, and Wi-Fi channel.
ESP_LOGI(TAG, "Max AP number ap_info can hold = %u", number);
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count));
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info));
ESP_LOGI(TAG, "Total APs scanned = %u, actual AP number ap_info holds = %u", ap_count, number);
for (int i = 0; i < number; i++) {
ESP_LOGI(TAG, "SSID \t\t%s", ap_info[i].ssid);
ESP_LOGI(TAG, "RSSI \t\t%d", ap_info[i].rssi);
print_auth_mode(ap_info[i].authmode);
if (ap_info[i].authmode != WIFI_AUTH_WEP) {
print_cipher_type(ap_info[i].pairwise_cipher, ap_info[i].group_cipher);
}
ESP_LOGI(TAG, "Channel \t\t%d", ap_info[i].primary);
}
Build and Flash Code to the ESP32 Board
To build and flash ESP-IDF code to the ESP32, you always need to follow this procedure. You need to select the flash method (UART), the COM port number, the target device (ESP32), build the code, and finally, flash it to the board. All these commands are available in the bottom menu bar of VS Code.
Make sure all your options are correct (they may already be properly configured if you used the project wizard).

However, if your setup is not correct, follow the next instructions to ensure everything is set up correctly. First, click the “Star” icon and select the flash method as UART.

While the ESP32 board is connected to your computer, click the COM Port (plug icon) and select the correct port number that refers to your ESP32.

You also need to select the target device. Click on the chip icon at the bottom bar. In my case, I have an ESP32 with the esp32s3 chip.

For this board, I also need to select the configuration: ESP32-S chip (via builtin USB-JTAG).

Finally, your command bar on the bottom of VS Code should have similar options selected.

Now, you can build the project by clicking the wrench icon (Build Project) as shown in the image below.

The first time you build a project, it usually takes a bit more time. Once completed, it should print a similar message in the Terminal menu and show a “Build Successfully” message.

This is the final step. You can now flash the ESP-IDF project to the ESP32 by clicking the “Flash Device” button (thunder icon).

Depending on your board, you might need to hold down the on-board BOOT button on your ESP32 to put into flashing mode. Once the process is completed, it will pop-up a info message saying “Flash Done“.

Demonstration
If you followed all the steps, the Wi-Fi scanner example should be running successfully on your board. Open your Terminal window — click the “Monitor Device” tool that is illustrated with a screen icon.

The terminal should be printing some information regarding each network nearby:
I (3033) scan: SSID MEO-20------
I (3033) scan: RSSI -52
I (3033) scan: Authmode WIFI_AUTH_WPA2_PSK
I (3033) scan: Pairwise Cipher WIFI_CIPHER_TYPE_CCMP
I (3043) scan: Group Cipher WIFI_CIPHER_TYPE_CCMP
I (3043) scan: Channel 11

You can press the ESP32 on-board RESET button to restart and see new scan results.
Wrapping Up
In this tutorial, you learned how to setup the ESP32 as a Wi-Fi scanner with the ESP-IDF framework using VS Code to find nearby networks and their corresponding signal strenght.
You might find helpful reading other ESP-IDF guides:
- Programming ESP32 with ESP-IDF using VS Code – Getting Started Guide
- ESP-IDF: ESP32 Blink LED Example (VS Code)
- ESP-IDF: ESP32 GPIO PWM with LEDC (Control LED Brightness)
- ESP-IDF: ESP32 GPIO – Read Analog Input (ADC – Analog to Digital Converter)
Meanwhile, you can check our ESP32 resources (with Arduino IDE) to learn more about the ESP32 board:
Thanks for reading.




I’ve compiled and ran this on an ESP32C5. Can’t figure out how or where the output is or goes. I added void setup(){} and loop(){{} which keeps the compiler happy.
So, is this incomplete, or am I missing someting – most likely I have.