N8N Email when block is found - How To Guide

Learn More - Play More - Use Umbrel - Get Notified of your miner discovering a new block!

I know it’s a ton of fun to check, but once the newness wares off, you might want to wake up to an email that spells out your new fortune. :slight_smile:

Step-by-Step Guide: Monitor a Bitcoin Wallet for Block Rewards with n8n

Overview

This guide will walk you through creating an n8n workflow to monitor a Bitcoin wallet address for a block reward, such as when solo mining with a setup like Public Pool on Umbrel. The workflow will:

  • Periodically check the wallet’s balance using your Umbrel’s Mempool API.
  • Detect if a block is found by checking for a significant balance increase (e.g., 3.125 BTC, the current block reward as of April 2025).
  • Send an email notification when a block is found, including the wallet’s balance in satoshis and BTC.
  • Handle cases where the wallet isn’t empty by tracking balance changes over time (optional section).

Prerequisites

  • Umbrel Setup: You’re running Umbrel with the Mempool app installed (to access wallet data via API).
  • n8n Installed: n8n is installed on your Umbrel (available in the Umbrel App Store).
  • Bitcoin Wallet Address: You have a Bitcoin address to monitor (e.g., bc1q…).
  • Email Account: A Gmail account for sending notifications (you can use another email service if preferred).
  • Basic Familiarity: No prior n8n experience is required, but you should be comfortable navigating a web interface.

Final Workflow Structure

The workflow will have the following nodes:

  • Cron: Triggers the workflow periodically.
  • HTTP Request: Fetches the wallet balance from Mempool.
  • If: Checks for a significant balance increase.
  • Gmail: Sends an email if a block is found.

For users with a non-empty wallet, we’ll add optional nodes to track the balance over time using a file-based approach.


Step 1: Set Up n8n on Umbrel

If you haven’t already installed n8n on your Umbrel, let’s do that first.

  1. Access Umbrel:
  1. Install n8n:
  • Go to the App Store in the Umbrel dashboard.
  • Search for “n8n” and click Install.
  • Wait for the installation to complete (this may take a few minutes).
  1. Open n8n:
  • Once installed, click Open on the n8n app in Umbrel, or go to http://umbrel.local/app/n8n.
  • You should see the n8n interface with a blank canvas and a “+” button to create a new workflow.

Step 2: Create a New Workflow

Let’s start building the workflow from scratch.

  1. Create a New Workflow:
  • In the n8n interface, click the “+” button in the top-right corner to create a new workflow.
  • You’ll see a blank canvas with a default “Start” node. We’ll replace this with a Cron node.

Step 3: Add a Cron Node to Schedule the Workflow

Purpose: The Cron node will trigger the workflow to run automatically at a set interval (e.g., every 6 hours). Since solo mining a block is rare, we don’t need to check too frequently.

  1. Add the Cron Node:
  • Click the “+” button on the canvas.
  • In the search bar, type “Cron” and select the Cron node.
  • Disconnect the default “Start” node by clicking the line connecting it to the canvas and pressing Delete.
  1. Configure the Cron Node:
  • Click on the Cron node to open its settings (on the left panel).
  • Name: Type “Check Schedule” (this is optional but helps with readability).
  • Trigger Mode: Select “Every Time Unit”.
  • Unit: Select “Minutes”.
  • Every: Type 360 (this runs the workflow every 6 hours; you can adjust this later to 30 minutes for testing, or 1440 for every 24 hours).
  • Leave other settings as default.
  1. Test the Node:
  • Click Test step (the play icon in the settings panel).
  • You should see a confirmation that the node executed successfully, with no output data (it just triggers the next node).
  1. Save: Click outside the settings panel to save.

Step 4: Add an HTTP Request Node to Fetch the Wallet Balance

Purpose: This node will query your Umbrel’s Mempool API to get the current balance of your Bitcoin wallet address.

  1. Add the HTTP Request Node:
  • Click the “+” button on the output of the “Check Schedule” node (the small circle on its right).
  • Search for “HTTP Request” and add the HTTP Request node.
  1. Configure the HTTP Request Node:
  • Name: Type “Check Balance”.
  • Request Method: Select “GET”.
  • URL: Enter the Mempool API endpoint for your wallet address:

http://umbrel.local:3006/api/address/YOUR_BTC_ADDRESS

