# Sosl With Clauses

> Guides composing SOSL FIND queries with result-scoping or result-shaping WITH clauses, covering clause order, supported objects, field-type limits, and API-version floors.

- Skill: `pranavnagrecha/sosl-with-clauses` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds add pranavnagrecha/sosl-with-clauses`
- Raw SKILL.md: https://api.skillmd.com/api/skills/pranavnagrecha/sosl-with-clauses/raw
- Safety review: PASS (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Data & Analytics, SQL & Databases
- Tags: Data Category, Find Query, Highlight, Network, Salesforce, Snippet, Sosl, With Clause
- Author: PranavNagrecha (https://skillmd.com/u/pranavnagrecha)
- Updated: 2026-08-22
- Page: https://skillmd.com/skills/pranavnagrecha/sosl-with-clauses

---


# SOSL WITH Clauses

This skill activates when a practitioner is composing or reviewing a SOSL `FIND` query and needs one of the optional `WITH` clauses that either **scope** which records match (`DivisionFilter`, `DATA CATEGORY`, `NETWORK`, `PricebookId`) or **shape** how matches come back (`SNIPPET`, `HIGHLIGHT`, `METADATA`, `SPELL_CORRECTION`). The clauses are standard, released SOSL syntax documented in the SOQL and SOSL Reference — the docs do not stamp them with a GA/Beta/Pilot label, so treat them as core syntax and do not assert a maturity level the docs don't state.

---

## Before Starting

Gather this context before working on a SOSL WITH clause:

- **Know your target objects.** Every WITH clause is gated to specific entities. `SNIPPET`, `HIGHLIGHT`, and `DATA CATEGORY` do nothing on objects they don't support, and there is no error — the clause is just ignored. Confirm the object list (see the clause table) before promising the feature will work.
- **Know your API version.** `DATA CATEGORY` needs 18.0+, `SNIPPET` needs 32.0+, `HIGHLIGHT` needs 39.0+ (40.0+ for custom fields/objects), and `SPELL_CORRECTION` needs 40.0+. A query running below the floor silently loses the clause. Check the `apiVersion` of the class, LWC, or REST call that issues the search.
- **The most common wrong assumption:** that WITH clauses can appear in any order, like SOQL `WHERE`/`ORDER BY`. They can't — SOSL enforces a **single fixed order** and rejects the query otherwise. See Core Concepts.
- **Wildcards suppress shaping.** If the `FIND` term contains `*` or `?`, `SNIPPET` excerpts and `HIGHLIGHT` markup are not generated. Decide up front whether the search needs wildcards or presentation, because you often can't have both.

---

## Core Concepts

### Scoping clauses vs shaping clauses

The eight WITH clauses fall into two jobs:

- **Result-scoping** — narrows *which* records are returned before they reach you: `WITH DivisionFilter` (Division field), `WITH DATA CATEGORY` (Knowledge/Question categories), `WITH NETWORK` (Experience Cloud site), `WITH PricebookId` (a single price book for `Product2`).
- **Result-shaping** — changes *how* the matches are represented: `WITH SNIPPET` (contextual excerpt text), `WITH HIGHLIGHT` (`<mark>`-delimited matched terms), `WITH METADATA` (label metadata in the response), and `WITH SPELL_CORRECTION` (whether a mis-typed term is auto-corrected before matching — it straddles both jobs).

### The clause order is fixed

After the required `FIND ... RETURNING ...`, WITH clauses must appear in exactly this order, then `LIMIT`, then `UPDATE`:

```
FIND {term} [IN SearchGroup] RETURNING FieldSpec
  WITH DivisionFilter
  WITH DATA CATEGORY DataCategorySpec
  WITH SNIPPET (target_length=n)
  WITH NETWORK NetworkIdSpec
  WITH PricebookId
  WITH METADATA
  WITH HIGHLIGHT
  WITH SPELL_CORRECTION = true|false
  LIMIT n
  UPDATE TRACKING, VIEWSTAT
