How to Block Distracting Websites on Your Laptop

"What exactly did I do the last 30 minutes?"

I'm sure you've been there, asking that same question, staring blankly into your computer screen.

I've written about how I'm working to minimized distraction. For me, a big component of that is blocking distraction on the device I spend the most time: my laptop.

Here's what I'm looking to do:

  • Automatically block distracting websites, but allow an easy way to temporarily unblock them. Example: I want to block Amazon by default, but sometimes I want to jump on and buy something quickly.
  • I don't want to have to manage a schedule. Creating exceptions to schedules and then remembering to re-enable the schedule never works well.
  • I don't want crappy software that is going to slow down my computer or cause weird networking issues.
  • I want it to be hard, but not impossible, to disable. One or two clicks to disable is too easy.

The Easy Way

For most folks, you'll want to use one of the couple apps out there that do this for you. Here are some that I've tried:

  • RescueTime
  • Focus
  • Freedom
  • Cold Turkey

Focus is the best option I've found. It's a simple and nicely designed app. Check it out!

The Hard Way

If you like tinkering with your system setup, read on.

The pre-built applications always seemed to do strange things to the networking stack on my computer or hog lots of resources (GBs of memory in some cases). This is probably due to how much I customize my computer.

Also, I found that if I disabled my "blocking schedule" it didn't automatically re-enable. I would then find myself down the Twitter rabbit-hole with 20m wasted. That was a big issue for me.

Eventually, I got frustrated and built a solution which works surprisingly well:

  • Maintain a simple file listing every host is distracting.
  • Run a script every time the computer wakes up. I used sleepwatcher for this.
  • The script consumes a list of distracting hosts and adds them to /etc/hosts with a reference to a non-existent server. After trying a couple of tools, a node package hostile worked best.

1. Build a List of Distracting Websites

First, create a simple text file. Back it up on Gist or somewhere where it won't be lost. Version tracking the file allows you to view a history of what websites are distracting over time.

I keep this file in my dotfiles repo. Here's what it looks like:

facebook.com
twitter.com
smile.amazon.com

(yes, that's Amazon Smile since I have a browser extension to redirect me there)

Then you'll want to clean the file, add www variants of each host, and point them to 127.0.0.1:

sed '/^$/d' ./distracting_websites.txt | sed $'s/\(.*\)/127.0.0.1  \1\\n127.0.0.1  www.\1/' > ~/distracting_sites.txt

I put this script in the setup process of my dotfiles for easy ad-hoc execution (you'll want to continually update your distracting_websites.txt as new things distract you).

2. Block all Distracting Websites with a Script

Below is a script that is run every time I wake my computer. Here's what it does:

  • Updates /etc/hosts using hostile and the distracting_sites.txt file
  • Clears system DNS cache
  • Clears Safari cache, which seems to have its own DNS cache. Chrome does not.
# asdf is a node version management tool I use. Your exact execution paths will probably be different
/Users/mike/.asdf/installs/nodejs/12.14.1/bin/node \
  /Users/mike/.asdf/installs/nodejs/12.14.1/.npm/bin/hostile \
  load /Users/mike/distracting_sites.txt

# clear system cache
# https://apple.stackexchange.com/questions/303110/flush-cache-of-dns-on-macos-sierra-high-sierra/303119#303119
sudo killall -HUP mDNSResponder

# clear safari cache
osascript << EOF
tell application "Safari"
    activate
end tell

tell application "System Events"
    tell process "Safari"
        tell menu bar 1 to tell menu bar item "Develop" to tell menu 1 to tell menu item "Empty Caches" to click
    end tell
end tell
EOF

You can test this script by running it with sudo:

sudo /usr/local/sbin/sleepwatcher --verbose --wakeup .wakeup

3. Run Website Blocking Script When your Computer Wakes from Sleep

First, install sleepwatcher:

brew install sleepwatcher

Then, you'll want to find the location of the plist file which starts up sleepwatcher as a daemon process:

$ brew services
Name         Status  User Plist
sleepwatcher started root /Library/LaunchDaemons/homebrew.mxcl.sleepwatcher.plist

You'll want to edit this plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>homebrew.mxcl.sleepwatcher</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/sbin/sleepwatcher</string>
        <string>-V</string>
        <string>-w /Users/mike/.wakeup</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>StandardOutPath</key>
    <string>/usr/local/var/log/sleepwatcher.log</string>
    <key>StandardErrorPath</key>
    <string>/usr/local/var/log/sleepwatcher.log</string>
</dict>
</plist>

Then, you'll want to ensure the process runs as root and the script you created is executable:

chmod + /Users/mike/.wakeup
brew services stop sleepwatcher
sudo brew services start sleepwatcher

And... you're done! Depending on your OS configuration you may need to grant some permissions on first run.

Was this overkill? Definitely. Does it prevent me from wasting any time on distracting websites? Absolutely.