Claude
Skills
Sign in
Back

obsidian-web-clipper

Included with Lifetime
$97 forever

Author and debug Obsidian Web Clipper extension templates: template JSON, variables, filters, template logic, schema.org/CSS selectors, AI interpreter prompts, URL/schema triggers. Use when generating, importing, or fixing a clipper template, or matching one to a target site. Not for general scraping.

Web Dev

What this skill does


# Obsidian Web Clipper Templates

Obsidian Web Clipper is a browser extension that saves web content to an Obsidian vault as Markdown notes. Templates define how pages are captured — what metadata to extract, how to format the note, and which sites to auto-match.

Templates are configured as JSON. Users can import/export individual templates or full settings backups. When generating templates, output valid JSON the user can import directly.

**Caution:** full settings exports contain interpreter API keys in plaintext (`interpreter_settings.providers[].apiKey`). Never quote them; flag exports stored in version control.

## Adapt to the user's vault conventions

Templates are deeply opinionated about folder layout, frontmatter property names, category/tag conventions, and note body structure. **Match the user's existing conventions rather than inventing.** Before drafting a template, look for:

- Vault-level docs (`CLAUDE.md`, `AGENTS.md`, READMEs)
- An existing templates folder, sample notes of the type being clipped, or a previously exported clipper settings file
- Any YAML property-sort configuration (Linter or similar)

When conventions aren't discoverable, default to minimal vendor-neutral choices and flag the assumptions you made so the user can adjust before import.

If the vault has a property sort order, mirror that order in the template's `properties` array — the extension preserves array order in the output frontmatter, so freshly clipped notes won't reshuffle on lint.

## Template JSON Schema

```json
{
  "schemaVersion": "0.1.0",
  "name": "Template Name",
  "behavior": "create",
  "noteNameFormat": "{{title}} - {{site}}",
  "noteContentFormat": "{{content}}",
  "vault": "VaultName",
  "path": "folder/subfolder",
  "context": "",
  "properties": [],
  "triggers": []
}
```

| Field               | Type   | Description                                                 |
| ------------------- | ------ | ----------------------------------------------------------- |
| `schemaVersion`     | string | Always `"0.1.0"`                                            |
| `name`              | string | Display name shown in the extension                         |
| `behavior`          | string | How the note is created (see below)                         |
| `noteNameFormat`    | string | Filename for the note, supports variables                   |
| `noteContentFormat` | string | Note body content, supports variables                       |
| `vault`             | string | Target vault name (optional — omit to use default)          |
| `path`              | string | Folder path within the vault (optional)                     |
| `context`           | string | Limits what page content the interpreter AI sees (optional) |
| `properties`        | array  | Frontmatter properties (optional)                           |
| `triggers`          | array  | Auto-match rules for URLs/schemas (optional)                |

When exporting a single template, the JSON is the template object directly (no wrapper). When part of a full settings export, templates are stored as `template_[id]` keys.

### Behaviors

| Value              | Description                         |
| ------------------ | ----------------------------------- |
| `create`           | Create a new note                   |
| `append-daily`     | Append to today's daily note        |
| `prepend-daily`    | Prepend to today's daily note       |
| `append-specific`  | Append to a specific existing note  |
| `prepend-specific` | Prepend to a specific existing note |

## Variables

All variables use `{{variableName}}` syntax. Filters chain with pipes: `{{variable|filter1|filter2:"arg"}}`. There are four kinds:

- **Preset variables** — built-in page metadata: `{{title}}`, `{{url}}`, `{{author}}`, `{{site}}`, `{{published}}`, `{{description}}`, `{{content}}` (full article markdown), `{{date}}`, `{{highlights}}`, etc. Look up the full list in the live docs.
- **Schema variables** — extract Schema.org JSON-LD from the page. Patterns:

  ```
  {{schema:name}}                    — first match anywhere
  {{schema:@Recipe:name}}            — scoped to a specific @type
  {{schema:author.name}}             — nested keys via dots
  {{schema:image[0].contentUrl}}     — array index
  {{schema:actors[*].name}}          — flatten arrays
  ```

  Schema-driven templates are usually the right choice for domain-specific clippers (recipes, films, books, jobs) since one `schema:@Type` trigger matches across many sites.

