README file from
Github☁️ Sync Confluence
💡 Why Sync Confluence
- Frontmatter-driven binding — drop a Confluence page URL into your note's frontmatter, that's the entire wiring.
- Multi-instance routing — connect up to 10 Confluence instances in one vault; multi-target notes can span instances safely.
- Cloud + Server / Data Center — Basic auth (email + API token) for Atlassian Cloud, Bearer (Personal Access Token) for Server 7.9+ / DC.
- Content-hash skip — unchanged notes are not re-pushed; bandwidth and audit log stay clean.
- Local attachments auto-upload —
![[image.png]]embeds become Confluence attachments; regular images display at a configurable width (192px by default) without resizing the uploaded source. - Native Confluence TOC — keep a hand-written
[!summary]+ 目录callout in Obsidian; on sync it becomes Confluence's official H2-H3 table-of-contents macro. - Auto-create child pages — set
confluence_parent_urland the first sync creates the page, then writes the URL back. - Mermaid / PlantUML pre-render — diagrams are rendered to an image attachment before sync. Mermaid defaults to the in-process Obsidian engine (SVG, pixel-identical to your preview, no network). A kroki HTTP service (PNG, max compatibility) is optional.
- Many triggers — ribbon icon, command palette, editor / file-tree right-click, scheduled timer.
- Bilingual UI — automatically follows Obsidian's language (English / 简体中文).
📦 Install
[!TIP] The plugin is published in the Obsidian community plugin browser. The community-plugin path is the fastest.
From the community plugin browser
- Open Settings → Community plugins.
- Click Browse, search
Sync Confluence. - Install → Enable.
From a GitHub release (manual)
- Download
main.js,manifest.json,styles.cssfrom the latest release. - Drop them into
<vault>/.obsidian/plugins/sync-confluence/. - Reload Obsidian → enable in Settings → Community plugins.
Via BRAT (for beta tracking)
- Install BRAT from the community store.
- BRAT settings → Add Beta plugin → enter
dzplus/obsidian-sync-confluence.
🚀 Quick Start
1. Get a token from Confluence
| You're on… | Get this | Where |
|---|---|---|
| Atlassian Cloud | API token | id.atlassian.com → Security → API tokens |
| Server / Data Center 7.9+ | Personal Access Token | Confluence → Profile picture → Settings → Personal Access Tokens |
| Server (legacy) | Your login password | (same as your domain login) |
2. Store the token in Obsidian's secret vault (Obsidian 1.11.4+)
Settings → Key vault → Create new secret → paste the token → name it (e.g. confluence-token).
3. Plug it into the plugin
Settings → Sync Confluence → Confluence authentication:
- Base URL — Cloud:
https://xxx.atlassian.net/wiki. Server/DC:https://confluence.your-corp.com(usually no/wiki). - Authentication type — Cloud + Server-legacy → Basic. Server-PAT → Bearer.
- Account (Basic only) — Cloud: your Atlassian email. Server: your domain account.
- Password / API token — pick the secret you just created.
- Click Validate credentials. You should see your display name.
4. Bind a note
Open any note and add to its frontmatter:
---
confluence_url: https://xxx.atlassian.net/wiki/spaces/XXX/pages/12345/Title
---
Or use the command palette: Insert Confluence frontmatter into current note — the plugin will stub the fields for you.
5. Sync
Any of these works:
- Click the ☁ ribbon icon (syncs all bound notes).
- Run command:
Sync current note/Sync all notes. - Right-click the note (or a folder in the file tree) →
Sync to Confluence. - Let the timer fire (default: every 30 min — change in Sync schedule).
The status-bar pill shows the last result: ☁ Idle / ☁ Syncing / ☁ Synced / ☁ Failed.
🏢 Multi-instance Confluence
Add another server with Settings → Sync Confluence → Confluence authentication → Add Confluence instance. Each instance has its own name, base URL, authentication, secret, and legacy-character compatibility switch.
Targets are index-aligned across confluence_url, confluence_parent_url, and confluence_page_id. An existing target is routed by confluence_url; confluence_parent_url is used only while its URL is empty and the child page still needs to be created. Overlapping base URLs use the longest valid URL-prefix match. A multi-target note may therefore sync to several instances, while each engine updates only its own targets and cache slice.
Up to 10 instances can be configured. A fully unmatched note is listed as
Unmatched; an unmatched target inside an otherwise matched note is reported as a target failure instead of being silently skipped.
📝 Frontmatter cheatsheet
Existing page — bind by URL
---
confluence_url: https://xxx.atlassian.net/wiki/spaces/DOC/pages/12345/My-Page
---
New page — let the plugin create it under a parent
---
confluence_parent_url: https://xxx.atlassian.net/wiki/spaces/DOC/pages/100/Parent
confluence_url:
---
On the first sync the plugin creates the child page (titled after the note's filename) and writes the new URL back into confluence_url. Subsequent syncs hit that URL directly.
Multi-parent example — create or update copies under multiple parents
---
confluence_parent_url:
- https://xxx.atlassian.net/wiki/spaces/DOC/pages/100/Parent-A
- https://xxx.atlassian.net/wiki/spaces/DOC/pages/200/Parent-B
confluence_url:
- https://xxx.atlassian.net/wiki/spaces/DOC/pages/12345/My-Page
- ""
confluence_page_id:
- "12345"
- ""
---
CSV-format multi-parent example
---
confluence_parent_url: https://xxx.atlassian.net/wiki/spaces/DOC/pages/100/Parent-A, https://xxx.atlassian.net/wiki/spaces/DOC/pages/200/Parent-B
confluence_url: https://xxx.atlassian.net/wiki/spaces/DOC/pages/12345/My-Page, ""
confluence_page_id: 12345, ""
---
Fields written back by the plugin — leave these blank, they're maintained automatically:
confluence_page_id— resolved page ID.confluence_last_synced— ISO timestamp of the last successful push.confluence_last_hash— instance ID → page ID → content hash; equal hash = sync is a no-op for that target.confluence_attachments— instance ID → page ID → filename →{hash, id}cache, used to skip re-uploading unchanged attachments.
🔗 Links & mentions
Wikilinks. [[Other Note]] / [[Other Note|alias]] (and standard [text](note.md) links) are resolved through Obsidian's metadata cache. If the target note has a confluence_url for the current instance, the link becomes a hyperlink to that instance's page; otherwise it degrades to plain text. Batch syncs pre-create placeholder pages for parent-only notes first, so cross-references inside the same batch resolve on the first sync.
Heading anchors. Same-page [[#Heading]] / [text](#heading) and cross-page [[Other Note#Heading]] / [text](note.md#heading) links are converted to native Confluence heading anchors. Heading matching is case-sensitive, following Confluence behavior.
User mentions (Server / DC only). Write @[[John Doe]] to mention a Confluence user. The plugin looks up the linked note (John Doe.md) and reads the current instance's username from its frontmatter:
---
confluence_username:
default: john.d
work: j.doe
---
The keys are the stable instance IDs shown on each settings card. If the current instance has an entry, the mention becomes a real Confluence user link; otherwise it degrades to plain @John Doe. Legacy scalar usernames are migrated to every configured instance once. Cloud is not supported yet (Cloud storage format requires ri:account-id).
🎨 Diagram rendering (optional)
| Source | Plugin behavior |
|---|---|
mermaid block |
On by default. Renders to an image attachment using one of two engines (see below). |
plantuml block |
Off by default; on → renders via a PlantUML server, uploads PNG. |
Mermaid engine
Pick one in Settings → Diagrams → Renderer:
| Engine | Output | Best for |
|---|---|---|
| Obsidian built-in engine (default) | SVG rendered locally with Obsidian's mermaid runtime | Pixel-identical to your editor preview, no network needed, time-axis diagrams scale to content width. Trade-off: SVG output — older Confluence Server (≤5.x) may not render it inline; fonts follow your Obsidian theme. |
| Kroki remote service | PNG via https://kroki.io/mermaid/png (or self-hosted) |
Maximum compatibility — works on every Confluence version, full CJK / emoji font coverage. Trade-off: mermaid source is sent to the configured server. The public kroki.io instance is a third party; use a self-hosted Kroki for confidential diagrams. Time-axis diagrams (gantt / timeline) also render at a cramped width and date labels overlap. |
For corporate networks using kroki, point Kroki service URL at a self-hosted kroki instance (a single docker run will do). The same privacy warning applies to PlantUML: enabling it sends source to the configured PlantUML server (public plantuml.com by default).
⌨️ Commands & menus
| Command | What it does |
|---|---|
Sync all notes |
Walks scan folders and syncs every bound note. |
Sync current note |
Syncs only the active note. |
Insert Confluence frontmatter into current note |
Stubs the 5 frontmatter fields so you only have to paste the URL. |
Create bound note |
Prompts for path + URL, then creates a new note already bound. |
Export storage preview of current note |
Writes the converted Confluence storage XHTML to <note>.preview.xml — useful for debugging parser errors. |
Validate credentials |
Pings Confluence with the current settings and shows your account name. |
Right-click menus:
- In the editor — Sync this note / Insert frontmatter (whichever applies).
- In the file tree on a note — same as above.
- In the file tree on a folder — Sync every bound note under this folder (recursive).
Properties panel: when a note has a confluence_url property, the plugin adds two icons next to the property key — sync this note and open in Confluence (multiple bound pages pop a picker menu). There is deliberately no one-click "unbind" button; destructive actions don't belong one click away in the properties panel.
🛠️ Troubleshooting
401 / Authentication failed — Cloud uses email + API token, not your Atlassian password. Server 7.9+ should use Bearer with a PAT, not Basic.
XSRF rejection on Server — The plugin already routes around this by using Node https for POST + JSON / multipart uploads. If you still hit it, your reverse proxy may be stripping headers; check X-Atlassian-Token: no-check.
Mermaid block shows source instead of image — turn on Render Mermaid diagrams in settings. The default engine (Obsidian built-in) renders locally. If you switched to kroki, it needs network access to the configured server; on a corporate network either self-host kroki or switch back to Obsidian built-in (SVG).
Gantt / timeline dates overlap on Confluence — kroki renders these at a fixed narrow width so the date axis labels collide. Switch the engine to Obsidian built-in (SVG) to let the chart scale to content width.
Cannot find secret vault — requires Obsidian 1.11.4+. On older versions the plugin falls back to a plaintext field; upgrade Obsidian to use the encrypted vault.
The plugin keeps syncing the same note — check confluence_last_hash; if you're editing in the Confluence UI too, every sync will overwrite Confluence and reset the hash. This plugin is one-way (Obsidian → Confluence) by design.
🧱 Limitations
- One-way sync only. Edits made directly in Confluence are overwritten on the next sync.
- Desktop only. Mobile Obsidian doesn't expose the Node
httpsmodules the plugin relies on for XSRF-safe uploads. - No vendor macros. Headings, lists, tables, fenced code, links, images and callouts are converted; vendor-specific macros aren't.
- TOC conversion is intentionally narrow. Only a
[!summary]+ 目录callout containing same-page heading links becomes the native Confluence TOC; manually curated ordering and inline grouping are replaced by Confluence's automatic H2-H3 hierarchy.
🧑💻 Development
bun install
bun test
bun run dev # watch mode, writes dist/main.js
bun run build # production build (typecheck + bundle)
bun run build also copies manifest.json and styles.css into dist/, so the directory can be dropped straight into .obsidian/plugins/sync-confluence/ for local testing.
Release flow:
npm version 0.2.1 # bumps package.json + manifest.json + versions.json
git push && git push --tags
The release.yml workflow builds and attaches the three required files to a GitHub Release.
📄 License
☁️ Sync Confluence(中文)
按定时把 Obsidian 笔记推到 Confluence 对应页面 —— 一个 frontmatter 字段搞定绑定,不需要单独的映射文件。
💡 为什么用 Sync Confluence
- Frontmatter 驱动绑定 —— 在笔记 frontmatter 里写一个 Confluence 页面 URL,就这一步。
- 多实例安全路由 —— 一个 vault 最多连接 10 个 Confluence 实例,多 target 笔记可跨实例同步。
- Cloud + Server / DC —— Cloud 用 Basic(邮箱 + API token),Server 7.9+ / DC 用 Bearer(个人访问令牌)。
- 内容哈希去重 —— 没改的笔记不重复推送,省带宽也省审计噪声。
- 本地附件自动上传 —— 笔记里
![[image.png]]形式引用的本地图片自动上传为 Confluence 附件;普通图片默认显示宽度为 192px(可配置),上传原图不压缩。 - 自动建子页面 —— 设
confluence_parent_url,首次同步时插件自动建子页面并把新 URL 回写到confluence_url。 - Mermaid / PlantUML 预渲染 —— 同步前渲染成图片附件,Confluence 端不装宏也能看图。Mermaid 默认走 Obsidian 内置引擎(SVG,跟笔记预览像素级一致、不走网络);可选 kroki 远端服务(PNG,兼容性最好)。
- 多种触发方式 —— Ribbon、命令面板、编辑器 / 文件树右键、定时器。
- 中英双语 UI —— 跟随 Obsidian 语言自动切换。
📦 安装
[!TIP] 插件已发布到 Obsidian 官方社区插件库,优先用这条路径。
从社区插件库安装
- 打开 设置 → 第三方插件。
- 点 浏览,搜索
Sync Confluence。 - 点 安装 → 启用。
从 GitHub Release 手动安装
- 在 最新 Release 页面 下载
main.js、manifest.json、styles.css。 - 放到
<vault>/.obsidian/plugins/sync-confluence/。 - 重启 Obsidian → 在 设置 → 第三方插件 里启用。
通过 BRAT(跟踪 beta 版)
- 从社区插件库装 BRAT。
- BRAT 设置 → Add Beta plugin → 填
dzplus/obsidian-sync-confluence。
🚀 快速开始
1. 从 Confluence 拿一个 token
| 你的环境 | 需要什么 | 在哪拿 |
|---|---|---|
| Atlassian Cloud | API token | id.atlassian.com → Security → API tokens |
| Server / DC 7.9+ | Personal Access Token | Confluence → 头像 → 设置 → Personal Access Tokens |
| Server(老账号体系) | 登录密码 | (和你登录 Confluence 的密码一致) |
2. 把 token 存到 Obsidian 密钥库(需 Obsidian 1.11.4+)
设置 → 密钥库 → 创建新密钥 → 把 token 粘到密钥值 → 给它起个名字(如 confluence-token)。
3. 在插件里连起来
设置 → Sync Confluence → Confluence 认证:
- Base URL —— Cloud 形如
https://xxx.atlassian.net/wiki;Server / DC 通常无/wiki后缀,如https://confluence.your-corp.com。 - 认证方式 —— Cloud 与 Server 老账号体系选 Basic;Server PAT 选 Bearer。
- 账号(仅 Basic)—— Cloud 填 Atlassian 邮箱;Server 填域账号。
- 密码 / API Token —— 从下拉里选你刚存的密钥。
- 点 验证认证,应该看到自己的显示名。
4. 给一篇笔记加 frontmatter 绑定
打开任意笔记,在 frontmatter 里加:
---
confluence_url: https://xxx.atlassian.net/wiki/spaces/XXX/pages/12345/Title
---
也可以用命令面板:在当前笔记插入 frontmatter,插件会把所有字段都准备好。
5. 同步
下面任意一种:
- 点左侧 ☁ Ribbon 图标(同步全部已绑定笔记)。
- 跑命令:
同步当前笔记/同步全部笔记。 - 右键笔记 / 文件夹 →
同步到 Confluence。 - 等定时器(默认 30 分钟一次,同步调度 里改)。
状态栏小图标会显示最近一次结果:☁ 空闲 / ☁ 同步中 / ☁ 已同步 / ☁ 失败。
🏢 多实例 Confluence
通过 设置 → Sync Confluence → Confluence 认证 → 新增 Confluence 实例 添加服务器。每个实例独立保存名称、Base URL、认证、密钥和旧版字符兼容开关。
confluence_url、confluence_parent_url、confluence_page_id 按下标组成 target。已有页面只按 confluence_url 路由;仅当 URL 为空、需要新建子页面时才使用 confluence_parent_url。Base URL 重叠时采用合法的最长 URL 前缀匹配。因此一篇多 target 笔记可进入多个实例,但每个同步引擎只写自己的 target 和缓存切片。
单个 vault 最多配置 10 个实例。整篇完全无法匹配时列为
Unmatched;已匹配笔记中的单个未知 target 会明确报失败,不会静默跳过。
📝 Frontmatter 速查
已有页面 —— 用 URL 直接绑
---
confluence_url: https://xxx.atlassian.net/wiki/spaces/DOC/pages/12345/My-Page
---
还没建页面 —— 让插件在指定父页下建子页面
---
confluence_parent_url: https://xxx.atlassian.net/wiki/spaces/DOC/pages/100/Parent
confluence_url:
---
首次同步时插件以本笔记文件名为标题创建子页面,并把新页面 URL 回写到 confluence_url。之后同步直接走这个 URL。
多父页面示例 —— 同一篇笔记同步到多个父页面下的副本
---
confluence_parent_url:
- https://xxx.atlassian.net/wiki/spaces/DOC/pages/100/Parent-A
- https://xxx.atlassian.net/wiki/spaces/DOC/pages/200/Parent-B
confluence_url:
- https://xxx.atlassian.net/wiki/spaces/DOC/pages/12345/My-Page
- ""
confluence_page_id:
- "12345"
- ""
---
CSV 格式多父页面示例
---
confluence_parent_url: https://xxx.atlassian.net/wiki/spaces/DOC/pages/100/Parent-A, https://xxx.atlassian.net/wiki/spaces/DOC/pages/200/Parent-B
confluence_url: https://xxx.atlassian.net/wiki/spaces/DOC/pages/12345/My-Page, ""
confluence_page_id: 12345, ""
---
插件自动回写的字段 —— 你不用填,留空即可:
confluence_page_id—— 解析出的 Page ID。confluence_last_synced—— 上次成功推送的 ISO 时间戳。confluence_last_hash—— 实例 ID → Page ID → 内容哈希;相同 target 的哈希一致就跳过。confluence_attachments—— 实例 ID → Page ID → 文件名 →{hash, id}附件缓存,用于跳过未变附件。
🔗 链接与 mention
Wikilink。 [[另一篇笔记]] / [[另一篇笔记|别名]](以及标准 [文本](note.md) 链接)会经 Obsidian metadata cache 解析:目标笔记在当前实例有 confluence_url → 替换为该实例页面的超链接;没有 → 降级为纯文本。批量同步会先给“仅有 parent”的笔记预建占位页,同批笔记互相引用首次同步即可解析。
标题锚点。 同页 [[#标题]] / [文本](#标题) 和跨页 [[另一篇笔记#标题]] / [文本](note.md#标题) 会转换为 Confluence 原生标题锚点。标题匹配遵循 Confluence 规则,区分大小写。
用户 mention(仅 Server / DC)。 写 @[[张三]] 即可 mention Confluence 用户。插件查找被链接的笔记(张三.md),按当前实例读取 confluence_username:
---
confluence_username:
default: zhangsan
work: zhang.san
---
键是每张设置卡里显示的稳定实例 ID。当前实例有值时会生成真实 Confluence 用户链接;缺失时只在该实例降级为纯文本 @张三。旧版单值 username 会一次性迁移到全部已配置实例。Cloud 暂不支持(Cloud storage 格式要求 ri:account-id)。
🎨 图表渲染(可选)
| 源 | 插件行为 |
|---|---|
mermaid 块 |
默认开。同步前渲染成图片附件,用两个引擎之一(见下)。 |
plantuml 块 |
默认关;开 → 走 PlantUML Server 渲染为 PNG 上传。 |
Mermaid 引擎
在 设置 → 图表渲染 → 渲染方式 二选一:
| 引擎 | 输出 | 适用 |
|---|---|---|
| Obsidian 内置引擎(默认) | SVG,本地用 Obsidian 自带的 mermaid 渲染 | 跟编辑器预览像素级一致、无网络依赖、时间轴图表按内容宽度自然撑开。代价:产物是 SVG,老版本 Confluence Server(≤5.x)可能不 inline 显示;字体跟随你当前主题。 |
| Kroki 远端服务 | PNG,走 https://kroki.io/mermaid/png(或自建实例) |
兼容性最好——任何 Confluence 版本都能 inline 渲染,中文/emoji 字体齐全。代价:mermaid 源码会发送到配置的服务器。公共 kroki.io 是第三方,机密图表请改用自建 Kroki。时间轴类图表(gantt / timeline)还会被压缩到固定窄宽度,日期标签挤在一起。 |
走 kroki 的企业内网用户,把 Kroki 服务 URL 指向自建 kroki 实例(一条 docker run 即可)。PlantUML 同样:开启后源码会发到配置的 PlantUML 服务器(默认公共 plantuml.com)。
⌨️ 命令与菜单
| 命令 | 作用 |
|---|---|
同步全部笔记 |
遍历扫描目录,同步所有已绑定的笔记 |
同步当前笔记 |
仅同步当前活动笔记 |
在当前笔记插入 frontmatter |
把 5 个 frontmatter 字段填好,你只需要粘 URL |
创建绑定笔记 |
填路径 + URL,直接生成一篇已绑定的笔记 |
导出当前笔记的 storage 预览 |
把转换后的 Confluence storage XHTML 写到 <笔记>.preview.xml,便于排查转换报错 |
验证认证信息 |
用当前设置 ping Confluence,回显你的账号显示名 |
右键菜单:
- 编辑器内 —— 同步该笔记 / 插入 frontmatter(按是否已绑定切换)
- 文件树里点笔记 —— 同上
- 文件树里点文件夹 —— 同步该文件夹下所有已绑定笔记(递归)
属性面板:笔记有 confluence_url 属性时,插件在属性名旁注入两个图标 —— 同步当前笔记 和 在 Confluence 中打开(绑定多个页面时弹菜单选择)。有意不做一键"解绑"按钮:破坏性操作不该在属性面板一击可达。
🛠️ 排错
401 / 认证失败 —— Cloud 用 邮箱 + API token,不要填 Atlassian 登录密码。Server 7.9+ 走 PAT 的话要选 Bearer,不是 Basic。
Server 上 XSRF 拒绝 —— 插件已经走 Node https 模块绕过 requestUrl 的 XSRF 限制了。如果还报,多半是你的反代剥了 header,检查一下 X-Atlassian-Token: no-check 透传。
Mermaid 代码块没渲成图 —— 在设置里把 渲染 Mermaid 图表 打开。默认引擎(Obsidian 内置)本地渲染、不走网络。如果切到了 kroki,需要能访问配置的服务器;企业内网要么自建 kroki,要么把引擎切回 Obsidian 内置引擎(SVG)。
Confluence 上 Gantt / timeline 的日期挤在一起 —— kroki 渲染这类时间轴图表用的画布太窄,日期标签互相重叠。把引擎切到 Obsidian 内置引擎(SVG),让图表按内容宽度自然撑开。
找不到密钥库 —— 需要 Obsidian 1.11.4+。老版本会回退到明文输入;升级 Obsidian 即可走加密密钥库。
插件一直在同步同一篇笔记 —— 看 confluence_last_hash;如果你也在 Confluence 端直接改,每次同步都会被插件覆盖回 Obsidian 的内容,hash 会循环变化。本插件单向(Obsidian → Confluence),不读回 Confluence 改动。
🧱 限制
- 仅单向同步。在 Confluence 端直接改的内容会在下次同步时被覆盖。
- 仅桌面端。Obsidian 移动端没暴露插件做 XSRF-safe 上传所需的 Node
https模块。 - 不覆盖第三方 Confluence 宏。标题、列表、表格、围栏代码、链接、图片、callout 都做了转换;vendor 自定义宏不处理。
- 目录转换范围刻意收窄。只有正文含同页标题链接的
[!summary]+ 目录callout 才会转成 Confluence 官方目录;手工排序和同一行分组会由 Confluence 自动生成的 H2-H3 层级取代。
🧑💻 开发
bun install
bun test
bun run dev # watch 模式,写 dist/main.js
bun run build # 生产构建(typecheck + 打包)
bun run build 会把 manifest.json 和 styles.css 一起拷到 dist/,整个目录可以直接拖到 .obsidian/plugins/sync-confluence/ 本地测试。
发版:
npm version 0.2.1 # 同步 package.json + manifest.json + versions.json
git push && git push --tags
release.yml 会自动构建并把三个必备文件挂到 GitHub Release 上。