<!-- generated by build_articles.py — edit content/answers/search-confluence-html-export.md instead -->
---
title: "How do I search a Confluence export?"
canonical: "https://xerj.org/answers/search-confluence-html-export"
updated: "2026-08-21"
source: "content/answers/search-confluence-html-export.md"
---

# 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`.

## Agent prompt

```text
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.
```

## Commands

### Command 1

Note: Index an unzipped Confluence HTML space export from local disk.

```sh
xerj autoindex ./confluence-export --url http://127.0.0.1:9200 --prefix cf --progress plain
```

### Command 2

Note: Find body text that lives on a nested page, and read the title and headings back.

```sh
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}'
```

### Command 3

Note: List every title the export produced, so the two title forms are visible.

```sh
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}'
```

### Command 4

Note: Find text inside a PDF under the attachments tree.

```sh
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}'
```

## 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.

```sh
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:"]` |

```sh
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.

## Related

- [I saved a help-center as HTML. How do I search it like the real help-center search?](/answers/search-html-export)
- [How should an agent figure out what's in a messy data folder before searching?](/answers/catalog-files-with-autoindex-map)
- [Can ChatGPT search a folder on my laptop, or do I need something else?](/answers/give-chatgpt-claude-local-file-access)
