Learn how to use the APDS9960 sensor with the ESP8266 board using Arduino IDE. This sensor combines gesture detection, proximity sensing, and ambient RGB light measurement over I2C. In this guide, we’ll show you how to wire the sensor to the ESP8266 and the code to use each of its features.

Table of Contents
In this guide, we’ll cover the following topics:
- Introducing the APDS9960 Sensor
- Wiring the APDS9960 Module to the ESP8266
- Installing Libraries for the APDS9960 Sensor
- Getting the Sensor I2C Address and Chip ID
- Examples:
Prerequisites
This tutorial focuses on programming the ESP8266 using the Arduino core. Before proceeding, you should have the ESP8266 Arduino core installed in your Arduino IDE. Follow the next tutorial to install the ESP8266 boards in the Arduino IDE, if you haven’t already.
Introducing the APDS9960 Sensor
The APDS9960 is a 4-in-one sensor that combines gesture detection, proximity sensing, ambient light, and RGB color sensing in one small module. It comes in a compact package with a built-in IR LED and a factory-calibrated LED driver. This sensor is used on the Samsung Galaxy S5 Smartphone.
For our ESP8266 projects, it’s useful to get a breakout board with the sensor. I’ve got the breakout board shown in the picture below.

You can get different modules with the same sensor, but from different providers. They may look different, but they will work the same.
The module uses the I2C communication protocol, which makes it quite simple to incorporate into your ESP32, ESP8266, Arduino, or Raspberry Pi Pico projects.
For more detailed information about how the sensor works, we recommend taking a look at the APDS9960 datasheet.
Key Features of the APDS9960
Here’s a summary of the key features of the APDS9960 sensor:
- Gesture Detection: detects up, down, left, right, and other gestures using IR-based proximity.
- Proximity Sensing: measures distance to objects typically up to 20 cm > analog output: 0–255 range.
- Ambient Light Sensing: measures ambient light intensity, useful to control the brightness of displays.
- RGB Color Sensing: detects red, green, blue, and clear light levels.
- I2C Interface: easy integration with microcontrollers like Arduino, ESP32, ESP8266, etc.
- Operating Voltage: 2.4V to 3.6V.
Where to Buy?
You can check our Maker Advisor Tools page to compare the APDS9960 module price in different stores:
APDS9960 Sensor Module Pinout and Wiring
Let’s take a quick look at the APDS9960 sensor module pinout. If you have a different module, the pinout should be similar.
Pin | Function | Wiring to the ESP8266 |
VCC | Power supply (2.4V to 3.6V) | 3.3V |
GND | Ground | GND |
SDA | I2C data line | GPIO 4 (D2) |
SCL | I2C clock Line | GPIO 5 ( D1) |
INT | Interrupt Output for the proximity sensor (active LOW) | Any digital pin |
VL | Additional power supply for the IR LED | Usually, you don’t need to connect |
APDS9960 Jumpers:
The APDS9960 sensor module comes with two jumpers, which you’ll usually want to leave as they are:

- PS Jumper: the PS jumper connects the power for the sensor and its IR LED. By default, it’s closed (solder blob present), which means, the IR LED will get its power from the VCC pin. The VL pin can be left unconnected.
- I2C PU Jumper: connects 10K pull-up resistors to SDA/SCL (you don’t need to add resistors for the SDA and SCL lines to your circuit).
Wiring the APDS9960 Module to the ESP8266

Here’s a list of the parts required for this tutorial:
- ESP8266 Board – read Best ESP8266 Development Boards
- APDS9960 Sensor
- LED
- 220 Ohm resistor
- SSD1306 OLED Display (optional)
- Jumper wires
- Breadboard
You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!
Wire the APDS9960 sensor to the ESP8266 as shown in the following table/diagram.

