I Built a Raspberry Pi Magic Mirror Using MagicMirror². Here’s What Actually Worked

How to Build a Raspberry Pi Magic Mirror With MagicMirror²

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 fancier than it is. It is basically a screen hiding behind glass, and it is a genuinely satisfying build once it is running reliably on the wall.

The software most people use is MagicMirror², an open-source project created by Michael Teeuw and maintained on GitHub. MagicMirror² runs on Node.js, renders the interface with Electron, and lets you configure everything through one file: config.js. If you can follow steps and copy commands carefully, you can build this. This guide aims for a mirror that stays stable and useful, not a fragile science project you fix every weekend.

Key Takeaways

  • MagicMirror² now requires Node.js v22 or higher. Node 18 will fail on current releases.
  • Raspberry Pi 4 with 2GB or 4GB RAM is the practical sweet spot for this build
  • PM2 is what turns the mirror into an appliance that survives reboots without intervention
  • Change one module at a time and test before adding another. A single config.js syntax error kills the whole interface.
  • Power supply quality matters more than almost any other component choice
  • Acrylic mirror is fine for first builds. Glass looks better for permanent installs.

What You Are 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, and a two-way mirror mounted in front of the display. Once installed, MagicMirror auto-starts at boot using PM2, a Node process manager. If power drops or the Pi reboots, the mirror comes back by itself.

How MagicMirror² works

MagicMirror² is an application, not an operating system. It runs on Raspberry Pi OS and uses Electron to draw a full-screen interface. Everything you see is a module. Clock is a module. Calendar is a module. Weather is a module. Modules render based on config.js. If config.js has a syntax error, the interface fails to load. If one third-party module crashes hard, it can take down the whole interface. The single best habit you can build with this project is changing one thing at a time and testing before moving on.

Magic mirror build layers

Hardware Requirements

Raspberry Pi model

The Raspberry Pi 4 is the practical choice for a Magic Mirror build. Electron behaves like a browser running full-screen all the time, and browsers like RAM. The Pi 4 with 2GB handles it comfortably. 4GB gives more headroom once you start stacking modules.

  • Pi 4 with 2GB or 4GB RAM: recommended
  • Pi 3B or 3B+: works, noticeably slower, longer boot times
  • Pi Zero or Zero 2 W: not recommended. Electron will make you regret it.

Raspberry SC15184 Pi 4 Model B 2019 Quad Core 64 Bit WiFi Bluetooth (2GB)

5.0
Amazon.com

Power supply

Use a 5V 3A USB-C power supply intended for Raspberry Pi 4. Cheap chargers cause undervoltage and weird behavior like random restarts and slowdowns. People blame MagicMirror for this constantly. It is usually the power supply. For the full picture on why power matters, see Preventing SD Card Corruption on Raspberry Pi.

Raspberry Pi 15W USB-C Power Supply US – Black

Amazon.com

Storage

16GB microSD minimum, Class 10 or better. Cheap cards fail quietly. Your install works until it does not, then you lose hours. If this mirror is going to run 24/7 on a wall, the SD card is the component most likely to give you grief over time. A USB SSD boot setup eliminates that failure mode entirely. See Booting Raspberry Pi from USB SSD if you want to set that up before installing MagicMirror.

SANDISK 256GB High Endurance Video microSDXC Card with Adapter for dash cam and home monitoring systems – C10, U3, V30, 4K UHD, Micro SD Card -…

Amazon.com

Operating system

Raspberry Pi OS Lite 64-bit is best for a long-running mirror. It uses less memory than the desktop version and has no background services competing for resources. The Desktop version is fine for initial setup if you want a GUI, but strip it back before deploying the mirror on the wall.

Full Hardware Checklist

Core hardware

  • Raspberry Pi 4 (2GB or 4GB)
  • microSD card (16GB+, Class 10)
  • 5V 3A USB-C power supply
  • HDMI monitor or display (16 to 24 inches is the practical sweet spot)
  • Two-way mirror, acrylic or glass, cut to screen size
  • Frame or enclosure with enough depth for the monitor and Pi
  • Micro HDMI to HDMI cable
  • Keyboard and mouse for initial setup (can be removed after)

Optional upgrades

  • HC-SR501 PIR motion sensor via GPIO for display sleep and wake
  • Heat sinks or small fan (enclosed builds need airflow)
  • USB microphone for voice modules
  • USB camera for facial recognition modules
  • Ethernet cable for more stable network connectivity

Acrylic vs Glass Two-Way Mirror

Both work. Acrylic is easier to cut, lighter, and less likely to shatter, which makes it the sensible choice for a first build. It scratches easily so clean it gently. Glass has better reflection quality and a more durable surface, but it is heavier and harder to cut without proper tools. For a mirror that is going on the wall permanently, glass is worth the extra effort. For a first build where you are still figuring out frame depth and cable routing, acrylic gets you there faster.

Software Installation

Step 1: Flash Raspberry Pi OS

Use Raspberry Pi Imager to flash the SD card. In the Imager settings (the gear icon), configure your hostname, Wi-Fi credentials, SSH access, and username before flashing. This saves the first-boot setup entirely and means a headless Pi is ready to SSH into immediately after the first boot.