* Replace YOUR_BTC_ADDRESS with your Bitcoin wallet address (e.g., bc1q...).
* If umbrel.local doesn’t work, use your Umbrel’s IP address (e.g., http://192.168.x.x:3006/api/address/YOUR_BTC_ADDRESS).
  • Response Format: Select “JSON” (n8n will automatically parse the response).
  • Leave other settings as default.
  1. Test the Node:
  • Click Test step.
  • The output should be a JSON object with details about your wallet address, like:
`[
  {
    "address": "YOUR_BTC_ADDRESS",
    "chain_stats": {
      "funded_txo_count": 0,
      "funded_txo_sum": 0,  // Total satoshis received (your wallet balance)
      "spent_txo_count": 0,
      "spent_txo_sum": 0,
      "tx_count": 0
    },
    "mempool_stats": {
      "funded_txo_count": 0,
      "funded_txo_sum": 0,
      "spent_txo_count": 0,
      "spent_txo_sum": 0,
      "tx_count": 0
    },
    "electrum": true
  }
]`
  • Note: If your wallet isn’t empty, funded_txo_sum will be greater than 0 (e.g., 1000000 for 1,000,000 satoshis). We’ll handle this case later.
  1. Save: Click outside to save.

Step 5: Add an If Node to Check for a Block Reward

Purpose: This node will check if the wallet balance has increased significantly, indicating a block reward. For simplicity, we’ll assume an empty wallet (balance starts at 0) and check if the balance becomes greater than 0. We’ll add a section later for non-empty wallets.

  1. Add the If Node:
  • Click the “+” button on the output of the “Check Balance” node.
  • Search for “If” and add the If node.
  1. Configure the If Node:
  • Name: Type “Check for Block”.
  • Condition:
    • Value 1: {{ $node[“Check Balance”].json[“chain_stats”][“funded_txo_sum”] }}
      • This gets the current balance (in satoshis) from the HTTP Request node.
    • Operation: Greater Than
    • Value 2: 0
      • If the balance is greater than 0, it means a block was found (for an empty wallet).
  • Leave other settings as default.
  1. Test the Node:
  • Click Test step.
  • If your wallet balance is 0 (funded_txo_sum: 0), the node will output to the “False” branch.
  • If your wallet balance is greater than 0, it will output to the “True” branch (we’ll handle this case in the optional section).
  1. Save: Click outside to save.

Step 6: Add a Gmail Node to Send a Notification (True Side – Block Found)

Purpose: This node will send an email if the balance is greater than 0, indicating a block was found.

  1. Add the Gmail Node:
  • Click the “+” button on the “True” output of the “Check for Block” node (the green circle).
  • Search for “Gmail” and add the Gmail node.
  1. Configure the Gmail Node:
  • Name: “Email Block Found”
  • Credentials:
    • Click “Add Gmail Credential”.
    • Authentication Method: Select “OAuth2” (recommended for Gmail).
    • Click “Sign in with Google” and follow the prompts to log into your Google account and allow n8n to send emails.
    • Name the credential (e.g., “Gmail”) and click “Create”.
  • Resource: Select “Message”.
  • Operation: Select “Send”.
  • From Email: Enter your Gmail address (e.g., your.email@gmail.com).
  • To Email: Enter the email address where you want to receive the notification (e.g., your.email@gmail.com).
  • Subject: Block Found! 3.125 BTC Received
  • Message:


`A block was found! Your wallet balance is now {{ $node["Check Balance"].json["chain_stats"]["funded_txo_sum"] }} satoshis ({{ ($node["Check Balance"].json["chain_stats"]["funded_txo_sum"] / 100000000).toFixed(8) }} BTC).`
* This includes the wallet balance in both satoshis and BTC (converted by dividing by 100,000,000).
  1. Test the Node:
  • To test this, temporarily modify the “Check for Block” node’s condition to >= 0 (so it triggers the “True” branch even with a 0 balance).
  • Click Execute Workflow (the play button at the bottom-right).
  • Check your email—you should receive a message like:

A block was found! Your wallet balance is now 0 satoshis (0.00000000 BTC).

  • Revert the condition back to > 0.
  1. Save: Click outside to save.

Step 7: Save and Activate the Workflow

  1. Save the Workflow:
  • Click Save in the top-right corner.
  • Name it “Simple Block Checker”.
  1. Activate the Workflow:
  • Toggle the “Active” switch in the top-right corner to “On”.
  • The workflow will now run every 6 hours (or whatever interval you set).

Final Workflow Map (Empty Wallet)

Here’s the simplified workflow for an empty wallet:



`Cron ("Check Schedule")
  ↓
HTTP Request ("Check Balance")
  ↓
If ("Check for Block")
  ↓ (True)
Gmail ("Email Block Found")`
  • No “False” Side Email: Since the balance will be 0 until you hit a block, we don’t need to email you every time it’s 0.
  • No Balance Tracking: We’re not saving or comparing the balance, keeping it simple.

What to Expect (Empty Wallet)

  • Behavior:
    • The workflow will check your wallet balance every 6 hours (or your chosen interval).
    • If the balance is 0, nothing happens (no email).
    • If the balance becomes greater than 0 (e.g., you mine a block and get 3.125 BTC), you’ll get a “Block Found!” email with the wallet balance.
  • Current State:
    • If your wallet balance is 0, you won’t get any emails until you hit a block.
  • When You Hit a Block:
    • The balance will jump to ~312,500,000 satoshis, and you’ll get an email like:

A block was found! Your wallet balance is now 312500000 satoshis (3.12500000 BTC).


Optional: Handling a Non-Empty Wallet

If your wallet isn’t empty (i.e., funded_txo_sum is greater than 0 to start with), the simple workflow above will send an email immediately because the balance is already greater than 0. To handle this case, we need to track the balance over time and only send an email if the balance increases by a significant amount (e.g., 3.125 BTC, indicating a block reward). We’ll add nodes to save the previous balance to a file and compare it with the current balance.

Step 8: Add a Read Binary File Node to Load the Previous Balance

Purpose: This node will read the previous balance from a file at the start of the workflow, so we can compare it with the current balance.

  1. Add the Node:
  • Click the “+” button between the “Check Schedule” node and the “Check Balance” node (insert it between them).
  • Search for “Read Binary File” and add the Read Binary File node.
  1. Configure the Node:
  • Name: “Read Previous Balance”
  • File Path: /home/node/previous_balance.txt
    • This path should be writable in the n8n container on Umbrel. If it doesn’t work, try /tmp/previous_balance.txt or see the troubleshooting section.
  • Options:
    • Fail on Error: No (if the file doesn’t exist yet, we’ll handle it in the next step).
  1. Test the Node:
  • Click Test step.
  • On the first run, the file won’t exist, so the node will fail or return nothing (we’ll handle this in the next step).
  1. Save: Click outside to save.

Step 9: Add a Set Node to Store the Current and Previous Balances

Purpose: This node will store the current balance and the previous balance (from the file) for comparison.

  1. Add the Node:
  • Click the “+” button between the “Check Balance” node and the “Check for Block” node (insert it between them).
  • Search for “Set” and add the Set node.
  1. Configure the Node:
  • Name: “Store Balances”
  • Fields to Set:
    • Name: current_balance
      • Type: Number
      • Value: {{ $node[“Check Balance”].json[“chain_stats”][“funded_txo_sum”] }}
        • This gets the current balance from the HTTP Request node.
    • Name: previous_balance
      • Type: Number
      • Value: {{ Number($node[“Read Previous Balance”].binary.data ?? 0) }}
        • This gets the previous balance from the file, defaulting to 0 if the file doesn’t exist (first run).
  • Include Other Input Fields: Yes (to pass through all data for later nodes).
  1. Test the Node:
  • Click Test step.
  • The output should be something like:

`[
  {
    "current_balance": 1000000,  // Example: 1,000,000 satoshis if your wallet isn’t empty
    "previous_balance": 0        // 0 on the first run
  }
]`
  1. Save: Click outside to save.

Step 10: Update the If Node to Check for a Block Reward

Purpose: Instead of checking if the balance is greater than 0, we’ll check if the balance has increased by ~3.125 BTC, indicating a block reward.

  1. Open the “Check for Block” Node:
  • Click on the “Check for Block” node.
  1. Update the Condition:
  • Value 1: {{ $node[“Store Balances”].json[“current_balance”] - $node[“Store Balances”].json[“previous_balance”] }}
    • This calculates the difference between the current and previous balances.
  • Operation: Greater Than or Equal
  • Value 2: 300000000
    • This checks for an increase of ~3.125 BTC (300,000,000 satoshis, with a buffer for fees).
  1. Test the Node:
  • Click Test step.
  • If your wallet balance hasn’t changed, the difference will be 0, and the node will output “False”.
  • If the balance increases by 3.125 BTC or more, it will output “True”.
  1. Save: Click outside to save.

Step 11: Update the Gmail Node to Include Balance Details

Purpose: Update the email to include both the current and previous balances for clarity.

  1. Open the “Email Block Found” Node:
  • Click on the Gmail node connected to the “True” output of “Check for Block”.
  1. Update the Message:
  • Change the Message to:


`A block was found! Your balance increased by {{ $node["Store Balances"].json["current_balance"] - $node["Store Balances"].json["previous_balance"] }} satoshis.
Current wallet balance: {{ $node["Store Balances"].json["current_balance"] }} satoshis ({{ ($node["Store Balances"].json["current_balance"] / 100000000).toFixed(8) }} BTC)
Previous balance: {{ $node["Store Balances"].json["previous_balance"] }} satoshis ({{ ($node["Store Balances"].json["previous_balance"] / 100000000).toFixed(8) }} BTC)`
  1. Test the Node:
  • Temporarily change the “Check for Block” condition to >= 0 to trigger the “True” branch.
  • Click Execute Workflow.
  • Check your email—you should receive a message like:

`A block was found! Your balance increased by 1000000 satoshis.
Current wallet balance: 1000000 satoshis (0.01000000 BTC)
Previous balance: 0 satoshis (0.00000000 BTC)`
  • Revert the condition back to >= 300000000.
  1. Save: Click outside to save.

Step 12: Add a Write Binary File Node to Save the Current Balance

Purpose: This node will save the current balance to a file, so we can compare it in the next run.

  1. Add the Node:
  • Click the “+” button on the output of the “Store Balances” node (create a parallel path to the “Check for Block” node).
  • Search for “Write Binary File” and add the Write Binary File node.
  1. Configure the Node:
  • Name: “Save Current Balance”
  • File Path: /home/node/previous_balance.txt
    • This should match the path used in the “Read Previous Balance” node.
  • Data: {{ $node[“Store Balances”].json[“current_balance”] }}
    • This writes the current balance to the file.
  • Options:
    • Overwrite: Yes (ensures the file is updated each time).
  1. Test the Node:
  • Click Test step.
  • If successful, it will write the current balance (e.g., 1,000,000 satoshis) to /home/node/previous_balance.txt.
  • If you get a permission error, see the troubleshooting section below.
  1. Save: Click outside to save.

Updated Workflow Map (Non-Empty Wallet)

Here’s the updated workflow for a non-empty wallet:

`Cron (“Check Schedule”)

Read Binary File (“Read Previous Balance”)

HTTP Request (“Check Balance”)

Set (“Store Balances”)

If (“Check for Block”)
↓ (True)
Gmail (“Email Block Found”)

(Parallel path from “Store Balances”):
Set (“Store Balances”)

Write Binary File (“Save Current Balance”)`


What to Expect (Non-Empty Wallet)

  • Behavior:
    • The workflow will check your wallet balance every 6 hours.
    • If the balance increases by 3.125 BTC or more (e.g., from 1,000,000 to 313,500,000 satoshis), you’ll get a “Block Found!” email.
    • The current balance will be saved to a file for the next run.
  • Current State:
    • If your wallet balance doesn’t change, you won’t get any emails.
  • When You Hit a Block:
    • The balance will increase significantly, and you’ll get an email like:

A block was found! Your balance increased by 312500000 satoshis. Current wallet balance: 313500000 satoshis (3.13500000 BTC) Previous balance: 1000000 satoshis (0.01000000 BTC)


Troubleshooting

1. Mempool API URL Not Working

2. File Permission Errors

  • If you get a permission error when writing to /home/node/previous_balance.txt:
    • Try a different path, like /tmp/previous_balance.txt.
    • Or SSH into your Umbrel and create a writable directory:

ssh umbrel@umbrel.local mkdir -p /home/umbrel/n8n-data

* Update the file path in both the "Read Previous Balance" and "Save Current Balance" nodes to /home/umbrel/n8n-data/previous_balance.txt.

3. No Emails Received

  • Double-check your Gmail credentials in n8n.
  • Ensure your Google account allows n8n to send emails (OAuth2 should handle this, but check your Google account security settings).
  • Check your spam/junk folder.

4. Testing the Workflow

  • To simulate a block reward, temporarily modify the “Store Balances” node’s current_balance value to a large number (e.g., 312500000 for 3.125 BTC), then run the workflow. Revert the value afterward.

Additional Customizations

1. Adjust the Check Frequency

  • If 6 hours is too infrequent, open the “Check Schedule” node and change “Every 360” minutes to “Every 30” minutes (for testing) or “Every 1440” minutes (every 24 hours).

2. Add a “No Block Found” Email

  • If you want an email even when no block is found:
    • Add a Gmail node to the “False” output of the “Check for Block” node.
    • Configure it with a subject like “No Block Found” and a message like:

`No block found. Current wallet balance: {{ $node["Store Balances"].json["current_balance"] }} satoshis ({{ ($node["Store Balances"].json["current_balance"] / 100000000).toFixed(8) }} BTC)`

3. Log Balances to a File

  • To keep a log of all balance checks:
    • Add a Write Binary File node after “Store Balances” (in a parallel path).
    • File Path: /home/node/balance_log.txt
    • Data: {{ new Date().toISOString() }}: Current balance: {{ $node[“Store Balances”].json[“current_balance”] }} satoshis\n
    • Append: Yes (to add to the file instead of overwriting).

Yay!

Hope you enjoy a few more toys to play with and something to get your balance emailed to you on a daily basis - IF you score a block.

P.S.

There are some complexities I didn’t go into here; especially the gmail setup and some of the pingback to your n8n node. If you do act on this and get stuck, you might need the following details. Proceed with caution.

Guide: Exposing a Local n8n Instance via Cloudflare Tunnel for Google OAuth Integration

What We Did

We set up a Cloudflare Tunnel to securely expose a local n8n instance (running on a home server) to the internet, enabling Google OAuth authentication for workflows. The goal was to allow n8n to authenticate with Google services (e.g., Google Sheets) by routing OAuth callbacks through a public domain.

Why We Did It

n8n, running locally on a home server (e.g., http://192.168.1.1:5678), needed to handle Google OAuth callbacks, which require a publicly accessible redirect_uri. Google doesn’t accept local domains (e.g., local-server) for OAuth, so we used Cloudflare Tunnel to create a public domain (e.g., subdomain.example.com) and route traffic to the local n8n instance.

How We Solve It

Here’s a step-by-step guide to the solution:

Prerequisite:

  1. Read this guide without taking action, then start over and implement after understanding the bigger picture.

  2. Follow this guide, and to keep it simple, buy a domain name from Cloudflaire

  3. Install the Cloudflare Tunnel App - Cloudflare Tunnel | Umbrel App Store

  4. Set Up a Cloudflare Tunnel:

  • Log in to Cloudflare and go to Zero Trust > Access > Tunnels.
  • Create a new tunnel (e.g., name it “MyTunnel”).
  • Follow the instructions to install cloudflared on your server and connect the tunnel.
  • Add a public hostname:
    • Subdomain: subdomain (e.g., app)
    • Domain: example.com (your domain)
    • Path: blank
    • Type: HTTP
    • URL: http://local-server:5678 (your local n8n address is likely 192.168.1.1, for example)
  • Save the configuration. The tunnel will now route traffic from https://subdomain.example.com to your local n8n instance.


View from Cloudflare Tunnel Console

  1. Configure n8n to Use the Public Domain:
  • On your server, navigate to the n8n app directory (e.g., ~/umbrel/app-data/n8n if using Umbrel).
  • Edit the docker-compose.yml file:

cp docker-compose.yml docker-composeorig Make a backup first.
vi docker-compose.yml

  • Update the environment variables to set the public domain and protocol:

`- N8N_HOST=subdomain.example.com

cd ~/umbrel/app-data/n8n docker-compose down docker-compose up -d

  1. Set Up Google OAuth in the Google Cloud Console:

  1. Test the OAuth Flow in n8n:
  • In n8n, go to Credentials > Google OAuth credential.
  • Enter the Client ID and Client Secret from the Google Cloud Console.
  • Click “Connect” and sign in with Google.
  • After authentication, Google should redirect to the redirect_uri, and n8n should complete the OAuth flow.
  1. Create a Workflow Using the Google Credential:
  • In n8n, create a new workflow.
  • Add a node that uses Google services (e.g., Google Sheets node).
  • Configure the node with your Google OAuth credential and test the workflow (e.g., read data from a sheet).

Outcome

By using Cloudflare Tunnel, we exposed the local n8n instance (http://local-server:5678) via a public domain (https://subdomain.example.com), allowing Google OAuth to work. Adjusting n8n’s N8N_HOST, N8N_PROTOCOL, and N8N_PORT ensured the redirect_uri matched the public domain, and the tunnel routed OAuth callbacks securely to the local server. The workflow can now interact with Google services using the authenticated credential.