Pubcopy

approved

by canartuc

Copy notes as platform-optimized HTML for Medium and Substack. - This plugin has not been manually reviewed by Obsidian staff.

1 stars242 downloadsUpdated 26d agoMIT

Pubcopy

Tests License: MIT

Obsidian plugin that copies your notes as platform-optimized HTML to clipboard for pasting into Medium and Substack without formatting loss.

Install

From Obsidian (recommended)

Settings > Community plugins > Browse > Search "Pubcopy" > Install > Enable

Manual

  1. Download main.js, manifest.json, styles.css from the latest release
  2. Create folder: <your-vault>/.obsidian/plugins/pubcopy/
  3. Copy the 3 files into that folder
  4. Restart Obsidian
  5. Settings > Community plugins > Enable "Pubcopy"

Usage

Three ways to trigger:

MethodBehavior
Command Palette (Cmd/Ctrl+P) > "Pubcopy"Copies entire note
Right-click in editor > Pubcopy submenuCopies selected text (or entire note if no selection)
Three-dot menu (top-right of note) > Pubcopy submenuCopies entire note

Each method offers two options:

  • Copy for Medium
  • Copy for Substack

After copying, paste (Cmd/Ctrl+V) into the Medium or Substack editor.

What gets converted

56 Obsidian markdown elements are handled:

ElementMediumSubstack
Bold, italic, strikethrough, inline codeYesYes
Highlights ==text==Converted to boldConverted to bold
Headers H1-H4YesYes
Headers H5-H6Flattened to H4Yes
Lists (ordered, unordered, nested)Max 2 levelsUnlimited
Task lists - [ ]Unicode checkboxesUnicode checkboxes
Callouts > [!note]Styled blockquote with labelStyled blockquote with label
Code blocks (with language)<pre><code><pre>
TablesHTML tableHTML table
Images (local)Base64 embeddedBase64 embedded
Images (remote URL)URL passthroughURL passthrough
Image captionsItalic text below image<figcaption>
FootnotesSuperscript + Notes sectionNative
Math (LaTeX)Rendered via KaTeXRendered via KaTeX
Mermaid diagramsStripped (not supported)Stripped (not supported)
Wikilinks, tags, comments, frontmatterStrippedStripped
Embeds ![[note]]Resolved and inlinedResolved and inlined

Settings

Settings > Community plugins > Pubcopy > Settings

SettingDefaultDescription
Strip frontmatterOnRemove YAML frontmatter
Strip tagsOnRemove #tag references
Strip wikilinksOnConvert [[links]] to plain text
Mermaid formatSVGSVG or PNG (for future use)
Image handlingAutoAuto: base64 for local, URL for remote
Show notificationOnDisplay notice after copying

Privacy & permissions

The Obsidian community store shows a "Clipboard Access" label for Pubcopy. That label is a generic notice applied to any plugin that touches the clipboard. Here is exactly what Pubcopy does:

  • Writes only, never reads. Pubcopy calls navigator.clipboard.write() to place your converted note on the clipboard. It never reads the clipboard, so the label's "may expose content copied from outside Obsidian" warning does not apply. That warning concerns plugins that read clipboard contents.
  • Only your note is copied. The clipboard payload is built solely from the note (or selection) you choose to copy, as text/html plus a text/plain fallback.
  • Stays on your device. Pubcopy makes no network requests. Conversion, including math rendering and local image embedding, runs entirely on your machine. Remote image URLs are passed through untouched, never fetched.

Pubcopy is MIT-licensed open source. You don't have to take these claims on trust: the full source is in this repository, so anyone can read it and verify exactly what the plugin does.

Development

Prerequisites

  • Node.js 24+
  • npm

Setup

git clone https://github.com/canartuc/pubcopy.git
cd pubcopy
npm install

Build

# Development (watch mode, rebuilds on file change)
npm run dev

# Production build
npm run build

Test

# Run all tests
npm test

# Watch mode
npm run test:watch

Deploy to your vault

First run asks for your vault path and saves it to .deploy.json (gitignored):

npm run deploy
# > Obsidian vault path: /path/to/your/vault
# > Saved to .deploy.json
# > Deployed to .../plugins/pubcopy

Every subsequent run just builds and copies:

npm run deploy

After deploying, restart Obsidian or reload the plugin.

Project structure

src/
├── main.ts                    # Plugin entry, commands, menus
├── settings.ts                # Settings interface and tab
├── converter/
│   ├── index.ts               # Conversion pipeline orchestrator
│   ├── preprocessor.ts        # Strip frontmatter, tags, wikilinks, etc.
│   ├── html-converter.ts      # Markdown to HTML via remark/rehype
│   ├── image-handler.ts       # Local base64, remote URL, captions
│   ├── embed-resolver.ts      # Resolve ![[note]] embeds
│   ├── footnote-processor.ts  # Platform-specific footnotes
│   └── math-renderer.ts       # LaTeX via KaTeX
├── platforms/
│   ├── index.ts               # PlatformProfile interface
│   ├── medium.ts              # Medium-specific rules
│   └── substack.ts            # Substack-specific rules
├── clipboard/
│   └── writer.ts              # Clipboard API (text/html + text/plain)
└── utils/
    ├── errors.ts              # PubcopyError, WarningCollector
    └── notifications.ts       # Obsidian Notice wrappers

Release

Push a tag to trigger a GitHub Actions release:

# Update version in manifest.json and package.json first
git tag X.Y.Z
git push origin X.Y.Z

GitHub Actions runs tests, builds, and creates a release with main.js, manifest.json, and styles.css.

License

MIT

For plugin developers

Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.