After first boot, update the system:

sudo apt update && sudo apt upgrade -y

Set locale and timezone:

sudo raspi-config

Change the default password. Yes, it is your house. Still, do not leave default credentials on a networked device:

passwd

Step 2: Install Node.js v22

This is where most guides get people into trouble. MagicMirror² now requires Node.js v22 or higher. Node 18, which was the safe baseline a year ago, will fail on current MagicMirror releases with a clear engine version error. Install Node 22 LTS using the NodeSource setup script:

curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs

Verify you have the right version before continuing:

node -v
npm -v

If node -v returns anything below v22, stop here and fix it. Almost every “MagicMirror won’t install” problem starts with the wrong Node version.

Step 3: Install MagicMirror²

The simplest and most reliable install method is the official community installer script. It handles Node version checking, clones the repo, and installs dependencies in the right order:

bash -c "$(curl -sL https://raw.githubusercontent.com/sdetweil/MagicMirror_scripts/master/raspberry.sh)"

This takes a while. A Pi 4 will spend 5 to 10 minutes on dependency installation with little terminal output. Give it time unless you see clear errors.

If you prefer the manual route, clone the repo and install dependencies yourself. Note the repo has moved to MagicMirrorOrg on GitHub, and the install command has changed from npm install:

cd ~
git clone https://github.com/MagicMirrorOrg/MagicMirror
cd MagicMirror
node --run install-mm

Create your config from the sample:

cp config/config.js.sample config/config.js

Test that it runs:

node --run start

If you have a monitor connected, the MagicMirror interface appears. Stop it with CTRL+C when ready to move on.

Step 4: Set Up PM2 for Auto-Start

PM2 is what turns this from a manual project into an appliance. It starts MagicMirror at boot, restarts it if it crashes, and gives you logs.

sudo npm install -g pm2

pm2 start ~/MagicMirror/installers/pm2_MagicMirror.json

pm2 save

pm2 startup

PM2 prints a command after running pm2 startup. Copy and run it exactly. It sets up the systemd service that launches PM2 at boot.

sudo reboot

After reboot, confirm MagicMirror is running:

pm2 list

Useful PM2 commands you will use regularly:

pm2 logs
pm2 restart mm
pm2 stop mm
pm2 start mm

Physical Build and Assembly

Monitor selection

16 to 24 inches is the easiest range to frame. 1080p is enough. Brightness matters more than resolution here. A dim monitor behind a mirror looks washed out and sad. If you are buying used, test brightness before committing. Some older monitors that look fine as a desktop display look terrible behind mirror glass.

Frame requirements

The frame needs to hold the mirror flat, keep the monitor aligned behind it, and allow airflow. A sealed box looks clean and traps heat. Vent holes, a gap at the back, or a small fan solves most heat issues. Depth is the thing people underestimate. You need room for the monitor, the Pi, and all the cables without anything being pinched.

Final assembly order

  1. Test the monitor and Pi on a table before putting anything in the frame
  2. Install the mirror into the frame
  3. Mount the monitor behind it, aligned to the mirror
  4. Attach the Pi behind the monitor using Velcro, zip ties, or screw mounts
  5. Route and secure all cables with clips or zip ties
  6. Test everything again before sealing the back panel

Loose cables are how mystery failures happen three months after the mirror goes on the wall. Zip ties are cheap. Use them.

Magic mirror module positions

Configuring Modules

Everything lives in ~/MagicMirror/config/config.js. Open it, make one change, restart, and confirm it works before making another change.

nano ~/MagicMirror/config/config.js

After any edit, restart and check logs if something looks wrong:

pm2 restart mm
cd ~/MagicMirror && npm run config:check
pm2 logs

Module positions

MagicMirror uses a modules: [] array. Each entry has a module name, a position, and optional config. Positions you will actually use: top_left, top_right, bottom_left, bottom_right, bottom_bar, middle_center, and lower_third.

Core module examples

Clock:

{
  module: "clock",
  position: "top_left",
  config: {
    timeFormat: 12,
    showSeconds: false
  }
},

Calendar (ICS feed, Google Calendar provides a private ICS URL):

{
  module: "calendar",
  position: "top_left",
  config: {
    calendars: [
      {
        url: "YOUR_PRIVATE_ICS_URL",
        symbol: "calendar"
      }
    ]
  }
},

Weather (requires a free OpenWeatherMap API key):

{
  module: "weather",
  position: "top_right",
  config: {
    location: "New York",
    locationID: "5128581",
    apiKey: "YOUR_API_KEY"
  }
},

Newsfeed:

{
  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."
      ]
    }
  }
},

Adding third-party modules

cd ~/MagicMirror/modules
git clone https://github.com/username/module-name.git
cd module-name
npm install

Add the module block to config.js and restart. Add one module at a time. If the screen goes black, comment out the new module entry in config.js and restart. If a module has not been updated in two or more years, expect compatibility problems with current Node and Electron versions. To remove a broken module:

rm -rf ~/MagicMirror/modules/module-name

Styling with custom.css