Pin | Wiring to the ESP8266 |
VCC | 3.3V |
GND | GND |
SDA | GPIO 4 (D2) |
SCL | GPIO 5 (D1) |
INT | GPIO 14 (D5) (or any digital pin) |
VL | don’t connect * (check your jumpers) |
Recommended reading: ESP8266 Pinout Reference: Which GPIO pins should you use?
Installing Libraries for the APDS9960 Sensor
There are several libraries that make it easy to interface with the APDS9960 sensor. We’ll use the APDS9960 library by Adafruit. Install it on your Arduino IDE.
Go to Sketch > Include Library > Manage Libraries. Search for APDS9960 Adafruit and install the corresponding library and any additional required dependencies

Getting the Sensor I2C Address and Chip ID
The APDS9960 sensor typically uses the I2C address 0x39 and has a chip ID of 0xAB.
However, some clone or counterfeit modules may use a different I2C address or return a different chip ID. To avoid issues, it’s a good idea to run the code below to confirm the actual address and ID of your sensor.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp8266-nodemcu-apds9960-sensor-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <Wire.h>
// Define APDS9960 chip ID register
#define APDS9960_ID_REG 0x92 // Chip ID register address
// Function to read chip ID from a given I2C address
uint8_t readChipID(uint8_t i2cAddress) {
Wire.beginTransmission(i2cAddress);
Wire.write(APDS9960_ID_REG); // Request chip ID register
Wire.endTransmission(false);
Wire.requestFrom(i2cAddress, (uint8_t)1);
if (Wire.available()) {
return Wire.read(); // Read chip ID
}
return 0; // Return 0 if no data (invalid or no response)
}
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("Starting I2C Scanner and Chip ID Reader");
// Initialize I2C
Wire.begin();
Wire.setClock(100000);
// Scan I2C bus for devices
Serial.println("\nScanning I2C bus...");
bool deviceFound = false;
for (uint8_t address = 0x08; address <= 0x7F; address++) {
Wire.beginTransmission(address);
uint8_t error = Wire.endTransmission();
if (error == 0) {
deviceFound = true;
Serial.print("I2C device found at address 0x");
if (address < 16) Serial.print("0");
Serial.print(address, HEX);
// Read and print chip ID
uint8_t chipID = readChipID(address);
Serial.print(" - Chip ID: 0x");
if (chipID < 16) Serial.print("0");
Serial.println(chipID, HEX);
}
}
if (!deviceFound) {
Serial.println("No I2C devices found. Check wiring or try again.");
} else {
Serial.println("\nScan complete.");
}
}
void loop() {
}
After uploading the code, open the Serial Monitor at a baud rate of 115200. You should get your sensor I2C address and chip ID.

In my case, the I2C address is 0x39, which is the expected address, and the chip ID is 0xA8, which is not what is expected (0xAB would be expected). This means I have a counterfeit module.
If you also have a counterfeit module, don’t worry. You can still use it and follow the tutorial. You just need to make a small change in one of the library files.
APDS9960 – Not Expected Chip ID
The Adafruit_APDS9960 library has the chip ID hardcoded, and it checks the sensor ID when initializing the module. If you have a counterfeit one, it won’t initialize properly.
To fix this, follow these steps:
- Open the Arduino IDE installation folder and navigate to the libraries directory.
- Locate the Adafruit_APDS9960_Library folder.
- Inside it, open the Adafruit_APDS9960.cpp file.
- Comment the following lines so that it ignores that you have a different chip ID (lines 100 to 104). Or replace with your chip ID.
/* Make sure we're actually connected */
/*uint8_t x = read8(APDS9960_ID);
if (x != 0xAB) {
return false;
}*/
Save the Adafruit_APDS9960.cpp file.
Now that you have the sensor address, chip ID, and all the required libraries installed, let’s test some examples to understand how the sensor works.
1) ESP8266 with APDS9960 – Detecting Gestures
The APDS9960 can detect basic gestures like up, down, right, and left when you swipe your hand in front of the sensor. With the right code, you can also detect more complex gestures.
The following picture shows the orientation of the sensor for gesture recognition.

