Coruve

Install

Installing the tracker

The script snippet, what the integrity hash and crossorigin attribute actually do, where the snippet goes on any platform, and how to handle your keys.

The script snippet

One tag before </head>. It is the supported install method, and it works the same everywhere.

Paste this before </head>

Your project's Settings page has this snippet with your real Project ID already filled in. It loads the tracker asynchronously, so it never blocks rendering, and it starts capturing page views the moment it runs — version 1.5.0 is 19.9 KB of JavaScript, 7.3 KB over the wire gzipped.

index.html
<script>
  !function(){var t=window._CORUVE=window._CORUVE||[];if(t.invoked)return void console.error("Coruve snippet included twice.");t.invoked=!0,t.methods=["init","track","identify"],t.factory=function(e){return function(){var n=Array.prototype.slice.call(arguments);return n.unshift(e),t.push(n),t}};for(var e=0;e<t.methods.length;e++){var n=t.methods[e];t[n]=t.factory(n)}var i=document.createElement("script");i.type="text/javascript",i.async=!0,i.src="https://coruve.com/tracker.v1.5.0.min.js",i.integrity="sha384-WKIaYR7qF3TaP1l+q51N8KKL+jKLrm8qfcBV93AwFFLoXuV16WIyAngODrA40nd/",i.crossOrigin="anonymous";var r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(i,r)}();
  _CORUVE.init("proj_YOUR_ID", { apiHost: "https://ingest.coruve.com" });
</script>
The snippet creates the _CORUVE queue synchronously, so init, track and identify can be called immediately — anything queued before the tracker file loads is replayed once it does, and the same three methods keep working after it loads. Nothing is lost to a slow network, and nothing changes under your code when the file arrives.

What integrity and crossorigin do

The snippet points at a versioned file — tracker.v1.5.0.min.js — and pins it with a sha384 subresource-integrity hash. Your browser hashes the bytes it downloaded and refuses to run the script if the hash does not match, so installing Coruve is not a promise from us that the file will never change; it is arithmetic your browser checks on every load. Because a versioned URL can never change, it is also served immutable and cached for a year, and a new tracker release writes a new file rather than altering the one you installed. The crossorigin="anonymous" attribute is not decoration: on a cross-origin script the browser will not check integrity at all without CORS, so dropping it stops the script from running.

AttributeValueWhy it is there
src/tracker.v1.5.0.min.jsA version-pinned, immutable file. Upgrades happen when you edit the snippet, never under you.
integritysha384-…The exact hash of that file. The browser verifies the download before executing a line of it.
crossoriginanonymousRequired for the integrity check on a cross-origin script. Without it the request is refused outright.

Older installs keep working

Snippets installed before version pinning point at the unversioned /tracker.min.js, which is still built and still served from the same URL. That file deliberately carries no integrity hash: its whole contract is that it changes when we ship, and a pinned hash on a mutable file is a customer site that breaks on our next deploy. If you want the pinned bytes and the year-long cache, replace your snippet with the one on your Settings page.

Integration guides

Where the snippet goes on the platforms people ask about most — and an honest note about what does not exist yet.

Every platform, one snippet

The snippet above works on every platform today. Anywhere you can add a line of HTML to the <head> of your pages, Coruve installs — a template file, a theme’s header include, a site builder’s custom-code panel, or your framework’s document component. There is no platform where a different install method is required, and nothing on this page changes depending on how your site is built.

Two platforms have a step-by-step guide of their own, because on both of them the snippet alone is not the whole job — the site has to be republished before a visitor ever loads it: Webflow and Framer.

If your site is…Where the snippet goes
Hand-written HTMLIn the <head> of each page, or in whatever partial/include your pages share.
A React, Next.js, Vue or Svelte appIn the framework's HTML document or root layout, so it loads once for the whole app. Route changes are captured automatically.
WebflowSite settings → Custom code → Head code, then publish. Full guide — including the paid Site plan it needs.
FramerSite settings → General → Custom code → head, then publish. Full guide.
Another CMS or site builderIn the theme or site settings panel for custom head code. The snippet is plain HTML; no plugin is needed.
Served behind a strict CSPAllow the script host in script-src. The snippet is a small inline bootstrap plus one external file, and it needs both.

There is no npm install command yet

The typed package @coruve/tracker is built but not published, so there is no install command we could print here that would work. Until it ships, the snippet is the supported install method and window.Coruve gives your application code the same init / track / identify API the package will export. We would rather say that plainly than publish a command that 404s.

Until the typed package ships, declare the global once: declare global { interface Window { Coruve?: { track: (name: string, props?: Record<string, unknown>) => void } } }

API key security

Best practices for keeping your keys safe.

Three credentials, and only one of them can read your data

Your Project ID (proj_…) is a public, write-only identifier meant for browser code. It is in the snippet on your page, so it is readable by anyone who views source — that is by design. It can send events and it can never read data.

Ingest keys (pk_live_…) are also write-only, but they belong in server-side environment variables rather than in frontend code or a public repository.

Read keys (rk_live_…) are the ones to be careful with. A read key can pull every report the project has through the read API and cannot write anything. A key does exactly one direction of traffic and its prefix says which, precisely so a string found in a log or a repository can be triaged without a database lookup: a leaked pk_live_ can pollute your data, and a leaked rk_live_ can take it.

.env
# Safe to expose in the browser (write-only)
NEXT_PUBLIC_CORUVE_PROJECT_ID=proj_xxx

# Keep server-side only — sends events, cannot read
CORUVE_API_KEY=pk_live_xxx

# Keep server-side only — reads every report, cannot write.
# Treat this one like a database password.
CORUVE_READ_KEY=rk_live_xxx

Leaked a key?

Revoke it in Project Settings → API keys and create a new one. Revocation is immediate. Treat an exposed rk_live_* key as a data incident rather than a cleanup task: unlike an ingest key, it could have been read with.
Installing the tracker | Coruve