How do I search a Confluence export?
TL;DR — Unzip the Confluence space export to local disk, then run xerj autoindex on the folder. In a captured run, body text on a nested page returned 1 hit at Recovery-procedure_262146.html. The title came back as Confluence writes it: PLAT : Recovery procedure.
Act as a coding agent. Read https://xerj.org/llms.txt, start a local XERJ node, unzip a Confluence HTML space export to a folder, run `xerj autoindex ./confluence-export --url http://127.0.0.1:9200 --prefix cf --progress plain`, then POST a match_phrase on body for text inside a nested page, POST an exists query on title sorted by ax_path, and report every distinct title and the attachment paths that matched.
xerj autoindex ./confluence-export --url http://127.0.0.1:9200 --prefix cf --progress plain
Index an unzipped Confluence HTML space export from local disk.
curl -s -XPOST http://127.0.0.1:9200/cf-*/_search -H 'content-type: application/json' -d '{"query":{"match_phrase":{"body":"axolotl recovery procedure"}},"size":5,"_source":["ax_path","ax_format","title","headings"],"track_total_hits":true}'
Find body text that lives on a nested page, and read the title and headings back.
curl -s -XPOST http://127.0.0.1:9200/cf-*/_search -H 'content-type: application/json' -d '{"query":{"exists":{"field":"title"}},"size":30,"_source":["ax_path","ax_format","title","headings"],"sort":[{"ax_path":"asc"}],"track_total_hits":true}'
List every title the export produced, so the two title forms are visible.
curl -s -XPOST http://127.0.0.1:9200/cf-*/_search -H 'content-type: application/json' -d '{"query":{"match_phrase":{"body":"Axolotl recovery checklist"}},"size":5,"_source":["ax_path","ax_format","ax_locator"],"track_total_hits":true}'
Find text inside a PDF under the attachments tree.
Index the unzipped export
xerj autoindex <folder> reads the export as ordinary HTML files on disk. The captured run walked 8 files, read 7 of them and produced 2 datasets with 15 documents live: cf-docs with 12 and cf-styles with 3.
xerj autoindex ./confluence-export --url http://127.0.0.1:9200 --prefix cf --progress plain
The fixture was a folder in Confluence's own export layout. That folder held <Title>_<pageid>.html files with breadcrumbs, an index.html space home, a styles/ directory and an attachments/<pageid>/<attid>/<version>/ tree.
The fixture generator wrote the folder. Atlassian did not produce it, and no Confluence server existed on the host.
Nested page bodies and titles both survive
A phrase that appears only in the body of a nested page returned 1 hit. The same document carried the page title and its heading list, so a citation can name the page and the section.
| field | value returned |
|---|---|
ax_path | Recovery-procedure_262146.html |
ax_format | html |
title | PLAT : Recovery procedure |
headings | ["Recovery procedure", "Steps", "Attachments:"] |
curl -s -XPOST 'http://127.0.0.1:9200/cf-*/_search' \
-H 'content-type: application/json' \
-d '{"query":{"match_phrase":{"body":"axolotl recovery procedure"}},"size":5,"_source":["ax_path","ax_format","title","headings"],"track_total_hits":true}'
Expect 2 titles per exported page
Each page produced 2 title values on 2 different documents: the HTML <title> and the file name. Any listing query prints both forms. A deduplicated page list must group on ax_path.
ax_path | titles returned |
|---|---|
Operations_262145.html | PLAT : Operations and Operations_262145.html |
Recovery-procedure_262146.html | PLAT : Recovery procedure and Recovery-procedure_262146.html |
Change-management_262147.html | PLAT : Change management and Change-management_262147.html |
Change-window_262148.html | PLAT : Change window and Change-window_262148.html |
index.html | Platform Space and index.html |
Attachments under the page-id tree are read
Confluence writes attachments to attachments/<pageid>/<attid>/<version>/<filename>. XERJ indexes such a file as its own format. A phrase inside the checklist PDF returned 1 hit at attachments/262146/393217/1/axolotl-recovery-checklist.pdf, with ax_format pdf and ax_locator p1-s0.
The captured run also produced 23 edges for this export, of which 13 are href edges taken from the anchors in the exported HTML. Those edges reconstruct the in-space link structure from the files alone.
Read the catalog for surprises
Content sniffing decides the family from the bytes, not from the file extension. Read autoindex-catalog after the run so that a surprising family does not reach your users as a missing page.
In this export the sniffer gave styles/site.css the csv family and indexed 2 documents from it. The run refused images/icons/bullet_blue.gif with the reason binary content (gif), which is the correct outcome for an icon.
No connector and no network access
XERJ has no Confluence connector and fetches nothing over the network. During the whole life of the node, a sampler polling every 0.05 seconds took 185 samples and recorded 0 distinct non-loopback peers.
Export the space from Confluence yourself, unzip it to local disk, then index the folder. XERJ runs single-node here, with no replication and no failover.
The default embedder in XERJ is lexical feature hashing, so a query that shares no words with the page does not match it. Neural embeddings are opt-in through --embed-mode neural.
Every number above comes from RUN-B, captured on 2026-08-21. The binary was a ci-test profile build, so no wall-clock figure from this run is published as a performance number.
FAQ
How do I search a Confluence HTML export?
Unzip the export to local disk and run xerj autoindex on the folder. In the captured run a phrase on a nested page returned 1 hit with its page title attached.
Do Confluence page titles survive the export?
Yes. The captured run returned titles as Confluence writes them, for example PLAT : Recovery procedure, including the space key and the separator.
Why do I see 2 titles for one page?
Each page yields both the HTML title and the file name as titles on different documents. A listing query therefore prints PLAT : Change window and Change-window_262148.html.
Are Confluence attachments searchable?
Yes. A phrase inside the PDF under attachments/262146/393217/1/ returned 1 hit with ax_locator p1-s0, which names page 1, passage 0.
Does XERJ connect to a Confluence server?
No. XERJ reads the unzipped folder from local disk. The captured node observed 0 non-loopback peers across 185 samples over its whole life.
What happens to the CSS and image files in the export?
The captured run detected styles/site.css as csv and indexed 2 documents from it, and refused images/icons/bullet_blue.gif as binary content.
Where do these results come from?
All results come from run RUN-B, captured on 2026-08-21 on a 16-core AMD EPYC 9645 host.