# note.com Hashtag Scraper: Articles & Creators (`reventadata/note-scraper`) Actor

Scrape note.com hashtag pages into rows: article title, URL, price, paywall flag, likes, comments, publish date and creator (name, urlname, X handle, custom domain). Optional details add body text, categories, follower counts and public links. Japan residential proxy built in. Unofficial.

- **URL**: https://apify.com/reventadata/note-scraper.md
- **Developed by:** [reventadata](https://apify.com/reventadata) (community)
- **Categories:** Social media, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## note.com Hashtag Scraper: Articles & Creators

> **Unofficial.** This Actor is not affiliated with, authorised by, endorsed by, or in any
> way officially connected to note.com or note株式会社. "note" is a trademark of its
> respective owner and is used here only to describe what this tool reads. It reads the same
> public pages a logged-out browser does.

Reads note.com (Japan's creator and blog platform) by hashtag and returns one row per
article: title, URL, publication time, price in JPY, free/paid/membership flags, likes,
comments, header image, and the creator's handle, name and X account. With `includeDetails`
on, it also opens each article page for the readable text (the whole article when free,
the part above the paywall when paid), the paywalled character count, categories, and the
creator's public profile: followers, following, note count, bio, external links (YouTube,
Instagram, Facebook, LINE, TikTok...), and the URLs the creator wrote in the bio or article.

### What does it do?

1. Opens `https://note.com/tag/<hashtag>` (the popular list) and, with `mode` `both` or
   `new`, `https://note.com/tag/<hashtag>?mode=new` (the newest list).
2. Parses the articles the page embeds: 20 on tags served as a search list, about 40-50
   (37-50 measured) on large tags served as a timeline list. There is no further page on the site without its
   JSON API, which note.com's `robots.txt` closes to everyone but three search engines, so
   this Actor never calls it. To reach past one page, `expandRelatedTags` also reads up to
   10 related hashtags the tag page lists (e.g. `AI` lists `AGI`, `AI Agent`, `AI Act`...).
3. Applies your filters (`keywords`, `excludeKeywords`, `freeOnly`, `minLikes`,
   `publishedAfter`), optionally fetches the article page, and pushes the row.

### Why use it?

- **Robots-clean by design:** two URL shapes, both outside the site's `Disallow` list;
  no API, no search endpoint, no login, no cookies.
- **Creator data from the page itself:** follower counts, bios and links come from the
  article page's own embedded profile object, not from a search-engine snippet.
- **Prices as the page states them:** `price` in JPY, `canRead`, `hasSubscription` and
  `paywalledChars` are the page's own values. `isFree` is the page's flag on the search list and
  `price == 0` with no membership gate on the timeline list; `isPaywalled` is `not canRead`.
- **Public data only:** creator names, bios, follower counts, social handles and the URLs
  a creator publishes are in the rows; nothing from behind a login.

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `hashtags` | array | required | Hashtags as written on note.com (`AI`, `#日記`) or tag URLs (`https://note.com/tag/ChatGPT`). |
| `mode` | string | `both` | `popular`, `new`, or `both` (two pages per tag, duplicates removed). |
| `includeDetails` | boolean | `false` | Fetch each article page for text, paywall count, categories and the creator profile. One request per article. |
| `expandRelatedTags` | integer | `0` | Also read this many related hashtags (0-10) from each seed tag page. |
| `maxItems` | integer | `200` | Stop after this many rows. |
| `keywords` | array | `[]` | Keep an article when any term appears in its title (and, with details, text, description or bio). Case- and width-insensitive substrings (`ＡＩ` matches `AI`; kana voicing marks are kept, so `バル` does not match `ハル`). |
| `excludeKeywords` | array | `[]` | Drop an article when any term appears in the same fields. |
| `freeOnly` | boolean | `false` | Keep only articles the page marks free (no price, no membership gate). |
| `minLikes` | integer | unset | Keep only articles with at least this many likes. |
| `publishedAfter` | string | unset | `YYYY-MM-DD` (Japan time) or an ISO timestamp. |
| `proxyConfiguration` | object | Apify residential, JP | The measured transport. Without a proxy or on datacenter exits the site often answers a listing shell with no articles, which the Actor retries until the run clock runs low. |

#### Sample input

```json
{
    "hashtags": ["AI"],
    "mode": "both",
    "includeDetails": true,
    "maxItems": 10
}
```

### Output

One row per article. Fields marked (details) are `null` or empty unless `includeDetails` is on.

| Field | Type | Description |
|---|---|---|
| `id`, `key` | integer, string | note.com article id and key (`n...` in the URL). |
| `title`, `url` | string | Title and `https://note.com/<creator>/n/<key>`. |
| `tag`, `listMode` | string | The hashtag page and list (`popular` / `new`) the article was found on. |
| `publishedAt` | string | ISO 8601 with the page's Japan offset, e.g. `2026-10-13T06:59:35.000+09:00`. |
| `price`, `currency` | integer, string | Single-purchase price in JPY (0 when none) and `JPY`. |
| `isFree` | boolean | The page's free flag: no price and no membership gate. |
| `hasSubscription` | boolean | Sold through a membership or subscription. |
| `oneshotLowestPrice` | integer / null | Lowest single-purchase price when the search list gives one. |
| `isPaywalled`, `canRead` | boolean / null | Whether a logged-out visitor can read the whole article, as the page flags it. |
| `likeCount`, `commentCount`, `imageCount` | integer / null | The page's counts (the timeline list carries likes only). |
| `eyecatch`, `format` | string / null | Header image URL; note.com editor format version. |
| `creatorUrlname`, `creatorName`, `creatorUrl`, `creatorImage` | string | Creator handle, display name, `https://note.com/<handle>`, profile image. |
| `creatorTwitter` | string / null | X (Twitter) handle linked on the profile. |
| `creatorCustomDomain` | string / null | Host of the custom domain the creator publishes on (e.g. `note.kidzania.jp`), when the page gives one. |
| `description` (details) | string / null | Article description (empty on every page read so far). |
| `bodyHtml`, `bodyText`, `bodyChars` (details) | string, string, integer | The readable part of the article as HTML, as text, and its length. |
| `paywalledChars` (details) | integer | Characters behind the paywall as the page counts them (0 when free). |
| `categories` (details) | array | Category names, e.g. `["テクノロジー", "IT"]`. |
| `hashtags` (details) | array | Hashtags the article page lists, e.g. `["#COMEMO", "#日経"]`; empty on pages that list none. |
| `anonymousLikeCount` (details) | integer / null | Likes from visitors without an account. |
| `creatorFollowers`, `creatorFollowing`, `creatorNoteCount` (details) | integer / null | The creator's counts. |
| `creatorProfile` (details) | string / null | Bio text. |
| `creatorExternalLinks` (details) | array | External profile links (YouTube, Instagram, Facebook, LINE, TikTok...). |
| `creatorSocials` (details) | object | Linked handles by platform, e.g. `{"twitter": "goto_finance"}`. |
| `creatorCreatedAt` (details) | string / null | Account creation time. |
| `contactUrls` (details) | array | URLs the creator wrote in the bio or the readable article text. |
| `detailsStatus` | string | `ok`, `skipped` (details off), `redirect` (article served from a custom domain or removed: listing fields only), `failed`. |
| `matchedKeywords` | array | Which input `keywords` matched. |
| `scrapedAt` | string | ISO 8601 UTC timestamp of the scrape. |

#### Sample output

```json
{
    "id": 180134013,
    "key": "n855f02e7507c",
    "title": "【EM367】AI企業がまさかの手のひら返し！政治まで動かす「AI減速論」、これはAIバブル崩壊の始まりなのか？",
    "url": "https://note.com/eminyurumazu/n/n855f02e7507c",
    "tag": "AI",
    "listMode": "popular",
    "publishedAt": "2026-09-14T07:39:05.000+09:00",
    "price": 0,
    "currency": "JPY",
    "isFree": false,
    "hasSubscription": true,
    "isPaywalled": true,
    "canRead": false,
    "likeCount": 545,
    "commentCount": 10,
    "imageCount": 15,
    "eyecatch": "https://assets.st-note.com/production/uploads/images/313451721/rectangle_large_type_2_04ee56f43a968477b79e889d1a927021.jpeg?fit=bounds&quality=85&width=1280",
    "format": "4.1",
    "creatorUrlname": "eminyurumazu",
    "creatorName": "エミン ユルマズ",
    "creatorUrl": "https://note.com/eminyurumazu",
    "creatorImage": "https://assets.st-note.com/production/uploads/images/93053872/profile_3941332640c9867e552957a34afc4328.jpg?fit=bounds&format=jpeg&quality=85&width=330",
    "creatorTwitter": "yurumazu_note",
    "bodyHtml": "<table-of-contents name=\"3ba9078b-3d29-4b49-bfc0-771c1c0d06dd\" id=\"3ba9078b-3d29-4b49-bfc0-771c1c0d06dd\"><br></table-of-contents>",
    "bodyChars": 0,
    "paywalledChars": 5327,
    "anonymousLikeCount": 18,
    "creatorFollowers": 31747,
    "creatorFollowing": 5,
    "creatorNoteCount": 762,
    "creatorProfile": "トルコ・イスタンブール出身。日本に留学し東京大学理科一類に合格、その後同大学院にて生命工学修士を取得。2006年野村證券に入社し、M&Aアドバイザリー業務に携わる。2024年レディーバードキャピタルを設立。https://www.eminyurumazu.com/",
    "creatorSocials": {
        "twitter": "yurumazu_note"
    },
    "creatorCreatedAt": "2022-08-07T16:06:45.000+09:00",
    "contactUrls": [
        "https://www.eminyurumazu.com/"
    ],
    "detailsStatus": "ok",
    "scrapedAt": "2026-10-22T08:48:31.595398+00:00"
}
```

### Limits, measured on 2026-10-22

- **One page per tag and list.** A tag page embeds 20 articles (search list) or about 40-50
  (37-50 measured; timeline list, large tags). The site pages further only through `/api/v3/searches`,
  which its `robots.txt` disallows, so the Actor stops at the page. `mode: both` and
  `expandRelatedTags` are the two ways to get more rows per run.
- **Keyword search is not offered.** `/search` is disallowed by `robots.txt`; a hashtag is
  the unit. `keywords` filters the rows the tag pages return.
- **Per-article hashtags come with `includeDetails` only.** The listing carries none; the
  article page lists them for some articles and none for others. The row always carries the
  tag it was found under.
- **Custom-domain creators:** their article URL on note.com answers a redirect to the
  custom domain; the row keeps the listing fields and `detailsStatus` is `redirect`.
- **No emails are extracted.** On 72 article pages read while building, no creator wrote
  an email address in a bio or in the readable text. The row carries the URLs, X handle
  and external links a creator publishes.
- **Listing shell.** The site sometimes answers a tag page without its article list; the
  Actor detects it by parsing (0 articles on a tag page) and retries on a fresh exit. On the
  default Japan residential proxy 25 of 25 probe pages came back whole.
- Comments, magazine contents, follower lists and anything behind a login are not read.

### Cost

Pay per result. With `includeDetails` off, one request per tag page (20-50 rows); on,
one more request per row. Pages go through Apify residential proxy, billed on
compressed transfer (about 40 KB per tag page, 30-40 KB per article page, measured 2026-10-22).

# Actor input Schema

## `hashtags` (type: `array`):

Hashtags to read, one per line, as written on note.com: `AI`, `#日記`, or a tag URL such as `https://note.com/tag/ChatGPT`. Each tag page lists 20 (search list) or about 40-50 (timeline list) articles; `mode` adds the newest list.

## `mode` (type: `string`):

Which tag list to read: `popular` (the tag page as it opens), `new` (`?mode=new`, newest first), or `both` (two pages per tag, duplicates removed).

## `includeDetails` (type: `boolean`):

One extra request per article: the readable text and HTML (the whole article when free, the part above the paywall when paid), paywalled character count, categories, and the creator's profile fields (followers, following, note count, bio, X handle, external links and URLs written in the bio or article).

## `expandRelatedTags` (type: `integer`):

How many of the related keywords each seed tag's page (popular and, with `mode: both`, newest) lists (up to 10) are also read, to get past the 20-47 articles one tag page shows. 0 reads only the tags given.

## `maxItems` (type: `integer`):

Stop after this many rows.

## `keywords` (type: `array`):

Case- and accent-insensitive substrings; an article is kept when any one appears in its title (or, with article pages fetched, in its text, description or the creator's bio). Empty keeps everything.

## `excludeKeywords` (type: `array`):

An article is dropped when any of these appears in the same fields.

## `freeOnly` (type: `boolean`):

Keep only articles the page marks free (no price and no membership gate).

## `minLikes` (type: `integer`):

Keep only articles with at least this many likes (the page's own count). Leave empty for no floor.

## `publishedAfter` (type: `string`):

A date, `YYYY-MM-DD` (read as Japan time), or an ISO timestamp. Articles published before it are dropped.

## `proxyConfiguration` (type: `object`):

Measured transport: Apify residential proxy, Japan (25/25 full pages). Without a proxy or on datacenter exits the site often answers a listing shell with no articles, which the Actor retries.

## Actor input object example

```json
{
  "hashtags": [
    "AI"
  ],
  "mode": "both",
  "includeDetails": true,
  "expandRelatedTags": 0,
  "maxItems": 10,
  "keywords": [],
  "excludeKeywords": [],
  "freeOnly": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "JP"
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Items scraped from the target website.

# 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 = {
    "hashtags": [
        "AI"
    ],
    "includeDetails": true,
    "expandRelatedTags": 0,
    "maxItems": 10,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "JP"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("reventadata/note-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 = {
    "hashtags": ["AI"],
    "includeDetails": True,
    "expandRelatedTags": 0,
    "maxItems": 10,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "JP",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("reventadata/note-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 '{
  "hashtags": [
    "AI"
  ],
  "includeDetails": true,
  "expandRelatedTags": 0,
  "maxItems": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "JP"
  }
}' |
apify call reventadata/note-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,reventadata/note-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/d9bRAFcHHbsEnrztL/builds/xgg0BdhTDaFVtqTef/openapi.json