The following code shows you the basic commands to detect the four different gestures. This is based on the example provided by the library.
/* This is a library for the APDS9960 digital proximity, ambient light, RGB, and gesture sensor
This sketch puts the sensor in gesture mode and decodes gestures. To use this, first put your hand close to the sensor to enable gesture mode. Then move your hand about 6" from the sensor in the up -> down, down -> up, left -> right, or right -> left direction.
Designed specifically to work with the Adafruit APDS9960 breakout ----> http://www.adafruit.com/products/3595 These sensors use I2C to communicate. The device's I2C address is 0x39
Adafruit invests time and resources providing this open source code, please support Adafruit andopen-source hardware by purchasing products from Adafruit! Written by Dean Miller for Adafruit Industries. BSD license, all text above must be included in any redistribution */
// Complete project details at https://RandomNerdTutorials.com/esp8266-nodemcu-apds9960-sensor-arduino/
#include "Adafruit_APDS9960.h"
Adafruit_APDS9960 apds;
// the setup function runs once when you press reset or power the board
void setup() {
Serial.begin(115200);
if(!apds.begin()){
Serial.println("failed to initialize device! Please check your wiring.");
}
else Serial.println("Device initialized!");
//gesture mode will be entered once proximity mode senses something close
apds.enableProximity(true);
apds.enableGesture(true);
}
// the loop function runs over and over again forever
void loop() {
uint8_t gesture = apds.readGesture();
if (gesture == APDS9960_DOWN) {
Serial.println("v Moving DOWN");
}
if (gesture == APDS9960_UP) {
Serial.println("^ Moving UP");
}
if (gesture == APDS9960_LEFT) {
Serial.println("< Moving LEFT");
}
if (gesture == APDS9960_RIGHT) {
Serial.println("> Moving RIGHT");
}
}
How Does the Code Work
Continue reading to learn how the code works, or skip to the demonstration section.
Importing the Library
First, import the Adafruit_APDS9960 library as follows.
#include "Adafruit_APDS9960.h"
Create an object called apds to interact with the sensor.
Adafruit_APDS9960 apds;
setup()
In the setup(), initialize the Serial Monitor.
Serial.begin(115200);
Then, initialize the sensor using the begin() method as follows.
if(!apds.begin()){
Serial.println("failed to initialize device! Please check your wiring.");
}
else Serial.println("Device initialized!");
The following lines enable proximity sensing and gesture sensing. The gesture detection only works when the sensor detects proximity.
apds.enableProximity(true);
apds.enableGesture(true);
loop()
In the loop(), check if a gesture is detected using the readGesture() function. If it detects a gesture, save it in the gesture variable.
uint8_t gesture = apds.readGesture();
Then, check the gesture detected and print it in the Serial Monitor.
if (gesture == APDS9960_DOWN) {
Serial.println("v Moving DOWN");
}
if (gesture == APDS9960_UP) {
Serial.println("^ Moving UP");
}
if (gesture == APDS9960_LEFT) {
Serial.println("< Moving LEFT");
}
if (gesture == APDS9960_RIGHT) {
Serial.println("> Moving RIGHT");
}
Testing Gesture Detection
After uploading the code, open the Serial Monitor at a baud rate of 115200.
Swipe your hand close to the sensor: up, down, left, and right.

The corresponding gesture will be printed in the Serial Monitor.

