Skip to content
Back to skills

Notion Clipper Skill

DSecurity

Clip web pages to Notion. Fetches any URL via Chrome CDP, converts HTML to Markdown, then to Notion blocks, and saves to user-specified Notion database or page. Use when user wants to save/clip a webpage to Notion, or mentions "clip to notion", "save page to notion", "网页剪藏到Notion".

  • 14 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 7, 2026
developmentjavascriptjavabashnodeapidatabasesecurity

Works with

  • terminal
  • cli
  • api

Security analysis

D46/100
  • criticalModifies startup scripts or system services for persistence
  • criticalModifies startup scripts or system services for persistence
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 10 files and shows the line behind each finding

Scanned September 7, 2026

npx -y skills add modbender/skill-library-mcp --skill notion-clipper-skill --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Notion Clipper Skill?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Notion Clipper Skill
[![Security: D — Skills Directory](https://www.skillsdirectory.com/api/skills/modbender-notion-clipper-skill/badge)](https://www.skillsdirectory.com/skills/modbender-notion-clipper-skill)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: notion-clipper-skill
description: Clip web pages to Notion. Fetches any URL via Chrome CDP, converts HTML to Markdown, then to Notion blocks, and saves to user-specified Notion database or page. Use when user wants to save/clip a webpage to Notion, or mentions "clip to notion", "save page to notion", "网页剪藏到Notion".
---

# Notion Clipper

Clip any web page to Notion. Uses Chrome CDP for full JavaScript rendering, converts to Markdown, then to Notion blocks.

## Prerequisites

1. **Notion API Key**: Create an integration at https://notion.so/my-integrations
2. **Store the key**:
```bash
mkdir -p ~/.config/notion
echo "ntn_your_key_here" > ~/.config/notion/api_key
```
3. **Share target database/page** with your integration (click "..." → "Connect to" → your integration name)

## First Time Setup

Dependencies are auto-installed when the script runs. No manual setup needed.

## Agent Execution Instructions

**CRITICAL**: Always use the command pattern below. It auto-installs dependencies on first run.

1. Determine this SKILL.md file's directory path as `SKILL_DIR`
2. **Command pattern** (package.json in `scripts/`; always run lazy install first):
```bash
(cd "${SKILL_DIR}/scripts" && (test -d node_modules || npm install) && npx -y tsx main.ts <args>)
```
3. Replace `${SKILL_DIR}` with the actual path (e.g. `/Users/xxx/.claude/skills/notion-clipper-skill`)

## Usage

**IMPORTANT - Use this command pattern for best results:**

```bash
# Recommended: Clear proxy env vars and use tsx runtime
(cd "${SKILL_DIR}/scripts" && (test -d node_modules || npm install) && unset http_proxy https_proxy all_proxy && npx -y tsx main.ts <url> --database-name "Resources")
```

**Why this pattern?**
- `unset http_proxy https_proxy all_proxy` - Avoids ECONNREFUSED from proxy conflicts
- `tsx` runtime - Node.js runtime that properly handles direct connections (bun has proxy issues)
- `(test -d node_modules || npm install)` - Auto-installs dependencies if missing

**If you encounter network issues:**
1. Close any VPN/proxy software
2. Switch to a stable network (mobile hotspot often works)
3. Use the recommended command pattern above

```bash
# Clip to a Notion database by NAME (recommended - searches for database)
(cd "${SKILL_DIR}/scripts" && (test -d node_modules || npm install) && npx -y tsx main.ts <url> --database-name "Resource")

# Clip to a Notion database by ID
(cd "${SKILL_DIR}/scripts" && (test -d node_modules || npm install) && npx -y tsx main.ts <url> --database <database_id>)

# Clip to an existing page (appends blocks)
(cd "${SKILL_DIR}/scripts" && (test -d node_modules || npm install) && npx -y tsx main.ts <url> --page <page_id>)

# List all accessible databases
(cd "${SKILL_DIR}/scripts" && (test -d node_modules || npm install) && npx -y tsx main.ts --list-databases)

# For pages requiring login (wait mode)
(cd "${SKILL_DIR}/scripts" && (test -d node_modules || npm install) && npx -y tsx main.ts <url> --database-name "Resource" --wait)
```

## Options

| Option | Description |
|--------|-------------|
| `<url>` | URL to clip |
| `--database-name, -n <name>` | Target database by name (searches for match) |
| `--database, -d <id>` | Target Notion database by ID |
| `--page, -p <id>` | Target Notion page ID (appends blocks) |
| `--list-databases, -l` | List all accessible databases and exit |
| `--wait, -w` | Wait for user signal before capturing |
| `--timeout, -t <ms>` | Page load timeout (default: 30000) |
| `--no-bookmark` | Don't include bookmark block at top |

## Capture Modes

| Mode | Behavior | Use When |
|------|----------|----------|
| Auto (default) | Capture on network idle | Public pages, static content |
| Wait (`--wait`) | User signals when ready | Login-required, lazy loading, paywalls |

**Wait mode workflow**:
1. Run with `--wait` → Chrome opens, script outputs "Press Enter when ready"
2. Log in or navigate as needed in the browser
3. Press Enter in terminal to trigger capture

## Output Structure

When saving to a **database**, creates a new page with:
- **Name**: Page title
- **URL**: Source URL (if database has URL property)
- **Content**: Bookmark block + converted content blocks

When appending to a **page**, adds:
- Bookmark block (link to source)
- Divider
- Converted content blocks

## Database Setup

For best results, create a Notion database with these properties:
- **Name** (Title) - Required, will contain page title
- **URL** (URL) - Optional, will contain source URL

## Examples

**Clip a tweet to "Resource" database (by name):**
```bash
(cd "${SKILL_DIR}/scripts" && (test -d node_modules || npm install) && unset http_proxy https_proxy all_proxy && npx -y tsx main.ts "https://x.com/dotey/status/123456" -n "Resource")
```

**List all databases first:**
```bash
(cd "${SKILL_DIR}/scripts" && (test -d node_modules || npm install) && unset http_proxy https_proxy all_proxy && npx -y tsx main.ts --list-databases)
```

**Clip article requiring login:**
```bash
(cd "${SKILL_DIR}/scripts" && (test -d node_modules || npm install) && unset http_proxy https_proxy all_proxy && npx -y tsx main.ts "https://medium.com/article" -n "Reading" --wait)
```

**Append to reading notes page:**
```bash
(cd "${SKILL_DIR}/scripts" && (test -d node_modules || npm install) && unset http_proxy https_proxy all_proxy && npx -y tsx main.ts "https://blog.example.com/post" -p xyz789)
```

**Quick alias (add to your ~/.bashrc or ~/.zshrc):**
```bash
alias notion-clip='(cd "${SKILL_DIR}/scripts" && unset http_proxy https_proxy all_proxy && npx -y tsx main.ts)'

# Usage: notion-clip <url> -n "Resources"
```

## How It Works

1. **Fetch**: Launch Chrome via CDP, navigate to URL
2. **Render**: Wait for JavaScript to execute, scroll to trigger lazy loading
3. **Extract**: Run cleanup script to remove ads/nav, extract main content
4. **Convert**: HTML → Markdown → Notion blocks
5. **Save**: Call Notion API to create page or append blocks

## Dependencies

- Chrome/Chromium browser (installed locally)
- Node.js (script runs with `tsx`; Bun may route through proxy and return empty body, use Node)
- Notion API key configured

(Other dependencies auto-install on first run.)

## Environment Variables

| Variable | Description |
|----------|-------------|
| `NOTION_CLIPPER_CHROME_PATH` | Custom Chrome executable path |
| `NOTION_CLIPPER_CHROME_PROFILE_DIR` | Custom Chrome profile directory |
| `https_proxy` / `HTTP_PROXY` | Proxy for Notion API (e.g. `http://127.0.0.1:7890`) |
| `http_proxy` / `HTTPS_PROXY` | Same as above |
| `all_proxy` | Optional, e.g. `socks5://127.0.0.1:7890` |

**Example (proxy on port 7890):**
```bash
export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_proxy=socks5://127.0.0.1:7890
```

## Troubleshooting

### Network Issues

| Error | Cause | Solution |
|--------|---------|-----------|
| `ECONNREFUSED 208.103.161.1:443` | DNS returns blocked IP; proxy conflict | 1. Close VPN/proxy software<br>2. Use `unset http_proxy https_proxy all_proxy`<br>3. Switch network (e.g., mobile hotspot) |
| `Notion API returned empty body (status 200)` | Using `bun` which routes through proxy incorrectly | Run with **tsx**: `npx -y tsx main.ts ...` (NOT `bun`) |
| `fetch failed` or `ECONNREFUSED` | Proxy env vars set but Node.js `https` doesn't support them | Either:<br>1. Use network without proxy (unset env vars)<br>2. Ensure proxy allows HTTPS traffic |
| `CloudFlare 403` | Direct IP access triggers security protection | Use hostname instead of IP; ensure proper `Authorization` header |
| Mixed: Sometimes works, sometimes fails | Unstable network or DNS returns different IPs | Script now has **6 retries with exponential backoff** (1s, 2s, 4s, 4s...) |

**Best Practice**: For reliable Notion API access, use a stable network (mobile hotspot often works better than corporate VPN).

### Content Issues

| Error | Cause | Solution |
|--------|---------|-----------|
| `Invalid URL for link` | Notion API rejects non-http(s) URLs | Script now **removes all markdown links** by default to avoid validation errors. Content is preserved, only links are stripped. |

**Note**: The script automatically removes these invalid URL types:
- `javascript:`, `data:`, `file:`, `about:` protocols
- WeChat internal links (`weixin:`, `wx://`)
- Relative paths (`/path`, `./path`)
- Hash-only links (`#anchor`)
- Empty links

### General Issues

- **Chrome not found**: Set `NOTION_CLIPPER_CHROME_PATH` environment variable
- **Timeout errors**: Increase `--timeout` value or use `--wait` mode
- **Content missing**: Try `--wait` mode for dynamic/lazy-loaded pages
- **Notion API error (401/403)**: Check API key validity and integration permissions
- **Notion API error**: Ensure integration has access to target database/page

### Code Optimizations Applied

The following optimizations have been implemented to handle unstable networks and invalid URLs:

1. **Auto-retry mechanism**: Up to 6 retries with exponential backoff (1s → 2s → 4s → 4s...)
2. **Increased timeout**: 30s for Notion API requests (was 25s)
3. **URL cleaning**: Removes invalid URLs before Notion API submission
4. **Using tsx**: Node.js runtime that properly handles direct connections (unlike Bun)

Files in this skill

  • SKILL.md9.2 KB
  • scripts/cdp.ts11 KB
  • scripts/constants.ts370 B
  • scripts/html-to-markdown.ts8.1 KB
  • scripts/main.ts9.2 KB
  • scripts/markdown-to-notion.ts5.7 KB
  • scripts/notion-api.ts10.2 KB
  • scripts/package-lock.json24.4 KB
  • scripts/package.json142 B
  • scripts/paths.ts1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…