Your CI tells CodeGecko which commit is live. Your visitors’ browsers report how it performed. CodeGecko compares every release with the one before, page by page and device by device, and tells you what got slower and why.
Today
Set up
Project, CI step, script tag.
Next deploy
First release
Release one starts collecting.
Deploy after that
Compare
Release two vs release one.
~30 visits per page
First verdict
Hours on busy pages.
01Connect
Create a project. Get two keys.
Name the project and enter your site’s origin. You get two credentials with separate jobs, so the one that lives in browser code can’t do anything dangerous.
Both are shown once. Only their SHA-256 hashes are stored.
Rotate the public key any time; the old one keeps working for 24 hours.
The public key works only from the origin you registered.
Server only · CI
Deployment secret
Lives in your CI secrets
8f2a••••••••••••••••
Register releases
Send visit data
Read reports
Rotate or delete keys
Browser · your origin
Public key
Lives in your script tag
cg_pub_8f2a••••••••
Send visit data
Register releases
Read reports
Rotate or delete keys
Reading reports and managing keys happens in the dashboard, signed in. Neither key can do it.
02Deploy
Tell CodeGecko what shipped.
After each production deploy, one CI step sends the live commit and its recent history. Each new commit becomes the next release: v1.0.0, v1.0.1 and so on.
Works from any CI that can run curl
Rolling back to an earlier commit keeps its release number
Retries of the same commit are safe
Each release keeps the commits that are new since the last one
Register before you collect
Measurements that arrive before your first release is registered are rejected, and the script stops sending for that visit. Run the CI step once before you add the script tag, or use data-commit.
No access to CI?
Add data-commit to the script tag with the build’s commit. Unknown commits then register themselves on first visit, up to 20 a day.
After each production deployBearer: deployment secret
Add one script tag to every page. Built on Google’s web-vitals library, it records how each page load felt and what it cost, then sends a small batch when the visitor leaves.
RequiredThe collector. ≈7 kB, loads async, never blocks rendering.
data-project="your-project-id"
RequiredWhich project the visits belong to.
data-key="cg_pub_…"
RequiredYour public key. Works only from the origin you registered.
data-routes="/blog/:post, /docs/:page"
OptionalYour own page groups. Otherwise /products/blue-shoe-42 becomes /products/:slug.
data-sample="0.25"
OptionalMeasure a share of page loads on busy sites.
data-commit="a3f9c1e"
OptionalOnly if you can’t add the CI step.
></script>
Mobile or desktop
From the browser’s own hint, or under 768 px wide.
Sent in the background
Batched when the page is hidden. Never retried; it stops for the visit after any rejection.
Nothing personal
No query strings, fragments or cookies. IDs, emails and tokens in URLs and error messages are replaced before anything leaves the browser.
04Compare
Every metric gets a verdict.
For each page, device and metric, CodeGecko takes the 75th percentile of this release and the one before, then asks the same three questions. No AI guesses, no averages hiding a bad page.
At least 30 visits for this page, device and metric in both releases. Once a newer release replaces the short one, no more can come.
Not yetGathering data
Replaced shortinconclusive
Yes
2
Is the change bigger than noise?
The typical visit has to move by more than 5% of the old value, or the metric’s floor, whichever is larger.
Nounchanged
Yes
3
Which way did it move?
Every metric is “lower is better”, so the direction decides the verdict.
Lowerimproved
Higherregressed
Worked example · LCP, /, mobile
visits 214 / 196 both over 30
typical 2.58s → 2.71s +130ms
threshold max(5% × 2.58s, 100ms) = 129ms
130ms > 129ms, and higher regressed
Health badges (Good, Needs improvement, Poor) use Google’s Core Web Vitals ranges and show where a metric stands. The verdict shows how it moved.
05Report
One verdict per release, and the why.
Metric verdicts roll up into one word for the release on each page, starting with /. When something got slower, the report puts the evidence next to it.
Metric verdicts
Release
improved+regressed+unchangedmixedSome improved and some regressed.
regressed+unchanged+unchangedregressedAt least one regressed, none improved.
improved+unchanged+unchangedimprovedAt least one improved, none regressed.
unchanged+unchanged+unchangedunchangedNothing moved past its threshold.
Gathering data+Gathering data+Gathering dataGathering dataNot enough data yet to say.
inconclusive+inconclusive+inconclusiveinconclusiveThe release before was replaced before it got enough visits.
Then the why.
Next to anything that got slower, the report shows the evidence.
Load steps
DNS, connect, server, download and DOM ready, so a slower page shows where the time went.
Page weight
JS, CSS, image and font bytes per page, with the growth marked.
Third-party cost
Bytes and main-thread blocking from other domains, new ones flagged.
Long animation frames
Time the page froze, and the script behind most of it.
JavaScript errors
Share of visits with an error, and messages new in this release.
Commits that shipped
Listed with a GitHub compare link. Which one caused it is still your call.
When you’ll see results
Your second release is your first verdict.
What your dashboard shows, from setup to the first verdict.
Today
Waiting for your first release
Project created
CI step added
Script tag on the site
First release registered
Create the project, add the CI step and the script tag.
Next deploy
v1.0.0 · collecting
First release
/182 visits
/products/:slug140 visits
/cart46 visits
Your first release starts collecting. Nothing to compare yet.
Deploy after that
v1.0.1 vs v1.0.0
Comparing as visits arrive
/30 / 30
/products/:slug22 / 30
/cart6 / 30
Release two is compared with release one as visits arrive.
~30 visits per page
v1.0.1 vs v1.0.0
Release verdictimproved
LCPimproved
INPunchanged
CLSunchanged
Busy pages get a verdict within hours; quiet ones keep gathering data, and end inconclusive if the next release comes first.
Create the project, add the CI step and the script tag.
Your first release starts collecting. Nothing to compare yet.
Release two is compared with release one as visits arrive.
Busy pages get a verdict within hours; quiet ones keep gathering data, and end inconclusive if the next release comes first.
What’s measured
What visitors feel, and what it costs.
LCP, INP and CLS are Google’s Core Web Vitals. The rest explain them, and some only count when the browser can measure them.
Metric
Measures
In plain words
Unit
Google “good”
Role
LCPLoadingWhen the largest element finishes rendering.ms≤ 2.5sDecides the verdictms · good ≤ 2.5s
INPResponsivenessHow fast the page reacts to taps, clicks and keys.ms≤ 200msDecides the verdictms · good ≤ 200ms
CLSVisual stabilityHow much content shifts unexpectedly.score≤ 0.1Decides the verdictscore · good ≤ 0.1
FCPFirst paintWhen the first text or image appears.ms≤ 1.8sDecides the verdictms · good ≤ 1.8s
TTFBServer responseTime until the first byte arrives.ms≤ 0.8sDecides the verdictms · good ≤ 0.8s
LoAFMain-thread blockingTime long frames froze the page. Chrome and Edge.ms—Decides it when measuredms
WeightPage weightCompressed JS, CSS, image and font bytes.kB—Decides it when measuredkB
ErrorsJavaScript errorsShare of visits with an uncaught error.%—Decides it when measured%
LoadLoad breakdownDNS, connect, server, download, DOM ready.ms—Explains, never decidesms
3rd partyThird-party costBytes and blocking from other domains.kB · ms—Explains, never decideskB · ms
“Good” is Google’s 75th-percentile range and drives the health badge. The verdict compares releases, whatever the range.
Built carefully
Private and safe by default.
What CodeGecko keeps, how it keeps it, and the straight answers on what it can’t do yet.
What it does
No personal data
Pages are templates. No query strings, fragments, cookies or identifiers.
Keys stored as hashes
Shown once, never kept in plain text.
Your data is yours
Row-level security isolates every project. Delete one and everything goes with it.
Rate-limited collection
Per-project limits per minute and per month, enforced in the database.
What it doesn’t do yet
Name the commit that caused a regression
Code-diff analysis is on the roadmap.
On the roadmap
Measure route changes inside single-page apps
Every full page load is measured.
Run synthetic lab tests
Everything comes from real visits.
Your next deploy is your first data point.
Set it up once. Every release after that is compared automatically.