# Bitcoin Network Scraper: Hashrate, Fees & Mempool (`arman-bd/bitcoin-network-stats-scraper`) Actor

Scrape Bitcoin network statistics: hash rate, difficulty, block count, mempool size, transaction fees, block interval and total value transacted. Network fundamentals.

- **URL**: https://apify.com/arman-bd/bitcoin-network-stats-scraper.md
- **Developed by:** [Arman Hossain](https://apify.com/arman-bd) (community)
- **Categories:** Business, Automation, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.56 / 1,000 snapshot scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Bitcoin Network Scraper: Hashrate, Fees & Mempool

![Bitcoin Network Scraper: Hash rate, difficulty, mempool size, fees and block interval, one network snapshot per run](https://api.apify.com/v2/key-value-stores/ZQOcNAOHrIgTacAmy/records/bitcoin-network-stats-scraper.jpg)

**Agent skill: [SKILL.md](https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/bitcoin-network-stats-scraper.md)**

```
https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/bitcoin-network-stats-scraper.md
```

### What it does

Scrape Bitcoin network statistics: hash rate, difficulty, block count, mempool size, transaction fees, block interval and total value transacted. Network fundamentals. Give it `metrics` and it returns one structured record per snapshot.

Each run is **one snapshot**, a single dataset record capturing the state of the Bitcoin network at that moment. Run it on a schedule and the dataset becomes a time series: hash rate against difficulty, mempool backlog against block interval, fee pressure against price.

It reads three public Blockchain.com endpoints: the network stats aggregate, the live unconfirmed-transaction count, and the fiat ticker used to convert USD values into your reporting currency.

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `metrics` | array | `[]` | Restrict the record to these metric names. `timestamp`, `currency` and `scrapedAt` are always kept. Empty = every metric. An unrecognised name fails the run immediately with the valid list. |
| `includeMempool` | boolean | `true` | Fetch the live unconfirmed-transaction count into `mempoolSize`. One extra request; turn it off for the daily aggregates only. |
| `currency` | string | `"USD"` | Fiat currency for the converted value block. One of the 30 currencies Blockchain.com's ticker quotes. |

Valid `metrics` values: `marketPriceUsd`, `hashRate`, `difficulty`, `totalBtcMined`, `blocksSize`, `minutesBetweenBlocks`, `totalTransactions`, `transactionsPerSecond`, `mempoolSize`, `minerRevenueUsd`, `totalFeesBtc`, `estimatedTransactionVolumeUsd`.

#### Which combinations make sense

- `metrics` **and** `includeMempool: false`: if `mempoolSize` is in `metrics` but the mempool is disabled, the field is present and `null`. Ask for one or the other consistently.
- `metrics` **and** `currency`: asking for a USD metric keeps its fiat twin too, request `marketPriceUsd` and you also get `marketPrice` and `fxRateUsd`. Metrics you did not ask for do not drag their twins along.
- `currency: "USD"` skips the ticker request entirely, `fxRateUsd` is `1` and the fiat fields mirror the USD ones.
- **No input at all** is a valid, complete run: all 19 fields, mempool included, in USD.

#### Example input

```json
{
 "metrics": ["hashRate", "difficulty", "mempoolSize", "marketPriceUsd"],
 "includeMempool": true,
 "currency": "USD"
}
```

### Output

One dataset item per snapshot. A real record, exactly as produced by a live run:

```json
{
 "timestamp": "2026-08-06T11:26:44.000Z", // Blockchain.com's own data timestamp
 "marketPriceUsd": 64565.51, // BTC spot price, USD
 "hashRate": 834575299886.082, // network hash rate in GH/s (÷ 1e9 for EH/s → 834.58 EH/s)
 "difficulty": 126231507121868, // current mining difficulty
 "totalBtcMined": 20066512.5, // BTC in circulation (source reports satoshis)
 "blocksSize": 222048135, // total size of blocks mined in the last 24h, bytes
 "minutesBetweenBlocks": 10.2727, // observed average block interval
 "totalTransactions": 568358, // transactions confirmed in the last 24h
 "transactionsPerSecond": 6.5782, // totalTransactions / 86400
 "mempoolSize": 49569, // unconfirmed transactions waiting right now
 "minerRevenueUsd": 0, // miner revenue over 24h, USD (see quirks below)
 "totalFeesBtc": -415.625, // total fees over 24h, BTC (see quirks below)
 "estimatedTransactionVolumeUsd": 7640022241.04,// estimated 24h on-chain value transacted, USD
 "currency": "EUR", // currency of the converted block below
 "fxRateUsd": 0.86619497, // units of `currency` per 1 USD, from the ticker
 "marketPrice": 55926.32, // marketPriceUsd × fxRateUsd
 "minerRevenue": 0, // minerRevenueUsd × fxRateUsd
 "estimatedTransactionVolume": 6617748831.53, // estimatedTransactionVolumeUsd × fxRateUsd
 "scrapedAt": "2026-08-06T11:32:51.828Z" // when this Actor read it
}
```

Fields ending in `Usd` are **always** USD, whatever `currency` you set. The five-field block from `currency` to `estimatedTransactionVolume` carries the converted view, with the exact rate used so the numbers are auditable.

#### Known source quirks

These are Blockchain.com's numbers, passed through faithfully rather than patched:

- **`totalFeesBtc` can come back negative** (`-415.625` in the sample above, the exact negation of the 24h BTC issuance). The upstream `total_fees_btc` field is occasionally sign-flipped. Take `Math.abs()` if you need a magnitude, but be aware you are working around a source bug.
- **`minerRevenueUsd` is often `0`.** Blockchain.com does not always populate it. Derive revenue from issuance × price if you need it reliably.
- **`totalTransactions` is a 24-hour count, not the all-time total.** Same for `blocksSize` and `estimatedTransactionVolumeUsd`.

#### `RUN_SUMMARY`

Written to the default key-value store at the end of every run:

```json
{
 "snapshotsSaved": 1,
 "sourcesQueried": 3,
 "sourcesFailed": 0,
 "failures": [],
 "blockHeight": 961284,
 "nextRetargetBlock": 961631,
 "filters": { "metrics": [], "includeMempool": true, "currency": "EUR" },
 "finishedAt": "2026-08-06T11:32:51.833Z"
}
```

`blockHeight` and `nextRetargetBlock` are bonus context: the difference tells you how many blocks remain until the next difficulty adjustment. `failures` holds one `{ source, error }` entry per degraded source.

### Use cases

#### 1. Monitor mining economics

Hash rate against difficulty against price is the whole miner-margin picture. Poll hourly and you can see hashprice compress in real time.

```json
{
 "metrics": ["hashRate", "difficulty", "marketPriceUsd", "minutesBetweenBlocks", "totalBtcMined"],
 "includeMempool": false,
 "currency": "USD"
}
```

`RUN_SUMMARY.nextRetargetBlock` minus `blockHeight` tells you how many blocks until difficulty adjusts, the number miners actually watch.

#### 2. Time transactions around fee pressure

Mempool backlog is the leading indicator of what you will pay. A tight, cheap snapshot every few minutes is enough to spot the windows.

```json
{
 "metrics": ["mempoolSize", "minutesBetweenBlocks", "totalTransactions", "transactionsPerSecond"],
 "includeMempool": true
}
```

A rising `mempoolSize` with `minutesBetweenBlocks` above 10 means the backlog is growing faster than blocks are clearing it, wait. Both falling means the window is open.

#### 3. Network-health research

Take everything, in your reporting currency, once a day, and build a longitudinal dataset.

```json
{
 "includeMempool": true,
 "currency": "EUR"
}
```

All 19 fields, converted, with the FX rate stored alongside so the series stays reproducible even as rates move.

### Limits and behaviour

- **Fast.** The stats endpoint answered in 98 ms on probe, the fastest in the whole survey. A full three-source run finishes in well under a second, which makes high-frequency scheduling practical.
- **No published rate limit.** Blockchain.com advertises no rate-limit headers on these endpoints. Polling every few minutes is comfortable; sub-minute polling is not something the Actor is built to pace, and there is no useful new data at that resolution anyway.
- **Graceful degradation.** If the mempool or ticker endpoint fails, the snapshot is still saved, `mempoolSize` is `null`, or values stay in USD with `currency` reported as `"USD"`, and the failure is recorded in `RUN_SUMMARY.failures`. Only a failure of the primary `/stats` endpoint aborts the run, because then there is no snapshot to save.
- **Transient errors are retried.** 429 and 5xx get three attempts with linear backoff (1 s, 2 s). Malformed responses fail fast rather than being retried into the timeout.
- **`?currency=` on the source endpoint does nothing.** Blockchain.com accepts the parameter but returns USD regardless, so this Actor converts explicitly against `blockchain.info/ticker` and shows you the rate. That is why `fxRateUsd` exists.
- **Public data only.** No authentication, no personal data, no access-control bypass.

### FAQ

**Do I need a proxy?** No. Proxy configuration is not required to run this Actor.

**Do I need a Blockchain.com account or API key?** No. You supply no credentials.

**What happens if a source is unavailable?** The mempool and ticker sources degrade gracefully, the snapshot still saves, with the gap noted in `RUN_SUMMARY.failures`. If the core stats endpoint is down after three retries the run errors out, since there would be nothing to record.

**Can I schedule it?** Yes, that is the point. One run = one snapshot; a schedule turns the dataset into a time series.

**What unit is `hashRate` in?** GH/s, as Blockchain.com reports it. Divide by 1e9 for EH/s: `834575299886` GH/s = 834.58 EH/s.

**Why is `totalFeesBtc` negative?** An upstream sign bug in Blockchain.com's `total_fees_btc`. The Actor reports what the API returns rather than silently correcting it, see "Known source quirks" above.

**Can I get historical data?** Not from this Actor, `/stats` is a live snapshot with no history parameter. Schedule it and accumulate your own series; `timestamp` and `scrapedAt` are your time keys.

**Can I get individual transactions or blocks?** No. This Actor covers network-level aggregates only.

**Can I integrate it with something else?** Yes, Apify API, client libraries, webhooks, scheduled runs, dataset exports (JSON/CSV/Excel) or MCP. Output is structured JSON.

### API example

```bash
curl -X POST "https://api.apify.com/v2/acts/arman-bd~bitcoin-network-stats-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
 "metrics": ["hashRate", "difficulty", "mempoolSize"],
 "includeMempool": true
 }'
```

### JavaScript example

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('arman-bd/bitcoin-network-stats-scraper').call({ currency: 'EUR' });

const { items: [snap] } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`${(snap.hashRate / 1e9).toFixed(2)} EH/s · ${snap.mempoolSize} tx queued · €${snap.marketPrice}`);
```

# Actor input Schema

## `metrics` (type: `array`):

Restrict the snapshot to these metrics. 'timestamp' and 'scrapedAt' are always included. Leave empty for every metric.

## `includeMempool` (type: `boolean`):

Fetch the current unconfirmed-transaction count into 'mempoolSize'. This is one extra request; turn it off if you only want the daily network aggregates.

## `currency` (type: `string`):

Fiat currency for the converted value fields ('marketPrice', 'minerRevenue', 'estimatedTransactionVolume'). The USD-suffixed fields always stay in USD. Conversion uses Blockchain.com's own ticker.

## Actor input object example

```json
{
  "metrics": [
    "hashRate",
    "difficulty",
    "mempoolSize"
  ],
  "includeMempool": true,
  "currency": "USD"
}
```

# Actor output Schema

## `items` (type: `string`):

Every record the run produced.

## `runsummary` (type: `string`):

The RUN\_SUMMARY record from the run's key-value store.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("arman-bd/bitcoin-network-stats-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("arman-bd/bitcoin-network-stats-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call arman-bd/bitcoin-network-stats-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,arman-bd/bitcoin-network-stats-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/4ei5E3dwiPfawaVpj/builds/mTSFQYW7f7NCOX7a8/openapi.json