Custom styling lives at ~/MagicMirror/css/custom.css. Mirrors reduce contrast, so bigger text and clean spacing beat fancy design every time.

body { font-size: 20px; }
.region { padding: 20px; }
.dimmed { opacity: 0.6; }

Smart Features

PIR motion sensor

A PIR motion sensor connected to the GPIO header can turn the display off when nobody is nearby and back on when someone walks up. The HC-SR501 is the common choice. It connects to a GPIO pin and triggers a script that calls HDMI power commands. This upgrade improves daily use more than almost any module you could add. The display staying dark when the room is empty also extends monitor life significantly over months of use.

HiLetgo 3pcs HC-SR501 PIR Infrared Sensor Human Body Infrared Motion Module for Arduino Raspberry Pi

Amazon.com

Voice control

Voice modules require a USB microphone and setup time. They work, but false triggers are annoying. Get the mirror stable first, then add voice if you still want it after a few weeks of use.

Facial recognition

Facial recognition modules rely on OpenCV and a USB camera and can show different module layouts for different people. They also depend heavily on lighting and camera quality. Plan for tinkering. This is a weekend project on top of a weekend project.

Performance and Stability

A mirror running 24/7 needs to be boring-stable, not peak-speed. Check temperature occasionally, especially in the first week:

vcgencmd measure_temp

If temperatures run consistently above 75 degrees Celsius, add heat sinks or a small fan. Enclosed builds trap heat faster than you expect. A sealed wooden frame with no airflow is a slow cooker.

For SD card longevity on a 24/7 build, setting up zram eliminates one of the most common sources of write-related wear. Five minutes of setup, meaningful long-term benefit. See Setting Up zram on Raspberry Pi.

Use Ethernet over Wi-Fi if your wall placement allows it. Wi-Fi works, but wired is one fewer thing that can cause random module failures or blank weather displays.

Troubleshooting

Black screen after config change

Almost always a config.js syntax error. Run the config checker, fix the last thing you changed, and restart:

cd ~/MagicMirror && npm run config:check
pm2 restart mm
pm2 logs

Modules not loading

Check whether the module folder name matches exactly what is in config.js, because case matters. Confirm the module has its own dependencies installed if the README says to run npm install in the module folder. Disable the new module first, restart, then re-add it correctly.

HDMI no signal

If the Pi is not detecting the display, add this line to /boot/firmware/config.txt to force HDMI output regardless of whether a display is detected at boot:

hdmi_force_hotplug=1

Also confirm the correct HDMI port. The Pi 4 has two micro HDMI ports and the display needs to be on port 0, which is the port closer to the USB-C power connector.

PM2 shows online but display is blank

PM2 can show the process running even when Electron is not rendering. Check the logs for the actual error:

pm2 logs --lines 50

Maintenance

Update MagicMirror² occasionally to stay compatible with modules and Node changes:

cd ~/MagicMirror
git pull
node --run install-mm
pm2 restart mm

Back up these two files before any update:

cp ~/MagicMirror/config/config.js ~/config.js.backup
cp ~/MagicMirror/css/custom.css ~/custom.css.backup

If you make frequent config changes, keeping those two files in a private GitHub repo means you can roll back in seconds rather than trying to remember what you changed three weeks ago.

FAQ

Can I use a Raspberry Pi 3 for a magic mirror?

Yes, but expect slower performance, longer boot times, and more noticeable lag once you add several modules. The Pi 3B+ is workable for a simple clock, weather, and calendar setup. If you want to add many third-party modules, the Pi 4 is worth the upgrade.

Do I need to know how to code to build a magic mirror?

No. You need to edit config files carefully and follow command-line steps. The config.js syntax is JSON-like and the official documentation has copy-ready examples for every core module. The main skill is patience with troubleshooting, not programming.

What Node.js version does MagicMirror² require?

As of current releases, MagicMirror² requires Node.js v22 or higher. Node 18, which was commonly recommended in older guides, will fail on current MagicMirror versions with a clear engine version error. Always check the MagicMirror² GitHub releases page for the current minimum requirement before installing.

What happens if power goes out?

The Pi reboots and PM2 starts MagicMirror automatically. This is exactly what PM2 is for. Once configured correctly you should never need to manually restart the mirror after a power interruption.

Is it safe to run a Raspberry Pi magic mirror 24/7?

Yes, if you manage heat and use a proper power supply. The Pi 4 is designed for continuous operation. The things that wear out over time are the SD card from constant writes and the monitor backlight. A PIR sensor that turns the display off when the room is empty dramatically extends monitor life for a 24/7 build.

How do I stop MagicMirror from showing a black screen after a reboot?

Confirm PM2 is configured to start at boot by running pm2 startup and executing the command it prints. Also add hdmi_force_hotplug=1 to /boot/firmware/config.txt so the Pi outputs HDMI signal even if the display is slow to initialize on boot.

Final Notes

The mirrors that stay on the wall and keep working are the boring ones. Simple module list, clean config, proper power supply, and airflow. The ones that get rebuilt every few weeks are the ones that tried to do too much too fast. Get the basics stable first. Add features when you are bored of how reliable it is.

References

Was this helpful?

Yes
No
Thanks for your feedback!