2) ESP8266 with APDS9960 – Detecting Gestures and Display on OLED
You can take this previous example to the next level and add an OLED display to your circuit to detect the gestures. This example can be easily modified to display whatever screen you like, depending on the gesture.
For this project, follow these next steps:
1) Add an OLED display to your previous circuit:
OLED | Wiring to the ESP8266 |
VCC | 3.3V |
GND | GND |
SDA | GPIO 4 (D2) |
SCL | GPIO 5 (D1) |
2) Install the Adafruit_SSD1306 Library and corresponding dependencies on your Arduino IDE.
3) Upload the following code to your board.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp8266-nodemcu-apds9960-sensor-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include "Adafruit_APDS9960.h"
#include <Adafruit_SSD1306.h>
#include <Wire.h>
// OLED display settings
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// APDS9960 sensor
Adafruit_APDS9960 apds;
// Function to center text horizontally
void centerText(const char* text, int y) {
int charCount = strlen(text);
int textWidth = charCount * 6;
int x = (SCREEN_WIDTH - textWidth) / 2;
display.setCursor(x, y);
display.println(text);
}
// Function to display UP gesture
void displayScreenUp() {
display.clearDisplay();
centerText("^", 10);
centerText("Moving UP", 30);
display.display();
Serial.println("^ Moving UP");
}
// Function to display DOWN gesture
void displayScreenDown() {
display.clearDisplay();
centerText("v", 10);
centerText("Moving DOWN", 30);
display.display();
Serial.println("v Moving DOWN");
}
// Function to display LEFT gesture
void displayScreenLeft() {
display.clearDisplay();
centerText("<", 10);
centerText("Moving LEFT", 30);
display.display();
Serial.println("< Moving LEFT");
}
// Function to display RIGHT gesture
void displayScreenRight() {
display.clearDisplay();
centerText(">", 10);
centerText("Moving RIGHT", 30);
display.display();
Serial.println("> Moving RIGHT");
}
void setup() {
Serial.begin(115200);
// Initialize OLED display
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x64
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
// Clear the display
display.clearDisplay();
display.display();
delay(500);
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println(F("Gesture Sensor"));
display.display();
delay(100);
// Initialize APDS9960
if(!apds.begin()){
Serial.println("Failed to initialize APDS9960! Check wiring.");
display.clearDisplay();
display.setCursor(0,0);
display.println(F("APDS9960 Failed"));
display.display();
} else {
Serial.println("APDS9960 initialized!");
apds.enableProximity(true);
apds.enableGesture(true);
}
}
void loop() {
uint8_t gesture = apds.readGesture();
if (gesture == APDS9960_DOWN) {
displayScreenDown();
}
if (gesture == APDS9960_UP) {
displayScreenUp();
}
if (gesture == APDS9960_LEFT) {
displayScreenLeft();
}
if (gesture == APDS9960_RIGHT) {
displayScreenRight();
}
}
We won’t explain how this code works. To learn how to interface an OLED SSD1306 with the ESP8266 read the following guide: ESP8266 0.96 inch OLED Display with Arduino IDE.
Demonstration
Swipe your hand in different directions in front of the sensor. The gesture will be displayed on the OLED screen.