- **Selector variables** — pull content via CSS selectors when there's no schema:

  ```
  {{selector:h1}}                    — text content
  {{selector:img.hero?src}}          — attribute value
  {{selectorHtml:article}}           — raw HTML
  {{selectorHtml:body|markdown}}     — HTML → Markdown
  ```

- **Interpreter variables** — natural-language prompts evaluated by an LLM (requires the user has an LLM provider configured in extension settings):

  ```
  {{"a summary of the page"}}
  {{"3 tags describing this content"}}
  {{"return JSON array with fields: author, text"|map:item => item.text|join:"\n"}}
  ```

  The `context` field at the template top level controls what page content the AI sees. Use `{{selectorHtml:#main}}` or wrap structured context like `<page>\nTitle: {{title}}\n{{content}}\n</page>` to keep prompts focused.

## Filters

Chain filters with `|`. Look up specific filter signatures in the live docs (see Reference at the bottom). The patterns and gotchas below are the operationally non-obvious parts.

### Filter gotchas (verified via testing)

These trip up template authors most often:

- **String concatenation with `+` doesn't work inside `map` callbacks.** The expression parser treats `+` as an unexpected character and fails the template import with `"Unexpected character '+' in template"`. Use template literals instead:

  ```
  ✗ |map:item => "- " + item               (parse error on import)
  ✓ |map:item => "- ${item}"               (template literal — correct)
  ```

- **Built-in filters cannot be chained inside `map`.** Flatten or transform inside `map`, then apply filters to the result outside:

  ```
  ✗ |map:item => item.text|trim            (filter not allowed inside map)
  ✓ |map:item => item.text|join:"\n"|trim  (filter chain outside map)
  ```

- **For arrays of objects with multi-line per-item output, use `map` to flatten to flat keys, then `template`.** Nested key access in `template` literals is not documented and unreliable; flattening first is the safe pattern:

  ```
  |map:item => ({name: item.author.name, body: item.reviewBody})
  |template:"${name}:\n> ${body}\n\n"
  ```

- **`duration` outputs `HH:mm:ss`, not compact human format.** For something like `45m` or `1h 30m`, skip the filter and chain `replace` on the raw ISO 8601 string:

  ```
  {{schema:@Recipe:prepTime|replace:"PT":""|replace:"H":"h "|replace:"M":"m"|trim}}
  → "PT1H30M" becomes "1h 30m"
  → "PT45M"   becomes "45m"
  ```

- **`|list` works on string arrays directly** — no need to map a `"- " + item` prefix yourself. Use `|list` for bullets, `|list:numbered` for numbered, `|list:task` for checkboxes.

### Common Filter Chains

```
{{url|split:"?"|slice:0,1}}                              — strip query params
{{schema:actors[*].name|wikilink|slice:0,4|join}}         — first 4 actors as wikilinks
{{highlights|map:item => item.text|join:"\n\n"|blockquote}} — highlights as blockquote
{{date|date:"YYYY-MM-DD-ddd"}}                            — formatted date with day name
{{"return JSON..."|map:item => item.title|join:"\n"}}     — AI → structured → formatted
```

## Template logic

Templates support Twig/Liquid-style logic in `noteContentFormat`, `noteNameFormat`, and property values: `{% if %}`/`{% elseif %}`/`{% else %}` conditionals, `{% for %}` loops (with a `loop` object: `loop.index`, `loop.first`, `loop.last`, etc.), `{% set %}` variable assignment, and `??` fallbacks (`{{title ?? "Untitled"}}`). Full s
Files: 1
Size: 15.4 KB
Complexity: 25/100
Category: Web Dev

Related in Web Dev