
Mempool Watch
- 135 installs
- 9 repo stars
- Updated July 16, 2026
- aibtcdev/skills
Monitor Bitcoin mempool congestion, fee spikes, and pending transaction patterns to tune broadcasts, RBF strategies, and user-facing confirmation estimates.
About
Operational skill for Bitcoin mempool monitoring. It supports agents and services that must watch pending transactions, fee markets, and congestion signals to optimize broadcast timing, RBF decisions, and user-facing ETA estimates in production BTC workflows.
- Live fee percentile tracking
- Pending tx and congestion alerts
- RBF and broadcast timing guidance
- Mempool API integration patterns
- Ops playbooks for high-fee regimes
Mempool Watch by the numbers
- 135 all-time installs (skills.sh)
- Ranked #144 of 479 Web3 & Blockchain skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/aibtcdev/skills --skill mempool-watchAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 135 |
|---|---|
| repo stars | ★ 9 |
| Last updated | July 16, 2026 |
| Repository | aibtcdev/skills ↗ |
What it does
Monitor Bitcoin mempool congestion, fee spikes, and pending transaction patterns to tune broadcasts, RBF strategies, and user-facing confirmation estimates.
Files
Mempool Watch Skill
Monitor the Bitcoin mempool and track on-chain activity using the mempool.space public API (no authentication required). Works on both mainnet and testnet.
Usage
bun run mempool-watch/mempool-watch.ts <subcommand> [options]Subcommands
tx-status
Check the confirmation status of a Bitcoin transaction.
bun run mempool-watch/mempool-watch.ts tx-status --txid <txid>Options:
--txid(required) — Bitcoin transaction ID to look up
Output:
{
"txid": "abc123...",
"network": "mainnet",
"confirmed": true,
"blockHeight": 880000,
"blockHash": "000000...",
"blockTime": "2026-01-01T00:00:00.000Z",
"confirmations": 42,
"explorerUrl": "https://mempool.space/tx/abc123..."
}If unconfirmed:
{
"txid": "abc123...",
"network": "mainnet",
"confirmed": false,
"blockHeight": null,
"blockHash": null,
"blockTime": null,
"confirmations": 0,
"explorerUrl": "https://mempool.space/tx/abc123..."
}address-history
Retrieve the transaction history for a Bitcoin address.
bun run mempool-watch/mempool-watch.ts address-history --address <addr> [--limit <n>]Options:
--address(required) — Bitcoin address to look up--limit(optional) — Maximum number of transactions to return (default: 10, max: 25)
Output:
{
"address": "bc1q...",
"network": "mainnet",
"count": 3,
"transactions": [
{
"txid": "abc123...",
"confirmed": true,
"blockHeight": 880000,
"blockTime": "2026-01-01T00:00:00.000Z",
"fee": 1200,
"valueIn": 500000,
"valueOut": 498800,
"explorerUrl": "https://mempool.space/tx/abc123..."
}
],
"explorerUrl": "https://mempool.space/address/bc1q..."
}mempool-stats
Get current Bitcoin mempool statistics including pending transaction count, backlog size, and fee histogram.
bun run mempool-watch/mempool-watch.ts mempool-statsOutput:
{
"network": "mainnet",
"pendingTransactions": 12400,
"pendingVsize": 8500000,
"totalFees": 120000000,
"recommendedFees": {
"fast": { "satPerVb": 15, "target": "~10 minutes (next block)" },
"medium": { "satPerVb": 8, "target": "~30 minutes" },
"slow": { "satPerVb": 3, "target": "~1 hour" },
"economy": { "satPerVb": 1, "target": "~24 hours" }
},
"feeHistogram": [[15, 200000], [8, 500000], [3, 1000000]]
}Notes
- All subcommands use the public mempool.space API — no authentication or wallet required
- Defaults to testnet unless
NETWORK=mainnetis set confirmationsintx-statusis estimated from current block height minus the transaction's block heightaddress-historyreturns the most recent transactions first; mempool.space paginates viaafter_txidwhich is not exposed here — use--limitto control result size
Mempool Watch Agent
Read-only Bitcoin mempool monitoring via mempool.space. No wallet unlock required for any subcommand. Use this skill to confirm transaction status, audit address activity, or assess current network congestion before sending.
Prerequisites
- No wallet required — all subcommands are read-only
NETWORKenv var controls network (defaults to testnet unlessNETWORK=mainnetis set)- Valid Bitcoin txid (64 hex chars) required for
tx-status - Valid Bitcoin address required for
address-history
Decision Logic
| Goal | Subcommand |
|---|---|
| Confirm whether a sent transaction is mined | tx-status --txid <txid> |
| Check how many confirmations a transaction has | tx-status --txid <txid> → read confirmations |
| Audit recent inbound/outbound activity for an address | address-history --address <addr> |
| Assess current mempool backlog before sending BTC | mempool-stats → read recommendedFees and pendingTransactions |
| Decide which fee tier to use for a time-sensitive send | mempool-stats → use recommendedFees.fast.satPerVb for next-block, medium for ~30 min |
Safety Checks
- All subcommands are read-only — no funds or state are modified
- Verify the
--txidis 64 hex characters before callingtx-status(malformed IDs return a 404 error) address-history --limitis capped at 25 to avoid large response payloads; for deeper history use the mempool.space explorer URL in the output- Always confirm
networkin output matches the expected network before acting on results
Error Handling
| Error message | Cause | Fix |
|---|---|---|
"Transaction not found" | txid does not exist on the selected network | Verify txid is correct and matches the network (mainnet vs testnet) |
"Failed to fetch..." with status 404 | Address or txid not found | Check input value and network |
"Failed to fetch..." with status 429 | mempool.space rate limit | Wait a few seconds and retry |
"limit must be between 1 and 25" | --limit out of range | Use a value between 1 and 25 |
Output Handling
tx-status: checkconfirmed(boolean) first; if true, readconfirmationsfor depth. 6+ confirmations is considered final for most use cases.address-history: iteratetransactions[]— each entry hasconfirmed,blockHeight,fee,valueIn,valueOut. UseexplorerUrlper tx for full UTXO breakdown.mempool-stats: readrecommendedFees.fast.satPerVbfor urgent sends;pendingTransactionsabove 50,000 indicates significant backlog and higher fees.
Example Invocations
# Check if a transaction is confirmed
bun run mempool-watch/mempool-watch.ts tx-status --txid 64892b681a7f1fa14dad055c1628252104839591d27a463a6f7b9cabfddf335a
# Get last 5 transactions for an address
bun run mempool-watch/mempool-watch.ts address-history --address bc1q9p6ch73nv4yl2xwhtc6mvqlqrm294hg4zkjyk0 --limit 5
# Check mempool before sending
bun run mempool-watch/mempool-watch.ts mempool-stats#!/usr/bin/env bun
/**
* Mempool Watch skill CLI
* Bitcoin mempool monitoring via mempool.space
*
* Usage: bun run mempool-watch/mempool-watch.ts <subcommand> [options]
*/
import { Command } from "commander";
import { NETWORK } from "../src/lib/config/networks.js";
import {
getMempoolApiUrl,
getMempoolTxUrl,
getMempoolAddressUrl,
} from "../src/lib/services/mempool-api.js";
import { printJson, handleError } from "../src/lib/utils/cli.js";
const MEMPOOL_API = getMempoolApiUrl(NETWORK);
// ---------------------------------------------------------------------------
// Program
// ---------------------------------------------------------------------------
const program = new Command();
program
.name("mempool-watch")
.description(
"Bitcoin mempool monitoring — transaction status, address history, and mempool stats via mempool.space"
)
.version("0.1.0");
// ---------------------------------------------------------------------------
// tx-status
// ---------------------------------------------------------------------------
program
.command("tx-status")
.description(
"Check confirmation status of a Bitcoin transaction. Returns confirmed state, block height, and number of confirmations."
)
.requiredOption("--txid <txid>", "Bitcoin transaction ID (64 hex characters)")
.action(async (opts: { txid: string }) => {
try {
const [statusRes, chainRes] = await Promise.all([
fetch(`${MEMPOOL_API}/tx/${opts.txid}/status`),
fetch(`${MEMPOOL_API}/blocks/tip/height`),
]);
if (!statusRes.ok) {
if (statusRes.status === 404) {
throw new Error(
`Transaction not found: ${opts.txid}. Verify the txid and network (current: ${NETWORK}).`
);
}
throw new Error(
`Failed to fetch tx status: ${statusRes.status} ${statusRes.statusText}`
);
}
const status = await statusRes.json() as {
confirmed: boolean;
block_height?: number;
block_hash?: string;
block_time?: number;
};
const currentHeight = chainRes.ok
? parseInt(await chainRes.text(), 10)
: null;
const confirmations =
status.confirmed && status.block_height != null && currentHeight != null
? currentHeight - status.block_height + 1
: 0;
printJson({
txid: opts.txid,
network: NETWORK,
confirmed: status.confirmed,
blockHeight: status.block_height ?? null,
blockHash: status.block_hash ?? null,
blockTime: status.block_time
? new Date(status.block_time * 1000).toISOString()
: null,
confirmations,
explorerUrl: getMempoolTxUrl(opts.txid, NETWORK),
});
} catch (error) {
handleError(error);
}
});
// ---------------------------------------------------------------------------
// address-history
// ---------------------------------------------------------------------------
program
.command("address-history")
.description(
"Retrieve recent transaction history for a Bitcoin address. Returns the most recent transactions first."
)
.requiredOption("--address <address>", "Bitcoin address to look up")
.option("--limit <number>", "Number of transactions to return (1-25)", "10")
.action(async (opts: { address: string; limit: string }) => {
try {
const limit = parseInt(opts.limit, 10);
if (isNaN(limit) || limit < 1 || limit > 25) {
throw new Error("limit must be between 1 and 25");
}
const res = await fetch(`${MEMPOOL_API}/address/${opts.address}/txs`);
if (!res.ok) {
if (res.status === 400) {
throw new Error(
`Invalid address: ${opts.address}. Check format for ${NETWORK}.`
);
}
throw new Error(
`Failed to fetch address history: ${res.status} ${res.statusText}`
);
}
const txs = await res.json() as Array<{
txid: string;
status: {
confirmed: boolean;
block_height?: number;
block_time?: number;
};
fee: number;
vin: Array<{ prevout?: { value: number } }>;
vout: Array<{ value: number }>;
}>;
const sliced = txs.slice(0, limit);
const transactions = sliced.map((tx) => {
const valueIn = tx.vin.reduce(
(sum, input) => sum + (input.prevout?.value ?? 0),
0
);
const valueOut = tx.vout.reduce((sum, output) => sum + output.value, 0);
return {
txid: tx.txid,
confirmed: tx.status.confirmed,
blockHeight: tx.status.block_height ?? null,
blockTime: tx.status.block_time
? new Date(tx.status.block_time * 1000).toISOString()
: null,
fee: tx.fee,
valueIn,
valueOut,
explorerUrl: getMempoolTxUrl(tx.txid, NETWORK),
};
});
printJson({
address: opts.address,
network: NETWORK,
count: transactions.length,
transactions,
explorerUrl: getMempoolAddressUrl(opts.address, NETWORK),
});
} catch (error) {
handleError(error);
}
});
// ---------------------------------------------------------------------------
// mempool-stats
// ---------------------------------------------------------------------------
program
.command("mempool-stats")
.description(
"Get current Bitcoin mempool statistics: pending transaction count, backlog size, total fees, and recommended fee rates."
)
.action(async () => {
try {
const [mempoolRes, feesRes] = await Promise.all([
fetch(`${MEMPOOL_API}/mempool`),
fetch(`${MEMPOOL_API}/v1/fees/recommended`),
]);
if (!mempoolRes.ok) {
throw new Error(
`Failed to fetch mempool stats: ${mempoolRes.status} ${mempoolRes.statusText}`
);
}
if (!feesRes.ok) {
throw new Error(
`Failed to fetch fee estimates: ${feesRes.status} ${feesRes.statusText}`
);
}
const mempool = await mempoolRes.json() as {
count: number;
vsize: number;
total_fee: number;
fee_histogram: Array<[number, number]>;
};
const fees = await feesRes.json() as {
fastestFee: number;
halfHourFee: number;
hourFee: number;
economyFee: number;
minimumFee: number;
};
printJson({
network: NETWORK,
pendingTransactions: mempool.count,
pendingVsize: mempool.vsize,
totalFees: mempool.total_fee,
recommendedFees: {
fast: {
satPerVb: fees.fastestFee,
target: "~10 minutes (next block)",
},
medium: {
satPerVb: fees.halfHourFee,
target: "~30 minutes",
},
slow: {
satPerVb: fees.hourFee,
target: "~1 hour",
},
economy: {
satPerVb: fees.economyFee,
target: "~24 hours",
},
minimum: {
satPerVb: fees.minimumFee,
target: "minimum relay fee",
},
},
feeHistogram: mempool.fee_histogram,
});
} catch (error) {
handleError(error);
}
});
// ---------------------------------------------------------------------------
// Parse
// ---------------------------------------------------------------------------
program.parse(process.argv);