A Raspberry Pi Magic Mirror is a smart mirror built using a Raspberry Pi, a display, and two-way mirror glass, running MagicMirror² software to show information like time, weather, and calendars.
The display shows through the mirror surface so you can see the time, weather, calendar, and headlines while the rest stays reflective. It looks fancy, but it’s basically a screen hiding behind glass.
The software most people use is MagicMirror², an open-source project created by Michael Teeuw and maintained on GitHub. MagicMirror² runs on Node.js, installs dependencies with npm, and renders the interface with Electron. You configure what appears on-screen by editing one file: config.js. If you can follow steps and copy commands carefully, you can build this.
This guide aims for a mirror that is stable and useful, not a fragile science project you “fix” every weekend.
What You’re Building
A working MagicMirror build has four main pieces:
- Raspberry Pi OS on a microSD card
- MagicMirror² installed from GitHub
- A display connected over HDMI
- A two-way mirror mounted in front of the display
Once installed, MagicMirror can auto-start at boot using PM2, a Node process manager. That way, if power drops or the Pi reboots, the mirror comes back on by itself.
How MagicMirror² Works
MagicMirror² is an application. It is not an operating system. It runs on Raspberry Pi OS and uses Electron to draw a full-screen interface.
Key idea: everything you see is a module.
- Clock is a module.
- Calendar is a module.
- Weather is a module.
- News feed is a module.
Modules render based on config.js. If config.js has a syntax error, the interface can fail to load. If one third-party module crashes hard, it can take down the interface. That’s why this guide pushes a simple habit: change one thing at a time, then test.
Raspberry Pi Compatibility and Requirements
You can run MagicMirror² on several Raspberry Pi models, but not all of them feel good.
Raspberry Pi (What Actually Matters)
For a Magic Mirror build, the Raspberry Pi 4 is the most practical option. The key factors that affect performance are RAM amount and power stability, not brand variants or accessories.
What to look for:
- Raspberry Pi 4 Model B
- At least 2GB RAM (4GB gives more headroom)
- Genuine board, not a clone
- Separate power supply rather than bundled cheap chargers
Many builders use standard Raspberry Pi 4 boards available through common retailers. As long as the board is authentic and paired with a proper power supply, performance differences between sellers are negligible.
Raspberry Pi 4 Model B 2019 Quad Core 64 Bit WiFi Bluetooth (4GB)
- Broadcom BCM2711, quad-core Cortex-A72 (ARM v8) 64-bit SoC @ 1. 5GHz—4GB LPDDR4-2400 SDRAM
- 2. 4 GHz and 5. 0 GHz IEEE 802. 11B/g/n/ac Wireless LAN, Bluetooth 5. 0, double-true Gigabit Ethernet
- 2 × USB 3. 0 ports, 2 x USB 2. 0 Ports—2 × micro HDMI ports supporting up to 4Kp60 video resolution
- 2-lane MIPI DSI/CSI ports for camera and display–4-pole stereo audio and composite video port–Micro SD card slot for loading operating system and data storage
5V 3A USB Type C Adapter for Raspberry Pi 4 Model B Power Supply Cord with ON/Off Switch
- [Compatibility]: Fit for Raspberry Pi 4, Pi 4 Model B.
- [Power Specs]: Input 100V-240V 50/60Hz; Output: 5V 3A.
- [Plug Type]: Type-C, USB-C plug. Product cable length 3.3 feet, with ON/Off Switch Design.
- [Safety Smart]: Built-in emergency protection mechanism with short circuit, over current, over voltage, over temperature protection.
Works but slower
- Raspberry Pi 3B / 3B+
Not recommended
- Raspberry Pi Zero / Zero 2 W
Electron behaves like a browser running full-screen all the time. Browsers like RAM. Underpowered boards can run it, but you’ll see longer boot times, more stutter, and more pain once you add modules.
Raspberry Pi OS
- Raspberry Pi OS Lite (64-bit) is best for a long-running mirror.
- Raspberry Pi OS with Desktop is fine for first setup, but it uses more memory.
Power supply matters
Use a 5V 3A USB-C power supply intended for Raspberry Pi 4. Cheap chargers cause undervoltage and weird behavior like random restarts or slowdowns. People blame MagicMirror for this, but it’s usually power.
Storage
- microSD card: 16GB minimum, Class 10 or better
Cheap cards fail quietly. Your install “works” until it doesn’t, then you lose hours.
Hardware Checklist
Core hardware
- Raspberry Pi 4
- microSD card (16GB+)
- 5V 3A power supply (USB-C for Pi 4)
- HDMI monitor or display (16–24 inches is the sweet spot)
- Two-way mirror (acrylic or glass)
- Frame/enclosure (wood, deep picture frame, custom box frame)
- HDMI cable
- Keyboard/mouse for initial setup (optional if headless)
- Wi-Fi or Ethernet
Optional upgrades
- PIR motion sensor (HC-SR501 is common) using GPIO
- Heat sinks or small fan
- USB microphone (for voice modules)
- USB camera (for face recognition and OpenCV modules)
- Ethernet cable (more stable than Wi-Fi)
Acrylic vs Glass Two-Way Mirror
Both work. The choice is mostly about durability and ease.
Acrylic
- Easy to cut
- Lightweight
- Less likely to shatter
- Scratches easily and needs gentle cleaning
Glass
- Better reflection quality
- More durable surface
- Heavier and can crack if mishandled
- Harder to cut without proper tools
For first builds, acrylic is fine. For “this is going in my house for years,” glass is nicer if you can mount it safely.
The parts below are common choices for MagicMirror² builds. The exact seller matters less than meeting these specifications.
Hardware Buying Guide (What to Look For and Why)
| Component | What Actually Matters | Common Choice for This Build | Amazon Link |
|---|---|---|---|
| Raspberry Pi | RAM amount and power stability matter more than brand or seller. The Pi 4 handles MagicMirror² smoothly without lag. | Raspberry Pi 4 Model B (2GB or 4GB RAM) | [Check current price] |
| Power Supply | Undervoltage causes random crashes and throttling. Many issues blamed on software are power-related. | Official 5V 3A USB-C Raspberry Pi power supply | [Check availability] |
| microSD Card | Speed and reliability matter more than capacity. Cheap cards corrupt silently. | 16GB–32GB Class 10 microSD from a known brand | [View options] |
| Monitor | Brightness matters more than resolution. A dim screen behind a mirror looks washed out. | 16–24 inch 1080p HDMI monitor (used or new) | [Browse compatible monitors] |
| Two-Way Mirror (Acrylic) | Easier to cut and lighter. Works well for first builds and wall mounting. | Acrylic two-way mirror sheet cut to screen size | [See sizes] |
| Two-Way Mirror (Glass) | Better reflection quality and durability. Heavier and harder to cut. | Glass two-way mirror panel (pre-cut if possible) | [Check options] |
| Frame / Enclosure | Depth and airflow matter more than looks. Shallow frames trap heat. | Deep picture frame or simple wooden box frame | [See frame materials] |
| HDMI Cable | Length and flexibility matter more than version numbers. | Standard HDMI cable (short length preferred) | [Check compatibility] |
| PIR Motion Sensor | Simple presence detection saves power and extends monitor life. | HC-SR501 PIR motion sensor (GPIO-compatible) | [View sensor] |
| Cooling (Optional) | Enclosed builds benefit from basic airflow. No need for aggressive cooling. | Small heat sink set or low-noise fan | [View cooling options] |
| Microphone (Optional) | Required only for voice modules. USB is simplest. | Basic USB microphone (no drivers required) | [See microphones] |
| Camera (Optional) | Needed for facial recognition modules using OpenCV. | USB webcam with Linux support | [Browse cameras] |
Software You’ll Install
- Raspberry Pi OS
- Git, curl
- Node.js and npm (Node 18 LTS is a safe baseline for Raspberry Pi OS)
- MagicMirror² from GitHub
- PM2 for auto-start and restarts
- A text editor (Nano is fine)
Install Raspberry Pi OS
Use Raspberry Pi Imager (or Balena Etcher) to flash your microSD card.
Headless setup (no monitor/keyboard)
If you plan to SSH in:
- After flashing, open the boot partition on the SD card.
- Create an empty file named
ssh(no extension). - Add Wi-Fi config if needed (many people use a
wpa_supplicant.conffile, depending on OS image and setup method).
If you’re using Raspberry Pi Imager, you can often set:
- hostname
- Wi-Fi SSID/password
- enable SSH
- user/password
inside the imager options. That is usually the cleanest route.
First boot basics
Once booted, log in and run:
sudo apt update && sudo apt upgrade -y
Then set locale/timezone:
sudo raspi-config
Also, change your password:
passwd
Yes, it’s your house. Still, don’t leave default credentials on a networked device.
Install Node.js and npm
MagicMirror² requires Node.js. On Raspberry Pi OS, Node 18 LTS is a common stable choice.
curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs
Verify versions:
node -v
npm -v
If Node is missing, stop here and fix that first. Almost every “MagicMirror won’t install” problem starts with Node issues.
Installing MagicMirror² From GitHub
Clone the repo and install dependencies:
cd ~
git clone https://github.com/MichMich/MagicMirror
cd MagicMirror
npm install
This can take a while. A Pi 4 is faster than a Pi 3. If it looks “stuck,” give it time unless you see clear errors.
Create your config file from the sample:
cp config/config.js.sample config/config.js
Start MagicMirror:
npm start
If you have a monitor connected, the MagicMirror interface should appear. If you’re headless, you’re mainly confirming the process runs without crashing.
Stop it with:
CTRL + C
Common first-run notes
- Weather may be blank until configured.
- Calendar may show nothing until you add an ICS feed.
- That’s normal at this stage.
Auto-Starting MagicMirror² With PM2
PM2 is the tool that turns this into an appliance. It starts MagicMirror at boot, restarts it if it crashes, and gives you logs.
Install PM2:
sudo npm install -g pm2
Start MagicMirror using the provided config:
pm2 start ~/MagicMirror/installers/pm2_MagicMirror.json
Save the process list:
pm2 save
Enable PM2 at boot:
pm2 startup
PM2 prints a command. Copy and run it exactly.
Reboot:
sudo reboot
After reboot, check:
pm2 list
If it’s online, you’re set.
Helpful PM2 commands:
pm2 logs
pm2 restart mm
pm2 stop mm
pm2 start mm
Building the Mirror Frame and Assembly
This is the physical part. Keep it simple.
Choose a monitor
- 16–24 inches is easiest to frame
- 1080p is enough
- make sure brightness is decent (a dim monitor behind a mirror looks sad)
Removing the bezel can slim the build, but it’s optional. If you do it, be careful. Some monitors use their casing for structural support.
Frame requirements
The frame must:
- hold the mirror flat
- keep the monitor aligned behind it
- allow airflow for the Pi and monitor
A sealed box looks clean but traps heat. Vent holes, a gap, or a small fan solves most issues.
Mount the Raspberry Pi
Mount the Pi behind the monitor using:
- adhesive Velcro
- zip ties
- small screw mounts
Keep it:
- close to HDMI
- accessible for the microSD card
- away from pinched cables
Cable routing
Route and secure:
- Pi power cable
- monitor power cable
- HDMI cable
Cable clips and zip ties are cheap. Use them. Loose cables become “mystery failures” later.
Final assembly order
- Test the monitor and Pi on a table first.
- Install the mirror into the frame.
- Mount the monitor behind it.
- Attach the Pi.
- Route cables.
- Test again before sealing the back.
If it’s slightly crooked, that’s life. You’ll notice it. Other people won’t.
Configuring MagicMirror² Modules
Everything lives in:
~/MagicMirror/config/config.js
Open it:
nano ~/MagicMirror/config/config.js
After edits, restart:
pm2 restart mm
If you get a black screen, check config syntax:
cd ~/MagicMirror
npm run config:check
How module config works
MagicMirror uses a modules: [] array. Each module entry includes:
modulenameposition- optional
config
Positions you’ll actually use:
top_lefttop_rightbottom_leftbottom_rightbottom_barmiddle_center
Core module examples (copy-ready)
Clock
{
module: "clock",
position: "top_left",
config: {
timeFormat: 12,
showSeconds: false
}
},
Calendar (ICS feed)
MagicMirror’s calendar module reads ICS URLs. Google Calendar can provide a private ICS link.
{
module: "calendar",
position: "top_left",
config: {
calendars: [
{
url: "YOUR_PRIVATE_ICS_URL",
symbol: "calendar"
}
]
}
},
Weather (OpenWeatherMap)
Weather commonly uses OpenWeatherMap. You’ll need an API key and location ID.
{
module: "weather",
position: "top_right",
config: {
location: "New York",
locationID: "5128581",
apiKey: "YOUR_API_KEY"
}
},
If weather stays blank, it’s usually:
- wrong API key
- wrong location ID
- network issues
Newsfeed (RSS)
{
module: "newsfeed",
position: "bottom_bar",
config: {
feeds: [
{ title: "BBC", url: "http://feeds.bbci.co.uk/news/rss.xml" }
],
showSourceTitle: true,
showPublishDate: true
}
},
Compliments
{
module: "compliments",
position: "lower_third",
config: {
compliments: {
anytime: [
"You made coffee. That counts as productivity."
]
}
}
},
Config rules that prevent pain
- Change one thing at a time.
- Restart and confirm it works.
- Back up
config.jsandcustom.cssbefore big changes.
Adding Third-Party Modules Safely
Most third-party modules live on GitHub and install like this:
- Clone into the modules folder:
cd ~/MagicMirror/modules
git clone https://github.com/username/module-name.git
- Read the README
Some modules need:
cd module-name
npm install
- Add the module block to
config.js - Restart:
pm2 restart mm
How to avoid breaking everything
- Add one module at a time.
- If the screen goes black, comment out the last module you added and restart.
- If a module hasn’t been updated in years, expect problems with newer Node/Electron combos.
To remove a broken module:
rm -rf ~/MagicMirror/modules/module-name
Styling With custom.css
Custom styling lives here:
~/MagicMirror/css/custom.css
Create or edit it:
nano ~/MagicMirror/css/custom.css
A few useful tweaks:
Increase base font size:
body { font-size: 20px; }
Add padding to regions:
.region { padding: 20px; }
Reduce secondary text brightness:
.dimmed { opacity: 0.6; }
Restart after changes:
pm2 restart mm
Mirrors reduce contrast. Bigger text and clean spacing beat fancy design every time.
Smart Features (Optional)
PIR motion sensor (GPIO)
A PIR sensor can turn the display off when nobody is there and on when someone walks up. It connects to the Raspberry Pi GPIO pins and can trigger HDMI power control.
Common approach:
- PIR input triggers a script
- script calls HDMI on/off commands
- MagicMirror keeps running, the display sleeps
This upgrade improves daily use more than most “cool” features.
Voice control
Voice modules require:
- USB microphone
- a compatible module
- setup time and tuning
It’s workable. It’s also easy to get annoyed by false triggers, so don’t make it your first upgrade.
Facial recognition (OpenCV)
Facial recognition modules often rely on OpenCV and a USB camera. They can show different modules for different users. They also depend heavily on lighting and camera quality. If you want this, plan for tinkering.
Smart home integration (MQTT, Homebridge)
Many smart home displays use MQTT or bridge platforms. If you already run a smart home stack, a mirror can display device status, sensor data, and alerts.
Performance, Stability, and Security
Heat control
Check temperature:
vcgencmd measure_temp
If temps run high:
- add heat sinks
- add airflow
- add a small fan
- avoid sealed enclosures
Network reliability
Ethernet is more stable than Wi-Fi. If you use Wi-Fi, use 5GHz when possible and keep the Pi away from metal and tight enclosures that block signal.
Security basics
- change default password
- keep SSH on your local network
- don’t expose the Pi directly to the internet
This is not paranoia. This is basic “don’t be lazy” hygiene.
Troubleshooting
Black screen
Most common cause: config.js syntax error.
Check:
cd ~/MagicMirror
npm run config:check
pm2 logs
Fix the last change you made, restart, and confirm.
Modules not loading
- third-party module dependency missing
- API key missing or wrong
- module folder name mismatch
Disable the new module first, restart, then re-add it correctly.
PM2 says online but display is blank
PM2 can show the process running even if Electron isn’t rendering correctly. Check logs:
pm2 logs
HDMI “no signal”
- wrong input selected
- loose cable
- Pi not detecting display
If you need to force HDMI output, update boot config (varies by OS version), then reboot. This is hardware-specific enough that you should confirm your current Raspberry Pi OS boot configuration path before editing.
Maintenance
Update MagicMirror² occasionally:
cd ~/MagicMirror
git pull
npm install
pm2 restart mm
Back up these files:
~/MagicMirror/config/config.js~/MagicMirror/css/custom.css
If you make frequent changes, put those files into a private GitHub repo so you can roll back fast.
FAQ
Can I use a Raspberry Pi 3?
Yes. Expect slower performance, especially with more modules.
Do I need to know how to code?
No. You need to edit config files carefully.
What happens if power goes out?
The Pi reboots and PM2 starts MagicMirror automatically if configured.
Is it safe to run 24/7?
Yes, if you manage heat and use a proper power supply.
Final Notes
If you want a mirror that stays reliable: keep the build simple, keep the config clean, and add features slowly. That’s the boring advice that works.