3) ESP8266 with APDS9960 – Detecting Proximity
The APDS9960 sensor can detect proximity within a range of approximately 10 to 20 cm. When an object comes close to the sensor, it activates the INT (interrupt) pin. This is an active LOW interrupt, meaning the pin’s state changes from HIGH to LOW when proximity is detected.
The APDS9960 sensor allows you to set a proximity threshold, which defines how close an object must be before it’s considered “detected.”
For this example, follow the next steps:
1) Wire an LED to your circuit. We’re connecting it to GPIO 12 (D6), but you can use any other digital output.
2) Upload the following code to your board. This code is based on the example provided by the Adafruit library.
/* This is a library for the APDS9960 digital proximity, ambient light, RGB, and gesture sensor
This sketch puts the sensor in proximity mode and enables the interrupt to fire when proximity goes over a set value
Designed specifically to work with the Adafruit APDS9960 breakout ----> http://www.adafruit.com/products/3595 These sensors use I2C to communicate. The device's I2C address is 0x39
Adafruit invests time and resources providing this open source code, please support Adafruit andopen-source hardware by purchasing products from Adafruit! Written by Dean Miller for Adafruit Industries. BSD license, all text above must be included in any redistribution */
// Complete project details at https://RandomNerdTutorials.com/esp8266-nodemcu-apds9960-sensor-arduino/
#include "Adafruit_APDS9960.h"
//the pin that the interrupt is attached to
#define INT_PIN 14
// LED for visual output
#define LED_PIN 12
//create the APDS9960 object
Adafruit_APDS9960 apds;
void setup() {
Serial.begin(115200);
pinMode(INT_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
if(!apds.begin()){
Serial.println("failed to initialize device! Please check your wiring.");
}
else Serial.println("Device initialized!");
//enable proximity mode
apds.enableProximity(true);
//set the interrupt threshold to fire when proximity reading goes above 175
apds.setProximityInterruptThreshold(0, 175);
//enable the proximity interrupt
apds.enableProximityInterrupt();
}
void loop() {
//print the proximity reading when the interrupt pin goes low
if(!digitalRead(INT_PIN)){
Serial.println(apds.readProximity());
digitalWrite(LED_PIN, HIGH);
//clear the interrupt
apds.clearInterrupt();
}
digitalWrite(LED_PIN, LOW);
}
How Does the Code Work
Continue reading to learn how the code works.
Importing the Library
First, import the Adafruit_APDS9960 library as follows.
#include "Adafruit_APDS9960.h"
Create an object called apds to interact with the sensor.
Adafruit_APDS9960 apds;
Defining Pins
Define the pin that the INT pin is connected to. In our case, it is connected to GPIO 14 (D5).
//the pin that the interrupt is attached to
#define INT_PIN 14
Then, define the pin that the LED is connected to.
// LED for visual output
#define LED_PIN 12
setup()
In the setup(), initialize the Serial Monitor.
Serial.begin(115200);
Set the interrupt pin as an input with an internal pull-up resistor, and the LED as an output.
pinMode(INT_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
Then, initialize the sensor using the begin() method as follows.
if(!apds.begin()){
Serial.println("failed to initialize device! Please check your wiring.");
}
else Serial.println("Device initialized!");
Enable the proximity detection using the enableProximity() function on the apds object.
apds.enableProximity(true);
Now, set the proximity interrupt threshold range using the setProximityInterruptThreshold() function. The sensor will only trigger an interrupt if it detects something close enough to produce a reading over 175 (the maximum reading is 255—the closer the object, the higher the value).
apds.setProximityInterruptThreshold(0, 175);
Then, activate the interrupt on proximity.
apds.enableProximityInterrupt();
After this, when the threshold is crossed, the sensor will pull the INT pin to LOW.
//set the interrupt threshold to fire when proximity reading goes above 175
apds.setProximityInterruptThreshold(0, 175);
You can use this interrupt to trigger an alert or perform a task only when something is near the sensor.
loop()
In the loop(), check the state of the INT pin. If it is LOW, it means we have an object close to the sensor. In that case, we read the proximity value with apds.readProximity() and light up the LED.
//print the proximity reading when the interrupt pin goes low
if(!digitalRead(INT_PIN)){
Serial.println(apds.readProximity());
digitalWrite(LED_PIN, HIGH);
//clear the interrupt
apds.clearInterrupt();
}
After that, we call the clearInterrupt() function. It resets the interrupt flag on the APDS9960 sensor. When the sensor detects a proximity event above the threshold, it pulls the INT pin LOW to signal the event.
//clear the interrupt
apds.clearInterrupt();
This LOW state will remain until the interrupt is cleared by calling the clearInterrupt() function. After this, the INT pin will go back to its original state, HIGH.
When the pin is not triggered, turn the LED off.
digitalWrite(LED_PIN, LOW);
Demonstration
Upload the previous code to your board.
Put something closer to the sensor. You’ll see that when it reaches a certain proximity threshold, the LED turns on.

At the same time, the proximity values are printed in the Serial Monitor.

4) ESP8266 with APDS9960 – Detecting RGB Light
The APDS9960 sensor can measure red, green, blue, and clear light. The clear channel measures overall brightness, while the red, green, and blue channels tell you how much of each color is present.
The values you get from the sensor are relative values. Higher values represent more light of that specific color. You can compare the values to try to estimate the dominant color of an object or environment.
The following code reads the red, green, blue, and clear light, and displays the results in the Serial Monitor. This code is based on this example provided by the library.
/* This is a library for the APDS9960 digital proximity, ambient light, RGB, and gesture sensor
This sketch puts the sensor in color mode and reads the RGB and clear values.
Designed specifically to work with the Adafruit APDS9960 breakout ----> http://www.adafruit.com/products/3595 These sensors use I2C to communicate. The device's I2C address is 0x39
Adafruit invests time and resources providing this open source code, please support Adafruit andopen-source hardware by purchasing products from Adafruit! Written by Dean Miller for Adafruit Industries. BSD license, all text above must be included in any redistribution */
// Complete project details at https://RandomNerdTutorials.com/esp8266-nodemcu-apds9960-sensor-arduino/
#include "Adafruit_APDS9960.h"
Adafruit_APDS9960 apds;
void setup() {
Serial.begin(115200);
if(!apds.begin()){
Serial.println("failed to initialize device! Please check your wiring.");
}
else Serial.println("Device initialized!");
//enable color sensing mode
apds.enableColor(true);
// Set ADC gain to high (16x) for better color sensitivity
apds.setADCGain(APDS9960_AGAIN_16X);
}
void loop() {
//create some variables to store the color data in
uint16_t r, g, b, c;
//wait for color data to be ready
while(!apds.colorDataReady()){
delay(5);
}
//get the data and print the different channels
apds.getColorData(&r, &g, &b, &c);
Serial.print("Red Light: ");
Serial.print(r);
Serial.print(" || Green Light: ");
Serial.print(g);
Serial.print(" || Blue Light: ");
Serial.print(b);
Serial.print(" || Ambient Light: ");
Serial.println(c);
Serial.println();
delay(500);
}
How Does the Code Work?
Enable the color sensing mode.
//enable color sensing mode
apds.enableColor(true);
Then, we’re setting a 16x gain for better sensitivity. This line is optional.
// Set ADC gain to high (16x) for better color sensitivity
apds.setADCGain(APDS9960_AGAIN_16X);
Here’s all gain options:
- APDS9960_AGAIN_1X
- APDS9960_AGAIN_4X
- APDS9960_AGAIN_16X
- APDS9960_AGAIN_64X
In the loop(), create four variables to save the color data.
- r = red
- g = green
- b = blue
- c = clear (ambient light)
Wait until new color data is available from the sensor.
while(!apds.colorDataReady()){
delay(5);
}
Once the data is ready, get the different values into our variables as follows:
apds.getColorData(&r, &g, &b, &c);
Then, print the results in the Serial Monitor.
Serial.print("Red Light: ");
Serial.print(r);
Serial.print(" || Green Light: ");
Serial.print(g);
Serial.print(" || Blue Light: ");
Serial.print(b);
Serial.print(" || Ambient Light: ");
Serial.println(c);
Serial.println();
Demonstration
Upload the previous code to your board. Then, open the Serial Monitor at a baud rate of 115200.
Try pointing your smartphone’s flashlight at the sensor—you’ll notice the light intensity values start to increase.

You can also experiment with colored lights or shine the flashlight onto a colorful object. The reflected light will hit the sensor, allowing it to detect the color of the object.

Wrapping Up
In this tutorial, you learned how to use the APDS9960 sensor module with the ESP8266. It can detect basic gestures, proximity, measure ambient light, and RGB light intensities.
We’ve shown you some basic examples to put the sensor to the test and learn the basic methods to use its features.
We hope you’ve found this guide useful. We have more guides for ESP8266 sensors and modules:
To learn more about the ESP8266, check out our resources:
- Home Automation using ESP8266 (eBook)
- MicroPython Programming with ESP32 and ESP8266 (eBook)
- Build Web Servers with ESP32 and ESP8266 (eBook)
- Free ESP8266 Tutorials and Guides
Thanks for reading.