Confluence CLI
A powerful command-line interface for Atlassian Confluence that allows you to read, search, and manage your Confluence content from the terminal.
Features
- π Read pages - Get page content in text or HTML format
- π Search - Find pages using Confluence's powerful search
- βΉοΈ Page info - Get detailed information about pages
- π List spaces - View available Confluence spaces
- βοΈ Create pages - Create new pages with support for Markdown, HTML, or Storage format
- π Update pages - Update existing page content and titles
- ποΈ Delete pages - Delete (or move to trash) pages by ID or URL
- π Attachments - List, download, upload, or delete page attachments
- π·οΈ Properties - List, get, set, and delete content properties (key-value metadata)
- π¬ Comments - List, create, and delete page comments (footer or inline)
- π¦ Export - Save a page and its attachments to a local folder
- π οΈ Edit workflow - Export page content for editing and re-import
- π Profiles - Manage multiple Confluence instances with named configuration profiles
- π Read-only mode - Profile-level write protection for safe AI agent usage
- π Raw API requests - Make arbitrary authenticated requests to any Confluence endpoint (like
gh api)
- π Format conversion - Convert between Markdown, HTML, Storage, and text formats locally (no server required)
- π§ Easy setup - Simple configuration with environment variables or interactive setup
Installation
Homebrew (macOS/Linux)
brew install pchuri/tap/confluence-cli
npm
npm install -g confluence-cli
Or run directly with npx:
npx confluence-cli
Claude Code Integration
confluence-cli ships as a Claude Code plugin. Once installed, Claude Code understands all confluence-cli commands automatically and receives updates when the skill is improved.
Option 1: Install as Plugin (recommended)
Add the marketplace and install the plugin:
/plugin marketplace add pchuri/confluence-cli
/plugin install confluence@pchuri-confluence-cli
Option 2: Install Skill manually
If you prefer not to use the plugin system, copy the skill documentation into your project:
confluence install-skill
This creates .claude/skills/confluence/SKILL.md in your current directory. Claude Code picks it up automatically.
Quick Start
-
Initialize configuration:
confluence init
-
Read a page:
confluence read 123456789
-
Search for pages:
confluence search "my search term"
-
List child pages:
confluence children 123456789
-
Create a new page:
confluence create "My New Page" SPACEKEY --content "Hello World!"
-
Update a page:
confluence update 123456789 --content "Updated content"
Configuration
Option 1: Interactive Setup
confluence init
The wizard helps you choose the right API endpoint and authentication method. It recommends /wiki/rest/api for Atlassian Cloud domains (e.g., *.atlassian.net) and /rest/api for self-hosted/Data Center instances, then prompts for Basic (email/username + token/password), Bearer, or client-certificate (mTLS) authentication.
Option 2: Non-interactive Setup (CLI Flags)
Provide all required configuration via command-line flags. Perfect for CI/CD pipelines, Docker builds, and AI coding agents.
Complete non-interactive mode (all required fields provided):
confluence init \
--domain "company.atlassian.net" \
--api-path "/wiki/rest/api" \
--auth-type "basic" \
--email "user@example.com" \
--token "your-api-token"
Scoped API token (recommended for agents β least privilege):
confluence init \
--domain "api.atlassian.com" \
--api-path "/ex/confluence/<your-cloud-id>/wiki/rest/api" \
--auth-type "basic" \
--email "user@example.com" \
--token "your-scoped-token"
Named profile (save to a specific profile):
confluence --profile staging init \
--domain "staging.example.com" \
--api-path "/rest/api" \
--auth-type "bearer" \
--token "your-personal-access-token"
mTLS profile (self-hosted or reverse-proxied Confluence APIs):
confluence --profile corp init \
--domain "docs.example.com" \
--api-path "/confluence/rest/api" \
--auth-type "mtls" \
--tls-client-cert "~/.certs/client.pem" \
--tls-client-key "~/.certs/client.key" \
--tls-ca-cert "~/.certs/ca-chain.pem"
Cookie authentication profile (Enterprise SSO):
confluence --profile sso init \
--domain "confluence.company.com" \
--api-path "/rest/api" \
--auth-type "cookie" \
--cookie "JSESSIONID=abc123xyz..."
confluence --profile sso init \
--domain "confluence.company.com" \
--auth-type "cookie" \
--cookie "JSESSIONID=abc123; XSRF-TOKEN=xyz789"
Reverse-proxy / no-auth profile (credentials injected upstream):
confluence --profile proxy init \
--domain "confluence.internal" \
--api-path "/rest/api" \
--auth-type "none"
Hybrid mode (some fields provided, rest via prompts):
confluence init --domain "company.atlassian.net" --token "your-api-token"
confluence init --email "user@example.com" --token "your-api-token"
Available flags:
-d, --domain <domain> - Confluence domain (e.g., company.atlassian.net)
-p, --api-path <path> - REST API path (e.g., /wiki/rest/api)
-a, --auth-type <type> - Authentication type: basic, bearer, mtls, cookie, or none
-e, --email <email> - Email or username for basic authentication
-t, --token <token> - API token or password
-c, --cookie <cookie> - Cookie for Enterprise SSO authentication (e.g., "JSESSIONID=...")
--tls-client-cert <path> - Client certificate for mTLS authentication
--tls-client-key <path> - Client private key for mTLS authentication
--tls-ca-cert <path> - Optional CA certificate chain for mTLS authentication
--read-only - Enable read-only mode (blocks all write operations)
β οΈ Security note: While flags work, storing tokens in shell history is risky. Prefer environment variables (Option 3) for production environments.
Option 3: Environment Variables
export CONFLUENCE_DOMAIN="your-domain.atlassian.net"
export CONFLUENCE_API_TOKEN="your-api-token"
export CONFLUENCE_EMAIL="your.email@example.com"
export CONFLUENCE_API_PATH="/wiki/rest/api"
export CONFLUENCE_AUTH_TYPE="basic"
export CONFLUENCE_PROFILE="default"
mTLS environment variables:
export CONFLUENCE_DOMAIN="docs.example.com"
export CONFLUENCE_API_PATH="/confluence/rest/api"
export CONFLUENCE_AUTH_TYPE="mtls"
export CONFLUENCE_TLS_CLIENT_CERT="~/.certs/client.pem"
export CONFLUENCE_TLS_CLIENT_KEY="~/.certs/client.key"
export CONFLUENCE_TLS_CA_CERT="~/.certs/ca-chain.pem"
Cookie environment variables (Enterprise SSO):
export CONFLUENCE_DOMAIN="confluence.company.com"
export CONFLUENCE_API_PATH="/rest/api"
export CONFLUENCE_AUTH_TYPE="cookie"
export CONFLUENCE_COOKIE="JSESSIONID=abc123xyz..."
Reverse-proxy / no-auth environment variables:
export CONFLUENCE_DOMAIN="confluence.internal"
export CONFLUENCE_API_PATH="/rest/api"
export CONFLUENCE_AUTH_TYPE="none"
Scoped API token (recommended for agents):
export CONFLUENCE_DOMAIN="api.atlassian.com"
export CONFLUENCE_API_PATH="/ex/confluence/<your-cloud-id>/wiki/rest/api"
export CONFLUENCE_AUTH_TYPE="basic"
export CONFLUENCE_EMAIL="user@example.com"
export CONFLUENCE_API_TOKEN="your-scoped-token"
CONFLUENCE_API_PATH defaults to /wiki/rest/api for Atlassian Cloud domains and /rest/api otherwise. Override it when your site lives under a custom reverse proxy or on-premises path. CONFLUENCE_AUTH_TYPE defaults to basic when an email is present and falls back to bearer otherwise. For mtls, set CONFLUENCE_TLS_CLIENT_CERT and CONFLUENCE_TLS_CLIENT_KEY; CONFLUENCE_TLS_CA_CERT is optional.
Config file location:
confluence-cli supports the XDG Base Directory Specification. The config directory is resolved in this order:
CONFLUENCE_CONFIG_DIR env var β explicit override (e.g., /custom/path)
- Legacy
~/.confluence-cli/ β if it already exists (backwards compatibility)
$XDG_CONFIG_HOME/confluence-cli/ β defaults to ~/.config/confluence-cli/
New installations go to ~/.config/confluence-cli/ by default. Existing users at ~/.confluence-cli/ are unaffected β the CLI continues to use the legacy location until you move it. To migrate, simply move the directory:
mkdir -p ~/.config/confluence-cli
mv ~/.confluence-cli/* ~/.config/confluence-cli/
rmdir ~/.confluence-cli
The stats file (stats.json) follows the same resolution and lives alongside config.json in the same directory.
Custom domains on Confluence Cloud:
If your Confluence Cloud instance uses a custom domain (e.g., wiki.example.org instead of *.atlassian.net), the CLI may misidentify it as a Server/Data Center instance and produce broken link formats. Set CONFLUENCE_FORCE_CLOUD=true to override the automatic detection:
export CONFLUENCE_FORCE_CLOUD=true
Or add "forceCloud": true to your profile in the config file (see Config file location):
{
"profiles": {
"default": {
"domain": "wiki.example.org",
"forceCloud": true
}
}
}
Link rendering on Cloud (linkStyle):
Some Cloud instances β particularly custom-domain Cloud setups β fail to render smart links (<a data-card-appearance="inline">) and show "Cannot handle: DefaultLink" errors instead. If you hit this, set linkStyle to plain to emit simple <a href> tags, which render reliably everywhere:
export CONFLUENCE_LINK_STYLE=plain
Or per-profile:
{
"profiles": {
"default": {
"domain": "wiki.example.org",
"forceCloud": true,
"linkStyle": "plain"
}
}
}
Valid values: smart (Cloud smart links), plain (simple <a href>), wiki (Server/DC ac:link). When unset, the CLI picks smart for Cloud and wiki for Server/DC β existing behavior is unchanged.
Read-only mode (recommended for AI agents):
export CONFLUENCE_READ_ONLY=true
When set, all write operations (create, update, delete, etc.) are blocked at the CLI level. The environment variable overrides the profile's readOnly setting.
Getting Your API Token
Atlassian Cloud:
Atlassian Cloud β Scoped API Token (recommended for agents and automation):
Scoped tokens restrict access to specific Atlassian products and permissions, following the principle of least privilege. They use a different API gateway (api.atlassian.com) instead of your site domain.
- Create a scoped token in your Atlassian Admin settings
- Find your Cloud ID by visiting
https://<your-site>.atlassian.net/_edge/tenant_info
- Configure with:
- Domain:
api.atlassian.com
- API path:
/ex/confluence/<your-cloud-id>/wiki/rest/api
- Auth type:
basic (email + scoped token)
Required scopes for scoped API tokens:
When creating a scoped token, select the following classic scopes based on your needs:
read:confluence-content.all | Reading pages and blog posts (read, info) |
read:confluence-content.summary | Reading content summaries and metadata (read, info) |
read:confluence-space.summary | Listing spaces (spaces) |
search:confluence | Searching content (search) |
readonly:content.attachment:confluence | Downloading attachments (attachments --download) |
write:confluence-content | Creating and updating pages (create, update) |
write:confluence-file | Uploading attachments (attachments --upload) |
write:confluence-space | Managing spaces |
For read-only usage, select at minimum: read:confluence-content.all, read:confluence-content.summary, read:confluence-space.summary, and search:confluence.
On-premise / Data Center: Use your Confluence username and password for basic authentication.
mTLS-protected Confluence APIs: Some self-hosted or reverse-proxied deployments authenticate at the TLS layer with a client certificate instead of sending an application-level token. In these environments, configure authType=mtls and provide certificate paths via CLI flags or environment variables. No Authorization header will be sent in mTLS mode.
Enterprise SSO with Cookie Authentication: For Confluence instances behind Enterprise SSO (SAML, OAuth, Okta, etc.) where API tokens or Basic/Bearer auth are not available, you can authenticate using session cookies. After logging in through your browser, extract the session cookie (typically JSESSIONID or similar) from your browser's dev tools and configure it via the --cookie flag or CONFLUENCE_COOKIE environment variable. The cookie is sent in the Cookie header instead of an Authorization header. Note that session cookies typically expire, so you'll need to refresh them periodically. For security, prefer CONFLUENCE_COOKIE env var or interactive prompt over --cookie flag since command-line arguments may be visible in shell history and process listings.
Reverse-proxy injected authentication: For deployments where a local reverse proxy injects credentials on the wire (e.g. SPNEGO/Kerberos, mTLS terminated at the proxy edge, or header injection), set authType=none. In this mode the CLI sends no Authorization or Cookie header β authentication is entirely the proxy's responsibility. Point CONFLUENCE_DOMAIN at the proxy and ensure no credentials are configured on the CLI side.
Usage
JSON output (for scripting / jq)
Pass the global --json flag to make a command emit raw JSON to stdout, so you can pipe it to tools like jq:
confluence search "release notes" --json | jq '.results[].title'
confluence spaces --json | jq -r '.spaces[].key'
confluence info 123456789 --json | jq '.version'
confluence create "Notes" ENG --content "hi" --json | jq -r '.id'
--json works on read commands (info, search, spaces, find, children, versions, comments, attachments, property-list/-get/-set) and write commands (create, create-child, update, move, delete, copy-tree, comment, comment-delete, property-delete, attachment-upload/-delete, version-delete, versions-purge). For destructive commands, --json requires --yes β it will not prompt interactively. Passing --json to a command that doesn't support it (e.g. init, convert, export, edit) is rejected with an error rather than silently ignored. Human-readable messages and warnings go to stderr, so stdout stays valid JSON.
Deprecation: the per-command --format json form is deprecated in favor of the global --json flag. It still works but prints a warning to stderr and will be removed in a future major version.
Read a Page
confluence read 123456789
confluence read 123456789 --format storage
confluence read 123456789 --format markdown
confluence read "https://your-domain.atlassian.net/wiki/viewpage.action?pageId=123456789"
Use --format storage when you need Confluence's native storage representation, especially for macros and other Confluence-specific markup.
Reading requires content with a storage body. Folders and other bodyless content return Page <id> has no readable body (it may be a folder or an unsupported content type).; use confluence info <id> to inspect their metadata.
Get Page Information
confluence info 123456789
confluence info 123456789 --json
info can inspect folders and other bodyless content because it only reads metadata.
Example JSON shape:
{
"id": "123456789",
"title": "Architecture Overview",
"type": "page",
"status": "current",
"spaceKey": "ENG",
"parentId": "100200300",
"version": 7,
"url": "https://your-domain.atlassian.net/wiki/spaces/ENG/pages/123456789/Architecture+Overview"
}
Search Pages
confluence search "search term"
confluence search "search term" --limit 5
confluence search "search term" --limit 5 --start 5
List or Download Attachments
confluence attachments 123456789
confluence attachments 123456789 --pattern "*.png" --limit 5
confluence attachments 123456789 --pattern "*.png" --download --dest ./downloads
Upload Attachments
confluence attachment-upload 123456789 --file ./report.pdf
confluence attachment-upload 123456789 --file ./a.pdf --file ./b.png --comment "v2"
confluence attachment-upload 123456789 --file ./diagram.png --replace
Delete Attachments
confluence attachment-delete 123456789 998877
confluence attachment-delete 123456789 998877 --yes
Content Properties
confluence property-list 123456789
confluence property-get 123456789 my-key
confluence property-set 123456789 my-key --value '{"color":"#ff0000"}'
confluence property-set 123456789 my-key --file ./property.json
confluence property-delete 123456789 my-key
confluence property-delete 123456789 my-key --yes
confluence comments 123456789
confluence comments 123456789 --location inline --format markdown
confluence comment 123456789 --content "Looks good to me!"
confluence comment 123456789 \
--location inline \
--content "Consider renaming this" \
--inline-selection "foo" \
--inline-original-selection "foo"
confluence comment 123456789 --parent 998877 --content "Agree with this"
confluence comment-delete 998877
Inline comment creation note (Confluence Cloud): Creating inline comments requires editor-generated highlight metadata (matchIndex, lastFetchTime, serializedHighlights, plus the selection text). The public REST API does not provide these fields, so inline creation and inline replies can fail with a 400 unless you supply the full --inline-properties payload captured from the editor. Footer comments and replies are fully supported.
Export a Page with Attachments
confluence export 123456789 --dest ./exports
confluence export 123456789 --format html --file content.html --pattern "*.png"
confluence export 123456789 --skip-attachments
List Spaces
confluence spaces
confluence spaces --limit 2000
confluence spaces --all
List Child Pages
confluence children 123456789
confluence children 123456789 --recursive
confluence children 123456789 --recursive --format tree
confluence children 123456789 --show-id --show-url
confluence children 123456789 --recursive --max-depth 3
confluence children 123456789 --recursive --json > children.json
children --json returns structured metadata for each page, including id, title, type, status, spaceKey, parentId, version, and url. Recursive output also includes depth, and when available, ancestors.
Example recursive JSON item:
{
"pageId": "123456789",
"childCount": 2,
"children": [
{
"id": "200300400",
"title": "Child Page",
"type": "page",
"status": "current",
"spaceKey": "ENG",
"parentId": "123456789",
"version": 4,
"url": "https://your-domain.atlassian.net/wiki/spaces/ENG/pages/200300400/Child+Page",
"depth": 1,
"ancestors": [
{
"id": "123456789",
"type": "page",
"title": "Architecture Overview"
}
]
}
]
}
Find a Page by Title
confluence find "Project Documentation"
confluence find "Project Documentation" --space MYTEAM
Create a New Page
confluence create "My New Page" SPACEKEY --content "**Hello** World!" --format markdown
confluence create "Documentation" SPACEKEY --file ./content.md --format markdown
confluence create "My New Page" SPACEKEY --content "**Hello** World!" --format auto
For create, create-child, update, and comment, --format auto detects the content type:
it preserves content that starts with markup such as <p>...</p> or <ac:structured-macro ...>, and converts plain text or Markdown to Confluence storage XHTML. This is useful for older Confluence Server/Data Center versions that reject bare text in a body.storage.value.
Create a Child Page
confluence create-child "Meeting Notes" 123456789 --content "This is a child page"
confluence create-child "Tech Specs" 123456789 --file ./specs.md --format markdown
Copy Page Tree
confluence copy-tree 123456789 987654321 "Project Docs (Copy)"
confluence copy-tree 123456789 987654321 --max-depth 3
confluence copy-tree 123456789 987654321 --exclude "temp*,test*,*draft*"
confluence copy-tree 123456789 987654321 --delay-ms 150 --copy-suffix " (Backup)"
confluence copy-tree 123456789 987654321 --dry-run
confluence copy-tree 123456789 987654321 --quiet
Notes:
- Preserves the original parent-child hierarchy when copying.
- Continues on errors: failed pages are logged and the copy proceeds.
- Exclude patterns use simple globbing:
* matches any sequence, ? matches any single character, and special regex characters are treated literally.
- Large trees may take time; the CLI applies a small delay between sibling page creations to avoid rate limits (configurable via
--delay-ms).
- Root title suffix defaults to
(Copy); override with --copy-suffix. Child pages keep their original titles.
- Use
--fail-on-error to exit non-zero if any page fails to copy.
Update an Existing Page
confluence update 123456789 --title "A Newer Title for the Page"
confluence update 123456789 --content "Updated page content."
confluence update 123456789 --file ./updated-content.md --format markdown
confluence update 123456789 --title "New Title" --content "And new content"
Title-only updates reuse the target's existing storage body. Folders and other bodyless content cannot be updated this way and return Page <id> has no readable body (it may be a folder or an unsupported content type)..
Move a Page to New Parent
confluence move 123456789 987654321
confluence move 123456789 987654321 --title "Relocated Page"
confluence move "https://domain.atlassian.net/wiki/viewpage.action?pageId=123456789" \
"https://domain.atlassian.net/wiki/viewpage.action?pageId=987654321"
Note: Pages can only be moved within the same Confluence space. Cross-space moves are not supported.
Delete a Page
confluence delete 123456789
confluence delete "https://your-domain.atlassian.net/wiki/viewpage.action?pageId=123456789"
confluence delete 123456789 --yes
Edit Workflow
The edit and update commands work together to create a seamless editing workflow.
confluence edit 123456789 --output ./page-to-edit.xml
vim ./page-to-edit.xml
confluence update 123456789 --file ./page-to-edit.xml --format storage
Only content with a storage body can be exported for editing. Folders and other bodyless content return Page <id> has no readable body (it may be a folder or an unsupported content type)..
Profile Management
confluence profile list
confluence profile use staging
confluence profile add staging
confluence profile add staging --domain "staging.example.com" --auth-type bearer --token "xyz"
confluence profile add agent --domain "company.atlassian.net" --auth-type basic --email "bot@example.com" --token "xyz" --read-only
confluence profile remove staging
confluence --profile staging spaces
Read-Only Mode
Read-only mode blocks all write operations at the CLI level, making it safe to hand the tool to AI agents (Claude Code, Copilot, etc.) without risking accidental edits.
Enable via profile:
confluence init --read-only
confluence profile add agent --domain "company.atlassian.net" --token "xyz" --read-only
Enable via environment variable:
export CONFLUENCE_READ_ONLY=true
When read-only mode is active, any write command (create, create-child, update, delete, move, edit, comment, attachment-upload, attachment-delete, property-set, property-delete, comment-delete, copy-tree) exits with code 1 and prints an error message.
confluence profile list shows a [read-only] badge next to protected profiles.
Raw API Requests
Make arbitrary authenticated requests to any Confluence REST endpoint, modeled after gh api. Useful for endpoints the CLI hasn't wrapped yet (labels, restrictions, groups, audit, v2 API, β¦) without falling back to curl.
Endpoint resolution:
- Relative path (no leading slash) β resolved against the configured
apiPath (the default for most calls).
- Absolute path (leading
/) β bypasses apiPath; resolved against the host. On Confluence Cloud, apiPath is typically /wiki/rest/api, so absolute endpoints must include the /wiki prefix.
- Full URL (
https://β¦) β used as-is, but only when it is same-origin with the configured host. A full URL pointing at a different origin (or an http:// downgrade of an https host) is refused, so your credentials are never sent to an unexpected server.
confluence api content/123456789/label
confluence api /wiki/rest/api/content/123456789/label
confluence api content/123456789/label --input - <<< '[{"name":"reviewed"}]'
confluence api content/123456789/label/reviewed -X DELETE
confluence api content/123456789/restriction
confluence api group
confluence api longtask/123
confluence api /wiki/api/v2/pages -f spaceKey=DEV -f limit=10 -X GET
confluence api group --jq '.results[].name'
confluence api audit -i
confluence api content/123456789/restriction --input ./restrictions.json
confluence api content/123456789/label --input - --silent <<< '[{"name":"approved"}]'
Read-only profiles block write methods (POST, PUT, PATCH, DELETE) while allowing GET and HEAD. --jq requires jq to be installed and available in PATH.
View Usage Statistics
confluence stats
Commands
init | Initialize CLI configuration | --read-only |
read <pageId_or_url> | Read page content | --format <html|text|storage|markdown> |
info <pageId_or_url> | Get page information | --json |
search <query> | Search for pages | --json, --limit <number>, --start <number> |
spaces | List available spaces | --json, --limit <number>, --all |
find <title> | Find a page by its title | --space <spaceKey>, --json |
children <pageId> | List child pages of a page | --recursive, --max-depth <number>, --format <list|tree>, --json, --show-url, --show-id |
create <title> <spaceKey> | Create a new page or folder | --content <string>, --file <path>, --format <auto|storage|html|markdown>, --type <page|folder>, --json |
create-child <title> <parentId> | Create a child page or folder | --content <string>, --file <path>, --format <auto|storage|html|markdown>, --type <page|folder>, --json |
copy-tree <sourcePageId> <targetParentId> [newTitle] | Copy page tree with all children | --max-depth <number>, --exclude <patterns>, --delay-ms <ms>, --copy-suffix <text>, --dry-run, --fail-on-error, --quiet, --json |
update <pageId> | Update a page's title or content | --title <string>, --content <string>, --file <path>, --format <auto|storage|html|markdown>, --json |
move <pageId_or_url> <newParentId_or_url> | Move a page to a new parent location | --title <string>, --json |
delete <pageId_or_url> | Delete a page by ID or URL | --yes, --json |
versions <pageId_or_url> | List historical versions of a page | --json |
version-delete <pageId_or_url> <versionNumber> | Delete a single non-current version of a page | --yes, --json |
versions-purge <pageId_or_url> | Delete every non-current historical version of a page | --yes, --throttle <seconds>, --json |
edit <pageId> | Export page content for editing | --output <file> |
attachments <pageId_or_url> | List or download attachments for a page | --json, --limit <number>, --pattern <glob>, --download, --dest <directory> |
attachment-upload <pageId_or_url> | Upload attachments to a page | --file <path>, --comment <text>, --replace, --minor-edit, --json |
attachment-delete <pageId_or_url> <attachmentId> | Delete an attachment from a page | --yes, --json |
comments <pageId_or_url> | List comments for a page | --format <text|markdown>, --json, --limit <number>, --start <number>, --location <inline|footer|resolved>, --depth <root|all>, --all |
comment <pageId_or_url> | Create a comment on a page | --content <string>, --file <path>, --format <auto|storage|html|markdown>, --parent <commentId>, --location <inline|footer>, --inline-selection <text>, --inline-original-selection <text>, --inline-marker-ref <ref>, --inline-properties <json>, --json |
comment-delete <commentId> | Delete a comment by ID | --yes, --json |
property-list <pageId_or_url> | List all content properties for a page | --json, --limit <number>, --start <number>, --all |
property-get <pageId_or_url> <key> | Get a content property by key | --json |
property-set <pageId_or_url> <key> | Set a content property (create or update) | --value <json>, --file <path>, --json |
property-delete <pageId_or_url> <key> | Delete a content property by key | --yes, --json |
export <pageId_or_url> | Export a page to a directory with its attachments | --format <html|text|markdown>, --dest <directory>, --file <filename>, --attachments-dir <name>, --pattern <glob>, --referenced-only, --skip-attachments |
profile list | List all configuration profiles | |
profile use <name> | Set the active configuration profile | |
profile add <name> | Add a new configuration profile | -d, --domain, -p, --api-path, -a, --auth-type, -e, --email, -t, --token, --protocol, --read-only |
profile remove <name> | Remove a configuration profile | |
api <endpoint> | Make an authenticated API request (relative path uses apiPath; absolute path bypasses it; full URL must be same-origin) | -X, --method <method>, -f, --field <key=value>, -H, --header <key:value>, --input <file>, --jq <expression>, -i, --include, --silent |
convert | Convert between content formats locally (no server required) | --input-file <path>, --output-file <path>, --input-format <markdown|storage|html>, --output-format <markdown|storage|html|text> |
stats | View your usage statistics | |
Global option: --profile <name> β Use a specific profile for any command (overrides CONFLUENCE_PROFILE env var and active profile).
Examples
confluence init
confluence read 123456789
confluence read 123456789 --format html
confluence info 123456789
confluence search "API documentation" --limit 3
confluence spaces
confluence move 123456789 987654321
confluence move 123456789 987654321 --title "New Title"
confluence attachment-upload 123456789 --file ./report.pdf
confluence attachment-delete 123456789 998877 --yes
confluence create "Engineering Docs" MYSPACE --type folder
confluence create-child "Sub-folder" 123456789 --type folder
confluence stats
confluence profile list
confluence profile use staging
confluence --profile staging spaces
confluence api content/123456789/label --jq '.[].name'
confluence convert --input-file doc.md --input-format markdown --output-format storage
echo "# Hello" | confluence convert --input-format markdown --output-format storage
confluence convert -i page.xml -o page.md --input-format storage --output-format markdown
Markdown Marker Conventions
When converting markdown to Confluence storage format (via confluence convert, create, or update), the following paragraph-level markers produce native Confluence macros. Each marker round-trips back to its markdown form when going storage β markdown.
Callout macros β INFO, WARNING, NOTE
A blockquote whose first line is **INFO**, **WARNING**, or **NOTE** becomes the corresponding Confluence macro:
> **INFO**
> Heads up β this is an info box.
> **WARNING**
> Watch out for this.
> **NOTE**
> Side note for the reader.
The reverse direction emits the same > **INFO** / > **WARNING** / > **NOTE** blockquote form, so multi-paragraph bodies round-trip cleanly. The bare [!info] / [!warning] / [!note] shorthand is still accepted on input for backwards compatibility.
A blockquote without one of these markers stays a plain blockquote (<blockquote>β¦</blockquote>) β > β¦ is treated as a quotation, not an alert. Use the markers above when you want a callout.
**TOC** β Table of Contents
A paragraph containing only **TOC** becomes a Confluence Table of Contents macro using the macro's default heading levels:
**TOC**
**ANCHOR: id** β anchor
A paragraph containing only **ANCHOR: my-section** becomes a Confluence anchor macro with the given id:
**ANCHOR: my-section**
**EXPAND: title** β¦ **EXPAND_END** β collapsible expand macro
Wrap a block of content between **EXPAND: title** and **EXPAND_END** markers (each on its own paragraph) to render it as a Confluence expand macro with a collapsible body:
**EXPAND: Show generated code**
```js
const x = 1;
```
**EXPAND_END**
The body may contain any content that is converted earlier in the pipeline (code blocks, tables, callout blockquotes). The reverse direction emits the same **EXPAND: title** / **EXPAND_END** markers so the conversion round-trips.
Inline markdown inside the title (*em*, backtick code, links, ~~strike~~) is stripped at capture time β Confluence's storage normalizer treats macro titles as plain text and will silently truncate or reject HTML in a <ac:parameter>. Title-less expand macros created in the Confluence UI still convert to <details>/<summary> blocks.
[text](#id) β same-page anchor link
A standard markdown link whose href starts with # becomes an ac:link with ac:anchor, rendering as an in-page jump in Confluence:
See [the anchor](#my-section) above.
This works under all three linkStyle modes (smart, wiki, plain) β the anchor-link conversion runs before the general <a href> handling.
Development
git clone https://github.com/pchuri/confluence-cli.git
cd confluence-cli
npm install
npm start -- --help
npm test
npm run lint
Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature)
- Commit your changes (
git commit -m 'Add some amazing feature')
- Push to the branch (
git push origin feature/amazing-feature)
- Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Roadmap
Support & Feedback
π¬ We'd love to hear from you!
Your feedback helps make confluence-cli better for everyone. Here's how you can share your thoughts:
π Found a bug?
π‘ Have a feature idea?
π General feedback?
- Share your experience with a feedback issue
- Rate us on NPM
- Star the repo if you find it useful! β
π€ Want to contribute?
Check out our Contributing Guide - all contributions are welcome!
π Usage Analytics
confluence-cli tracks command usage statistics locally on your machine (in stats.json alongside your config file β see Config file location above). No data is sent to any external server. This includes:
- Command usage counts (success/error)
You can view your stats with confluence stats, or disable tracking by setting: export CONFLUENCE_CLI_ANALYTICS=false
Made with β€οΈ for the Confluence community