Options
| Option | Default | What it does |
|---|---|---|
enabled | true | Turn the whole module off without removing it. |
endpoint | '/_precog/predict' | Path of the Nitro route that talks to Jev. |
model | unset | Leave it unset. See the model name is a trap. |
provider | unset | 'typesafe' or 'vercel'. Unset, the key decides. |
baseURL | unset | TypeSafe base URL. Point it at a mock in tests. |
mode | 'prefetch' | 'prefetch', 'prerender' or 'auto'. |
thresholds.prefetch | 0.25 | Lowest click probability worth a prefetch. |
thresholds.prerender | 0.6 | Lowest click probability worth a prerender. |
budget.maxPrefetch | 3 | Most URLs prefetched at once. |
budget.maxPrerender | 1 | Most URLs prerendered at once. |
budget.maxCallsPerMinute | 20 | Enforced on the client and on the server. |
budget.maxCallsPerSession | 200 | Hard stop for one visitor. |
maxCandidates | 30 | Links sent per request. Capped at 254 by Jev's choice limit. |
timeoutMs | 1500 | Client deadline. Measured round trips are 340 to 500 ms. |
minIntervalMs | 1200 | Shortest gap between two predictions. |
fallback | 'native' | On failure: 'native' document rules at moderate, or 'none'. |
include | [] | Only these path globs may be speculated. Empty means all. |
exclude | ['/logout', '/signout', '/api/**', '/auth/**', '/cart/**'] | Never speculated. |
cache.ttlSeconds | 60 | How long a prediction stays reusable on the server. |
privacy.sendQuery | false | Send query strings. Off because they carry tokens. |
privacy.sendAnchorText | true | Send link text. |
privacy.sendHistory | true | Send the last five paths. |
privacy.requireConsent | false | Nothing runs until grantConsent(). |
overlay | 'dev' | true, false or 'dev'. When false, nothing ships. |
takeOverNuxtLinkPrefetch | false | Turn off NuxtLink's viewport prefetch, keep interaction. |
documentNavigation | false | Experimental, see below. |
pricing | unset | { inputPerMillion, outputPerMillion } for the overlay's cost line. |
The API key
It never reaches the browser, and there is an e2e test that fails if it ever appears in anything the browser receives.
There are two kinds of key and they are not interchangeable:
| Variable | Kind of key | Goes to |
|---|---|---|
TYPESAFE_API_KEY | TypeSafe | api.typesafe.ai |
AI_GATEWAY_API_KEY | Vercel AI Gateway | ai-gateway.vercel.sh, selected automatically |
NUXT_PRECOG_API_KEY | either | set provider to say which |
A gateway key sent to TypeSafe directly answers 401 Cannot authenticate with the server,
which reads like a bad key rather than the wrong door. If you see that, check which kind you
have before regenerating anything.
The model name is a trap
Leave model unset. advocaat then picks the right one for the service: jev-latest against
TypeSafe, typesafe-ai/jev through the gateway.
Setting it to jev-latest explicitly works directly and breaks the gateway, where a bare
name gets a typesafe-ai/ prefix and typesafe-ai/jev-latest does not exist. The error is
404 Model 'typesafe-ai/jev-latest' not found.
Glob syntax
include and exclude take path globs, matched against the path with the query stripped:
| Glob | Matches |
|---|---|
/logout | exactly /logout |
/blog/* | one segment: /blog/hello, not /blog/2026/hello |
/api/** | any depth: /api/v1/users |
/a? | one character: /a1 |
documentNavigation
With it on, a click on a link the module prerendered bypasses the client router and does a real document navigation, so the browser can hand over the copy it already has. Good for content sites that want an MPA feel; it throws away the SPA's state on every click.
Measured behaviour: the click does leave the router out, and the browser serves the document
from whatever it already has. In a test that gives it a couple of seconds, that was the
prefetch (deliveryType: "navigational-prefetch") rather than a finished prerender. The flag
promises a real document navigation that uses what is already there, not "always instant".