---
title: Tune what the search box returns
description: "Exclude pages from the index, weight document priority, and scope the indexed HTML region without replacing the search backend."
canonical_url: https://usepennington.net/how-to/discovery/search/
sidecar_url: https://usepennington.net/how-to/discovery/search.md
content_hash: sha256:e2e2f7a2e4c8d5bf6f143bf68b831a5ec33fa7d89d849d1f9b07251076aadd9f
tokens: 2359
uid: how-to.discovery.search
reading_time_minutes: 6
---

Guides
# Tune what the search box returns

Exclude pages from the index, weight document priority, and scope the indexed HTML region without replacing the search backend.

 
When the search index is already live but results contain nav or footer noise, a page appears that should be hidden, or relative document weight needs adjusting, the options below tune the index without touching the search client. For how the index is built, sharded, and queried, see [How the search index is built and queried](https://usepennington.net/explanation/discovery/search.md).

 
## Before you begin

 
 - A working Pennington site that serves `/search/en/index.json` (or the default locale code) — the search index entrypoint
 - Pages using `DocSiteFrontMatter` or another `IFrontMatter` implementation (which carries the `Search` default member)
 - The default locale code (from `LocalizationOptions`) — it is the suffix in the index filename
 
 
[examples/DocSiteKitchenSinkExample](https://github.com/usepennington/pennington/tree/main/examples/DocSiteKitchenSinkExample) ships with the DocSite-pinned `#main-content` selector and a `Content/main/hidden.md` fixture demonstrating `search: false`.

 
---

 
## Options

 
### Exclude a markdown page with `search: false`

 
Add `search: false` to the page's front matter. The index builder skips the page entirely while it continues to render at its URL and appear in the sidebar.

 
```yaml
---
title: Internal draft
search: false
---
```

 
```markdown:symbol
---
title: Not in search
description: This page is intentionally excluded from the search index.
sectionLabel: authoring
order: 220
search: false
uid: kitchen-sink.main.hidden
---
  
This page carries `search: false` in its front matter. It still renders
at its URL and still appears in the sidebar, but the search index
JSON does **not** contain it. Open `/search-index-en.json` to verify
— this title and body are absent from the `documents` array.
  
Pair this with `llms: false` on a separate page to carve the opposite
hole in `/llms.txt`.
```

 
### Exclude a Razor `@page` with a metadata sidecar

 
Razor components do not carry YAML front matter, so `RazorPageContentService` loads a sibling `Foo.razor.metadata.yml` file. Place the sidecar next to the component; `search: false` there has the same effect as in a markdown page's front matter.

 
```yaml
title: Internal Tools
search: false
```

 
### Set the default document priority

 
`SearchIndexOptions.DefaultPriority` (default `5`) is the baseline weight every document starts from — `p` is a linear multiplier on a result's score, so a document with twice the priority needs only half the term relevance to tie. Raise it for sites whose content should outrank neighbors; lower it for auxiliary content. `AreaPriorities` and `PrefixPriorities` (below) override it per content area and per URL prefix; see [Pennington.Search.SearchIndexOptions](https://usepennington.net/reference/api/search-index-options.md) for the shipped defaults.

 
Under `AddDocSite` this property is reachable via the `ConfigurePennington` escape hatch (`ConfigurePennington = penn => penn.SearchIndex.DefaultPriority = …`), so this adjustment does not require dropping down to bare `AddPennington`.

 
### Drop a URL territory below prose with a prefix priority

 
To rank a whole URL subtree below comparable prose — generated API reference is the usual case, where dozens of type pages repeat a term and bury the article that explains it — register the prefix in `SearchIndexOptions.PrefixPriorities`. The longest matching prefix wins, and its value *replaces* the area priority rather than stacking, so the subtree drops to an absolute low `p` even inside a boosted area.

 
```csharp
services.AddDocSite(() => new DocSiteOptions
{
    SiteTitle = "My Docs",
    SiteDescription = "Project documentation",
    ConfigurePennington = penn =>
        penn.SearchIndex.PrefixPriorities["/imagesharp/api/"] = 3,
});
```

 
`AddApiReference` registers each reference tree's route prefix here automatically at priority `3`; set `ApiReferenceRegistrationOptions.SearchPriority` to choose a different value (`AddApiReference(o => o.SearchPriority = 2)`).

 
### Override the content selector on DocSite

 
The selector scopes which HTML element's text becomes the search body — and the same element drives llms.txt sidecars and the build-time link audit, so chrome is stripped once. `DocSiteOptions.ContentSelector` defaults to `#main-content` to match the stock `MainLayout.razor`; set it after replacing the layout or to widen the indexed region. See [What the DocSite and BlogSite templates wire for you](https://usepennington.net/explanation/positioning/docsite-positioning.md) for the cases that require dropping to bare `AddPennington`.

 
```csharp
services.AddDocSite(() => new DocSiteOptions
{
    SiteTitle = "My Docs",
    SiteDescription = "Project documentation",
    ContentSelector = "article.prose",
});
```

 
### Add query synonyms

 
To make a term also match alternates, set `SearchIndexOptions.Synonyms`. Keys and values are stemmed at build time and shipped in the entrypoint, so authors write natural words; the client expands query terms as it searches.

 
```csharp
services.AddDocSite(() => new DocSiteOptions
{
    SiteTitle = "My Docs",
    SiteDescription = "Project documentation",
    ConfigurePennington = penn =>
        penn.SearchIndex.Synonyms = new Dictionary<string, string[]>
        {
            ["config"] = ["configuration", "settings"],
        },
});
```

 
### Choose which facets the client can filter by

 
`SearchIndexOptions.Facets` selects the dimensions surfaced as filter chips: content area (the first URL segment after any locale prefix), section, and tags. Only area is on by default — it stays a short, stable list that reads well as chips. Section and tag vocabularies grow large enough to bury the filter bar, so opt into them when the extra filtering is worth the chips.

 
```csharp
services.AddDocSite(() => new DocSiteOptions
{
    SiteTitle = "My Docs",
    SiteDescription = "Project documentation",
    ConfigurePennington = penn =>
        penn.SearchIndex.Facets = SearchFacetField.Area | SearchFacetField.Section | SearchFacetField.Tags,
});
```

 
---

 
## Result

 
The build emits the index under `/search/{locale}/`: an `index.json` entrypoint with the document table, facet labels, and ranking stats, plus `t-*.json` term shards and `f-*.json` per-page fragments. A document-table row in the entrypoint, after the knobs above are applied:

 
```json
{
  "u": "/how-to/configuration/search/",
  "t": "Tune what the search box returns",
  "l": 142,
  "p": 10,
  "f": { "section": [0], "tag": [2, 5], "area": [1] }
}
```

 
The page body lives in its fragment (`f-{docId}.json`), fetched only when the page appears in results. Pages with `search: false` are absent from the table; each row's `p` is `DefaultPriority`, overridden by any matching `AreaPriorities` or `PrefixPriorities` entry.

 
## Verify

 
 - Run `dotnet run` and fetch `/search/{locale}/index.json`. The excluded page is absent from the `docs` table
 - Add a second locale and observe one index tree per locale (`/search/en/index.json`, `/search/fr/index.json`). Registered-but-empty locales return a valid entrypoint with an empty `docs` array
 - Fetch the matching `/search/{locale}/f-{docId}.json` and confirm its `body` contains only the scoped element's text (no header / sidebar / footer noise)
 - After raising `DefaultPriority` (or registering an `AreaPriorities` / `PrefixPriorities` entry), fetch `index.json` and confirm the affected rows carry the new value in their `p` field
 - After adding a synonym, fetch `index.json` and confirm the stemmed synonym map carries the entry; in the modal, query the key term and confirm pages that mention only the alternate now appear
 - After enabling the section and tag facets, fetch `index.json` and confirm rows carry `section` and `tag` ids in their `f` object; in the modal, confirm the matching filter chips appear above the results
 
 
## Related

 
 - How-to: [Add the search modal to a non-DocSite site](https://usepennington.net/how-to/discovery/search-on-a-bare-host.md) — surface this index in a search UI on a bare host
 - Reference: [Front matter key reference](https://usepennington.net/reference/front-matter/keys.md)
 - Reference: [SearchIndexOptions](https://usepennington.net/reference/api/search-index-options.md) — the knobs this how-to touches; see also [HighlightingOptions](https://usepennington.net/reference/api/highlighting-options.md), [LlmsTxtOptions](https://usepennington.net/reference/api/llms-txt-options.md), and [OutputOptions](https://usepennington.net/reference/api/output-options.md)
 - Background: [How the search index is built and queried](https://usepennington.net/explanation/discovery/search.md)
 - Background: [What the DocSite and BlogSite templates wire for you](https://usepennington.net/explanation/positioning/docsite-positioning.md)
 - How-to: [Make the site discoverable to LLM crawlers](https://usepennington.net/how-to/feeds/llms-txt.md)
 
 
[Previous
                
                Serve docs and a blog from separate content roots](https://usepennington.net/how-to/discovery/multiple-sources.md)[Next
                    
                Add the search modal to a non-DocSite site](https://usepennington.net/how-to/discovery/search-on-a-bare-host.md)