Getting started
From purchase to live: one zip, three commands and a script tag. No server to run, no API key to manage, no per-query fee — search runs on the visitor's own device.
1. Purchase and zip
After paying you are redirected to a thank-you page. It shows your licence key and the download link. The key looks like this:
LE-XXXX-XXXX-XXXX-XXXX
Keep the key. There are no accounts and no passwords here; the key is your identity. You will use the same key to download updates. If you lose it, email us and we will find it from your order.
The zip contains:
lightembed-1.0.0.zip
├── model-tr-1.0.0.bin the model, fingerprinted to you
├── lightembed-cli-1.0.0.tgz command-line tool
├── lightembed-client-1.0.0.tgz browser client and search widget
├── LICENCE.txt licence text and your key
└── docs/ an offline copy of this page
2. Install
Nothing is published to the npm registry; you install from inside the zip:
unzip lightembed-1.0.0.zip -d lightembed
cd lightembed
npm install ./lightembed-cli-1.0.0.tgz ./lightembed-client-1.0.0.tgz
This install never touches the network — the packages have no dependencies, and the search engine (WebAssembly) ships inside the CLI package. To check:
npx lightembed inspect ./model-tr-1.0.0.bin
3. Index your content
If you already have a content directory:
npx lightembed index ./content \
--model ./model-tr-1.0.0.bin \
--out ./public/lightembed \
--base-url https://yoursite.com
If all you have is the live site, download it first:
npx lightembed crawl https://yoursite.com/docs/ --out ./content
crawl mirrors the site's URL structure onto disk, so the result
links point at real pages. It obeys robots.txt, fetches serially
with a delay, and exits non-zero if it fetched nothing rather than quietly
leaving you an empty directory.
--content-selector. When indexing HTML it decides which
part of the page counts as content (main, .article,
#content). Get it wrong and the index holds your navigation and
footer instead of your article — search does not "break", it talks nonsense.
That is why a selector matching no file is an error.4. Add search to your page
The ready-made component — one script tag and one element:
<script type="module" src="/lightembed/widget.mjs"></script>
<lightembed-search src="/lightembed" hotkey="cmd+k" placeholder="Search the docs…">
</lightembed-search>
Or drive it yourself:
import { createSearch } from 'lightembed-client';
const search = await createSearch('/lightembed');
// Warm on focus: the download happens while the user types, so the first
// search feels like the tenth.
input.addEventListener('focus', () => search.warm());
const hits = await search.query('how do I get a tax refund', { topK: 5 });
Copy public/lightembed/ to any static host. Nothing in it needs
a server.
What downloads, and when
| Moment | Bytes (gzip) |
|---|---|
| Page load | 8.2 KB — manifest, widget and client |
| Visitor focuses the search box | engine 48 KB + model 2.58 MB + index |
| Every search after that | 0 |
A visitor who never searches pays 8.2 KB. One who does pays once, while typing.
5. Updating
Re-run lightembed index whenever your content changes. When a new
model version is released:
npx lightembed update --key LE-XXXX-XXXX-XXXX-XXXX
npm install ./lightembed-update/lightembed-cli-<new>.tgz
The command downloads the newest release your licence covers and unpacks it
into ./lightembed-update/. Swap in the new model file. Every update
is included for the first 12 months; after that renewing is an optional $10/year,
and if you skip it the version you have keeps working forever.
Whether a model change forces a re-index:
| Model change | Index |
|---|---|
| 1.2.0 → 1.2.1 | stays valid |
| 1.2.0 → 1.3.0 | stays valid |
| 1.2.0 → 2.0.0 | must be rebuilt |
A major version moves the embedding space. Comparing a query embedded in the new space against documents embedded in the old one produces confident, wrong results with no other symptom — so the client refuses to search and tells you to re-index, rather than failing quietly.
Troubleshooting
"index was built with model X but Y is loaded" — the model
file next to the index is not the one that built it. Re-run
lightembed index, or put the right model back.
Results are relevant but the exact term I searched is missing.
If the term lives inside a code block, look at --include-code.
Otherwise the keyword half of search should have caught it; try raising
--lexical-weight (1–2 for sites where
people search part numbers and error codes, 0–0.5 for
sites where they ask questions).
The first search is slow. Call warm() earlier —
on focus, or on hover over the search button.
For anything that stays broken: [email protected]. Within 14 days the refund is no-questions too.