```

You include only the clauses you need, but the ones you include must stay in this relative sequence. `OFFSET` and per-object `WHERE` live **inside** the `RETURNING` field spec, not among the WITH clauses.

### Each clause is object- and version-gated

| WITH clause | Job | Applies to | API floor | Key limit |
|---|---|---|---|---|
| `DivisionFilter` | scope | Orgs using the Divisions feature | — | Accepts a division name or ID; pre-filters all results by the Division field |
| `DATA CATEGORY` | scope | `KnowledgeArticleVersion` / `__kav` types, `Question` | 18.0 | Requires `RETURNING` + a `WHERE PublishStatus=...`; operators `AT` / `ABOVE` / `BELOW` / `ABOVE_OR_BELOW`; multiple specs combine with `AND` only |
| `SNIPPET (target_length=n)` | shape | `Case`, `CaseComment`, `FeedItem`, `FeedComment`, `Idea`, `IdeaComment`, `KnowledgeArticleVersion` | 32.0 | `n` = 50–1,000 (default 300); no snippet with wildcards; only when ≤20 results per page |
| `NETWORK NetworkIdSpec` | scope | Experience Cloud `User` and feeds (`FeedItem`/`FeedComment`) | — | `WITH NETWORK = 'id'` or `IN ('id1','id2')`; `'000...0'` for internal; can't mix scoped and unscoped in one query |
| `PricebookId` | scope | `Product2` only | — | Filters product results to one price book |
| `METADATA` | shape | Search response envelope | — | No metadata (e.g. labels) returned unless the clause is present |
| `HIGHLIGHT` | shape | auto number, email, text, text area, long text area fields | 39.0 (40.0 for custom) | Max 25 records highlighted per entity per query; `<mark>` delimiters; no highlight with wildcards |
| `SPELL_CORRECTION = true\|false` | shape | Searches that support spell correction | 40.0 | Defaults to `true`; only affects supported searches |

---

## Common Patterns

### Knowledge search UI (DATA CATEGORY + SNIPPET + HIGHLIGHT)

**When to use:** a support console or Experience Cloud help center that searches published Knowledge articles, shows a short contextual excerpt, and bolds the matched terms.

**How it works:** `RETURNING KnowledgeArticleVersion (Id, Title, ... WHERE PublishStatus='online' AND Language='en_US')`, then `WITH DATA CATEGORY` to constrain to a category branch, then `WITH SNIPPET (target_length=n)` for the excerpt, then `WITH HIGHLIGHT` for the `<mark>` markup. Keep them in that order.

**Why not the alternative:** building excerpts and highlight markup in Apex after a plain SOSL means re-implementing the search engine's tokenizer and relevance — the platform already computes the best-matching passage.

### Experience Cloud site-scoped search (NETWORK)

**When to use:** a community/site search that must return only users and feed posts belonging to one Experience Cloud site, not the whole org.

**How it works:** `WITH NETWORK = 'siteNetworkId'` (or `IN (...)` for several sites). It scopes `User` and feed results; for other objects the filter is ignored and results span all sites plus internal data.

**Why not the alternative:** filtering feed results in Apex after an unscoped SOSL leaks cross-site content into memory and risks showing one site's posts in another. Let SOSL scope at the source — and never mix a scoped and an unscoped search in the same statement.

### Product search within a price book (PricebookId)

**When to use:** a product-lookup that should only surface products present on a specific price book.

**How it works:** `FIND {term} RETURNING Product2 (Id, Name) WITH PricebookId`. It restricts the `Product2` matches to that price book.

---

## Decision Guidance

| Situation | Recommended clause | Reason |
|---|---|---|
| Show an excerpt of the matched text | `WITH SNIPPET (target_length=n)` | Platform-computed contextual passage; 50–1,000 chars |
| Bold/emphasize the matched terms | `WITH HIGHLIGHT` | Returns `<mark>`-wrapped terms on supported field types |
| Restrict Knowledge/Question by category tree | `WITH DATA CATEGORY ... AT/ABOVE/BELOW` | The only category filter for search; needs `WHERE PublishStatus` |
| Limit results to one Experience Cloud site | `WITH NETWORK` | Scopes `User` and feed results to that site |
| Limit product hits to one price book | `WITH PricebookId` | `Product2`-only price-book scope |
| User keeps mistyping the term | leave `SPELL_CORRECTION` default (`true`) | Auto-correction is on unless you disable it |
| You need exact-match, no auto-correct | `WITH SPELL_CORRECTION = false` | Turns off correction for supported searches |
| Term contains `*`/`?` wildcard | do **not** rely on `SNIPPET`/`HIGHLIGHT` | Neither is generated for wildcard terms |

---

## Recommended Workflow

1. **Classify the need** — is it scoping (which records) or shaping (how they look)? Pick the specific clause(s) from the table; a Knowledge search often needs three.
2. **Verify object + field-type support** — confirm each chosen clause actually applies to the objects and (for `HIGHLIGHT`) the field types in your `RETURNING` list; drop clauses the objects don't support.
3. **Check the API-version floor** — confirm the issuing class/LWC/REST call runs at or above each clause's minimum (18.0 / 32.0 / 39.0 / 40.0); bump the `apiVersion` if needed.
4. **Assemble in the fixed order** — write the clauses in canonical sequence (DivisionFilter → DATA CATEGORY → SNIPPET → NETWORK → PricebookId → METADATA → HIGHLIGHT → SPELL_CORRECTION), with `RETURNING`-internal `WHERE`/`OFFSET` in place and `LIMIT` after the WITH block.
5. **Validate wildcard and required-clause rules** — if the term has `*`/`?`, don't expect snippet/highlight output; if using `DATA CATEGORY`, ensure `RETURNING` + `WHERE PublishStatus` are present. Run `scripts/check_sosl_with_clauses.py` against the query.
6. **Test on real data** — snippets only appear at ≤20 results per page and highlighting caps at 25 records per entity; run the query and confirm the shaping actually renders before wiring the UI.

---

## Review Checklist

Run through these before marking a SOSL WITH-clause query complete:

- [ ] WITH clauses appear in the fixed canonical order; `LIMIT`/`UPDATE` follow them
- [ ] Every clause's target objects support it (no `SNIPPET`/`HIGHLIGHT`/`DATA CATEGORY` on unsupported entities)
- [ ] The issuing context's API version meets each clause's floor (18.0 / 32.0 / 39.0 / 40.0)
- [ ] `SNIPPET` `target_length` is within 50–1,000; a bad value silently falls back to 300
- [ ] `HIGHLIGHT` fields are auto number / email / text / text area / long text area only
- [ ] `DATA CATEGORY` query includes `RETURNING` and `WHERE PublishStatus=...`; multiple specs joined with `AND` only
- [ ] `NETWORK` query does not mix scoped and unscoped searches; non-user/feed objects aren't assumed to be filtered
- [ ] Wildcard terms don't rely on `SNIPPET`/`HIGHLIGHT` output

---

## Salesforce-Specific Gotchas

Non-obvious platform behaviors that cause real production problems:

1. **Clause order is enforced** — SOSL rejects WITH clauses that appear out of the fixed sequence, even though each clause is individually valid. This surprises anyone used to reordering SOQL clauses freely.
2. **Snippets and highlights vanish with wildcards** — add a `*` to the `FIND` term and the excerpt/`<mark>` markup silently disappears; the query still runs and returns rows, just without shaping.
3. **`NETWORK` only scopes users and feeds** — for any other object, the site filter is ignored and results span all sites plus internal data, which can leak cross-site content if you assumed it filtered everything.

---

## Output Artifacts

| Artifact | Description |
|---|---|
| Ordered SOSL `FIND` query | A `FIND ... RETURNING ...` statement with WITH clauses in canonical order |
| `scripts/check_sosl_with_clauses.py` output | Lint findings on clause order, `SNIPPET` range, `SPELL_CORRECTION` value, and wildcard/required-clause rules |
| `templates/sosl-with-clauses-template.md` | A fill-in worksheet + ordered clause skeleton to assemble the query |

---

## Related Skills

- `data/sosl-search-patterns` — base SOSL mechanics: SOSL-vs-SOQL choice, `FIND`/`IN`/`RETURNING`, search groups, and injection-safe `Search.query`. Start there for the query itself; use *this* skill for the WITH clauses layered on top.
- `data/sosl-search-result-limits` — how many rows SOSL returns per object and overall; pair with `LIMIT` when your WITH-clause query returns too much.
- `data/knowledge-article-import` — populating the `KnowledgeArticleVersion` and data-category structures that `WITH DATA CATEGORY` filters against.

