DEV Community

bao001 xiao
bao001 xiao

Posted on

Build Your Own Obsidian Web Clipper with the Web to Markdown/JSON API

We've all hit the same wall with read-later apps: you save an article to Pocket or Instapaper, and it works — right up until you want to actually use that content. Your notes are trapped inside someone else's silo, and the "clean view" is nice but it's not yours.

If you live in Obsidian (or any Markdown-based note system), you want something better: the article's clean content saved as plain Markdown into your vault — searchable, linkable, and permanent. The only thing standing in the way is turning a messy web page into clean Markdown.

That's exactly what the Web to Markdown/JSON API does. One HTTP call takes any URL and returns clean Markdown with the nav bars, ads, cookie banners, and scripts stripped away.

In this article you'll build your own web clipper that saves any page into your Obsidian vault as a proper note, in about 50 lines of Python.

The API at a glance

Endpoint:

POST https://web2md-api-production-d822.up.railway.app/extract
Enter fullscreen mode Exit fullscreen mode

Request:

{
  "url": "https://example.com/great-article",
  "format": "markdown",
  "max_length": 50000
}
Enter fullscreen mode Exit fullscreen mode
  • formatmarkdown, json, or text
  • max_length — cap the response size (up to 50000 characters)
  • Free tier: 50 requests/day
  • Sign up / grab a key on RapidAPI

Response:

{
  "success": true,
  "title": "The Great Article",
  "content": "# The Great Article\n\n## Introduction\n\n...",
  "description": "A summary of the article",
  "word_count": 1523,
  "response_time_ms": 210
}
Enter fullscreen mode Exit fullscreen mode

The content field is clean Markdown — headings, paragraphs, lists, code blocks, nothing else. That's the whole game: your clipper gets an article that's already ready to live in Obsidian, instead of a pile of HTML you'd have to clean yourself.

The plan

  1. POST a URL to /extract and get Markdown back.
  2. Wrap it in YAML frontmatter (title, source URL, date, tags).
  3. Sanitize the title into a filename.
  4. Save the file into your vault's Inbox folder.

The code

Save this as clip.py:

import re
import sys
from datetime import date
from pathlib import Path

import requests

API_URL = "https://web2md-api-production-d822.up.railway.app/extract"
VAULT = Path.home() / "Documents" / "Obsidian" / "Inbox"  # your vault inbox


def fetch_markdown(url: str) -> dict:
    """Turn any web page into clean Markdown via the API."""
    r = requests.post(
        API_URL,
        json={"url": url, "format": "markdown", "max_length": 50000},
        timeout=30,
    )
    r.raise_for_status()
    return r.json()


def slugify(title: str) -> str:
    """Turn an article title into a safe, readable filename."""
    name = re.sub(r"[^\w\- ]+", "", title).strip().replace(" ", "-")
    return (name[:80] or "untitled") + ".md"


def build_note(data: dict, url: str, tags: list[str]) -> str:
    """Wrap extracted Markdown in Obsidian-friendly frontmatter."""
    frontmatter = "\n".join([
        "---",
        f"title: "\"{data['title']}\"\","
        f"source: {url}",
        f"clipped: {date.today().isoformat()}",
        f"tags: [{', '.join(tags)}]",
        "---",
        "",
    ])
    return frontmatter + data["content"]


def clip(url: str, tags: list[str]) -> Path:
    """Fetch a page and save it into the vault as a Markdown note."""
    data = fetch_markdown(url)
    note = build_note(data, url, tags)

    VAULT.mkdir(parents=True, exist_ok=True)
    out = VAULT / slugify(data["title"])
    out.write_text(note, encoding="utf-8")

    print(f"Saved: {out.name} ({data['word_count']} words)")
    return out


if __name__ == "__main__":
    url = sys.argv[1]
    tags = sys.argv[2:] or ["clippings"]
    clip(url, tags)
Enter fullscreen mode Exit fullscreen mode

Run it

pip install requests
python clip.py https://example.com/great-article "reading" "tech"
Enter fullscreen mode Exit fullscreen mode

The note lands in your vault, ready to be searched, linked, and edited:

---
title: "The Great Article"
source: https://example.com/great-article
clipped: 2026-09-07
tags: [reading, tech]
---

# The Great Article

## Introduction

...clean Markdown, no nav bars or ads...
Enter fullscreen mode Exit fullscreen mode

Make it one click: a bookmarklet

A clipper you run from the terminal is fine, but a clipper you trigger with one click is a tool. Here's a tiny bookmarklet that fires off the same request and copies the Markdown to your clipboard:

javascript:(()=>{fetch("https://web2md-api-production-d822.up.railway.app/extract",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:location.href,format:"markdown"})}).then(r=>r.json()).then(d=>navigator.clipboard.writeText(d.content)).then(()=>alert("Markdown copied to clipboard"))})();
Enter fullscreen mode Exit fullscreen mode

Drag it to your bookmarks bar, click it on any article, and paste straight into a new Obsidian note. No server, no setup — the API does the extraction, your browser does the rest.

For a fully automatic flow, point clip.py at a Raycast script, an Alfred workflow, or an iOS Shortcut that posts the shared URL to a tiny Flask endpoint running clip().

Why clean Markdown matters here

Obsidian is at its best when your notes are text you can actually read and grep. If you save raw HTML into your vault, you get garbage — inline styles, <div> soup, and tracking scripts polluting your search index. By clipping through the API, every note you save is already clean Markdown, which means:

  • Full-text search finds your clipped articles by their content, not by markup.
  • Backlinks and links work normally because the text is real Markdown.
  • Syncing (iCloud, Syncthing, git) is tiny and fast — no bloated HTML.

The API's json format is also handy here: it returns structured paragraphs, headings, images, and links separately, so you can build richer notes — for example, auto-generating a ## Links or ## Images section from the structured output.

Taking it further

  • Auto-tag — run the clipped text through a keyword check (or an LLM) to suggest tags before saving.
  • Clip a whole reading list — feed the API a list of URLs and clip them all overnight (50 free requests/day covers a serious reading habit).
  • Use format: "text" for a stripped, no-markup version when you just want the prose.
  • Track your reading — append each clip's word_count to a small CSV to see what you're actually consuming.

Wrapping up

Read-later apps are convenient, but they own your notes. Building your own clipper on the Web to Markdown/JSON API gives you the same one-click convenience with output that lives in your vault, in your format, forever.

Try it free — 50 requests/day on RapidAPI — and stop letting the read-later apps hold your articles hostage.

Top comments (0)