nuxt-precog

Your links, loaded before the click. Click prediction with TypeSafe Jev, wired into Speculation Rules and Nuxt preloading.
759 8
Install
npm install nuxt-precog
Latest Version:0.3.1
Vue:3
License:MIT
Last Updated:Sep 20, 2026
Links: GitHub  ·  npm
Maintainer: oskar.lebuda

precog

nuxt-precog next-precog license

Documentation


Asks TypeSafe Jev which link a visitor is about to click, then warms exactly that navigation with the Speculation Rules API and your framework's own preloading. It comes with an overlay that draws the probabilities on top of the page, so you can watch it guess.

Not a general prefetcher. Nuxt and Next already prefetch every link that enters the viewport. This one tries to prefetch three links instead of thirty, and to start before the hover.

Package For
nuxt-precog Nuxt 3 and 4
next-precog Next.js App Router
precog-core the framework-free half, if you want to write another adapter

Quickstart

Nuxt

npx nuxt module add nuxt-precog

Next.js, App Router:

npm install next-precog
// app/api/precog/route.ts
import { createPrecogHandler } from "next-precog/server";
export const POST = createPrecogHandler();
// app/layout.tsx
import { PrecogProvider } from "next-precog";
// wrap children in <PrecogProvider>

Either way, set a key from console.typesafe.ai:

# .env
TYPESAFE_API_KEY="your-api-key"

A Vercel AI Gateway key goes in AI_GATEWAY_API_KEY instead; the two are not interchangeable.

The full setup for each, including the one step in Next that actually matters, is in the documentation.

What it actually buys you

Eight scripted sessions per arm, six navigations each, real Chrome against a production build, throttled to 250 ms latency and 2000 kbit/s, predictions from Jev. Method in the benchmark page; reproduce with pnpm bench.

arm off native precog
navigation median 147 ms 145 ms 68 ms
navigation p95 404 ms 397 ms 395 ms
hit rate n/a n/a 29%
top guess correct n/a n/a 17%
wasted kB / session 6.9 6.9 10.3
jev calls / session 0 0 14.9
jev latency p50 / p95 n/a n/a 372 / 622 ms

How it works

One request per prediction, three questions, evaluated in parallel:

Key Type Asked
next choice over the candidate ids plus none Which of these links will the visitor click next, if any?
soon score over four levels How soon will the visitor open another page?
exit yes/no Will the visitor leave the site entirely instead?
sequenceDiagram
    participant B as Browser
    participant N as Your Nitro server
    participant J as TypeSafe Jev

    Note over B: collect candidate links,<br/>watch scroll and pointer
    B->>N: POST state, one request in flight
    N->>N: validate, rate limit, look in cache
    N->>J: one request, three questions
    J-->>N: next, soon, exit
    N-->>B: ids and probabilities
    Note over B: policy: thresholds, budgets, guards
    B->>B: effector A, speculation rules, for document navigations
    B->>B: effector B, Nuxt preloading, for in-app navigations

The short version of the important part: a client-router click is not a document navigation, so speculation rules do nothing for it. That is measured in packages/nuxt/e2e/spa-vs-document.spec.ts. The in-app win comes from warming the payload of the pages the model picked, which only exists for routes rendered ahead of time.

:mag: The full walk-through

Limitations

  • Speculation rules are Chromium only. Elsewhere, prefetch falls back to <link rel="prefetch"> and prerender is skipped. Nuxt preloading works everywhere.
  • Payload preloading needs a payload, which means prerendered routes with experimental.payloadExtraction. On a purely server-rendered route the win is small.
  • Prerendering runs the page's JavaScript. Analytics fire, onMounted fetches run. This is why mode is 'prefetch' by default.
  • It costs money per prediction. Tune minIntervalMs, cache.ttlSeconds and the budgets before pointing it at real traffic.
  • Jev is in early access. Every failure path returns an empty prediction and the page is untouched.

Privacy

The module sends page context and part of a browsing path to a third party. It sends no identifier of any kind, no full URLs, and never the API key. The privacy page lists exactly what goes over the wire and how to gate it behind consent.

Development

pnpm install
pnpm dev              # the Nuxt playground, needs a key in packages/nuxt/playground/.env
pnpm check            # lint, typecheck, unit tests
pnpm test:e2e         # builds everything and drives real Chrome
pnpm bench            # writes bench/results/bench.md
pnpm docs:dev         # the documentation site
pnpm client:dev       # the DevTools tab on its own, while working on it

pnpm dev:prepare builds the DevTools tab client into dist/client, which pnpm dev runs first. To work on the tab itself, start pnpm client:dev and run the playground with PRECOG_DEVTOOLS_LOCAL=1, which proxies the tab to that dev server instead.

The unit suite never touches the network: test/mock-typesafe.ts is a small stand-in for the System One API. The live smoke test is skipped unless TYPESAFE_API_KEY is set.

One note that did not fit on the site: decisions, the running log of why things are the way they are.

Thanks

  • TypeSafe for Jev. It answers typed questions in about 100 ms, which is the only reason guessing a click before it happens is possible at all. A model that writes text would arrive long after the visitor had already clicked.
  • advocaat by pi0, the small typed client this talks to Jev through. Its source is also where test/mock-typesafe.ts took the wire format from, which is what lets the whole test suite run offline.

License

MIT

Related Packages

@mono-lit/nuxt-pre-fetch

Nitro-side API prefetching for Nuxt apps with ssr: false — usePreFetch() reuses...

292 0
@privyid/nuxt-csrf

Module CSRF for NUXT

26,088 9
mixpanel-nuxt

Mixpanel module for Nuxt

19,992 7
nuxt-radash

radash for Nuxt

10,601 20
gsap-nuxt-module

GSAP integration for Nuxt.

8,932 37

Version History

Version Released Vue License
0.3.1 ^3.0 MIT
0.3.0 ^3.0 MIT
0.2.0 ^3.0 MIT
0.1.0 ^3.0 MIT