Skip to main content

Changelog

Stay up to date with all the latest changes to Zenovay.

A new proxy key waits for your proxy

A new proxy key now takes effect only after your proxy has sent it once, so turning it on never costs you data.

  • Create the key, add it to your proxy, done. Until the first request with the key arrives, requests without it are handled as before.
  • Domain settings shows the key as waiting for your proxy until then. A replaced key stays in effect: the old one stops working immediately.
  • zenovay init 1.0.38 creates the key for you when it sets up a Cloudflare Pages proxy, shows it once with the exact place to add it in Cloudflare, and can store it for you if wrangler is logged in.
  • Domain settings now shows when your proxy last sent the key, and warns if requests without it start arriving, so a lost ZENOVAY_PROXY_KEY does not go unnoticed.

Proxy key for self-hosted proxies

If you run your own first-party proxy, you can now protect the visitor IP it forwards with a proxy key.

  • Create the key under Domain settings > General > First-party proxy key. It starts with zvpk_ and is shown only once.
  • Send it in the X-Zenovay-Proxy-Key header on every forwarded request. With a valid key, Zenovay trusts the visitor IP your proxy forwards.
  • Once a site has a key, requests through /fp without it (or with a wrong one) can no longer set the visitor IP. Sites without a key behave as before.
  • You can replace the key (the old one stops working immediately) or remove it in the same place. The CNAME setup and the plain script tag do not need a key.

Heatmaps show the latest page image

On pages with more than ten captured page images, the heatmap could show an older capture instead of the newest one. It now always shows the latest capture, and picking a specific date in the capture list shows that day's image.

More accurate Core Web Vitals

A page opened in a background tab can report a load time of minutes or even hours, because its timer starts when the tab opens, not when someone looks at it. Those readings no longer count.

  • LCP, FCP, TTFB and INP values above 60 seconds are now discarded when they arrive, together with their rating.
  • Readings like this that were already stored have been removed, so the p75 of affected pages now reflects what visitors actually experienced.
  • The tracking script (version 2.1.4) now ignores paints that happen after a tab was hidden, so background tabs no longer send these readings in the first place.

Backup status page

If status.zenovay.com itself does not load, a backup status page at zenovay.github.io/status shows whether each Zenovay site is up.

  • It is checked from GitHub's servers and hosted by GitHub, so it keeps working when our own infrastructure does not.
  • Each row shows when it was last checked, and state changes are published as an Atom feed.
  • The main status page and the help center link to it.

The backup status page listing each Zenovay site as operational

Faster Funnels overview

The Funnels overview in Journeys now calculates every funnel and both comparison periods together, so it loads noticeably faster, also with filters or a segment applied.

Faster dashboard loading

Dashboard cards now wait less before they show your numbers.

  • Each card checks your access to the website with fewer, parallel lookups, and repeated checks within a few seconds reuse the answer.
  • The page checks your login once per load instead of several times.

Clearer email validation during signup

Invalid email addresses now get a clear correction prompt on the password step.

  • The password step checks the email format before submitting a sign-in or sign-up request.
  • An email-format rejection from the authentication service now asks you to correct the address, instead of showing a generic account-creation error.

The signup password step showing a clear correction prompt for a malformed email address

SQL Playground, CLI queries and chart chat now run on ClickHouse

Queries on your analytics tables (visitors, page views, events, goals, performance, uptime and the daily rollups) in the SQL Playground, the CLI query command and the charts in the AI chat now run on ClickHouse, a database built for analytics. Other tables, such as payments, still run on PostgreSQL.

  • Your saved queries keep working. Common PostgreSQL syntax runs unchanged: INTERVAL '7 days', ::date, COUNT(*) FILTER (WHERE ...), DATE_TRUNC, ILIKE, HAVING and window functions. A cast to numeric keeps its decimals
  • Same results, same format. Timestamps come back as before, for example 2026-10-25T13:50:31.751+00:00
  • Templates and the AI SQL assistant write ClickHouse SQL for these tables, so you can also use functions such as countIf, uniqExact, toStartOfDay and dateDiff
  • One difference: a value exactly halfway between two numbers rounds to the even one, so ROUND(2.5) returns 2

Bounce rate and page views, now even more precise, and the funnel chart is back

Every figure that builds on page views now follows one precise definition: a page view is every page a visitor opens, and a visit bounces when it has exactly one page view.

  • Bounce rate = visits with exactly one page view ÷ all visits. Zenovay counts every page each visit opens, so bounce rate and page views now reflect your visits even more precisely, also for past periods
  • What counts as a page view. Page loads, reloads and route changes in single-page apps. Time on page, scrolling, clicks and events do not change the bounce rate. GA4 uses an engagement rule (10 seconds, a key event or 2 page views), so its bounce rate is usually lower than Zenovay's
  • The same numbers everywhere. The Analytics tab, Home, the client portal and shared dashboards use one calculation, and filters on a shared dashboard apply to its totals too
  • Pages by page view. On the Analytics tab, the Page tab ranks pages by page views and shows each page's visits, exit rate and median time on page when you hover a row. The Entry Page tab lists the page each visit started on, together with its bounce rate
  • Bounce rate by page in Retention counts the visits that started on each page, so the pages add up to your site-wide bounce rate
  • Reports, Daily Movers, benchmarks, AI insights, exports, the API, the CLI and MCP use the same definition for their daily figures, for past days too, so new reports can show different figures than earlier ones. A day's figures are final two days later, once all its visits have ended. Page views stored before October 10, 2026 keep their values
  • Users in Journeys, the weekly summary email and Ask Zenovay count visits and page views the same way, and so does the Pages viewed filter
  • Imported history keeps the bounce rate of the tool it came from. Days for which that tool has no bounce rate are left out of the average
  • The funnel chart is back. Hover a step to see its drop-off, conversion, typical time from the previous step and its top channels and countries. Click the chart to open the step list with See why. On phones it runs top to bottom
  • Every funnel within reach. "Show all" lists all your funnels, and the funnel you are looking at always stays visible
  • Full step names in the funnel builder preview, and goal and funnel names stay unique regardless of upper and lower case

Funnels in Journeys: the funnel chart with three steps, the visits at each step and the drop-off between them

Stripe revenue: missed payments recovered, each payment counted once

Zenovay now checks your connected Stripe account every hour and makes sure every paid charge shows up in your revenue, exactly once.

  • Missed payments are recovered automatically. If a Stripe payment never reached Zenovay, for example because a webhook endpoint was removed or a restricted key expired, it is added on the date it was paid, so your totals and charts match Stripe
  • Subscription renewals count in MRR. On newer Stripe API versions, renewals were saved without their subscription and left out of MRR. They are now linked to their subscription
  • Each payment counted once. On newer Stripe API versions, one subscription payment could be recorded two or three times. New payments are recorded once
  • Clear connection status. Revenue settings show "Verification failed" when Stripe stops accepting your connection, and "Last verified" shows the latest successful check

Journeys: goals and funnels rebuilt

Goals and funnels now work from the data you already have: pick any period and see real numbers right away, history included.

  • History right away. Goals and funnels are calculated from your recorded data for the period you pick. A new goal or funnel shows its history immediately, and editing one recalculates the past
  • Manage everything in one place. Every goal and funnel has a menu to edit, rename, duplicate, pause and delete, also on phones
  • Details for every goal. Click a goal to see its trend, where conversions come from, the real pages it counts and the latest conversions, each linked to the visitor's timeline
  • Pick real pages. A page picker lists your site's real pages with their visits, and a live preview shows what a rule matches before you save
  • New goal type: a click on a link. Count clicks on links to your app, a booking page or a partner site, without code
  • Patterns that fit your site. "Matches a pattern" with *, ** and {locale} covers every language version of a page in one rule, for example /{locale}/pricing
  • Funnel time windows. Count a funnel within the same visit, or within 1, 7 or 30 days for longer decisions
  • See why visitors stop. The drop-off panel shows where visitors went instead, who stops most often, the latest visits that stopped and a short AI explanation in plain words
  • Compare by device, country, channel, host or entry page
  • Funnel ideas built from the paths your visitors really take, and Create a funnel from this path in Flows
  • Correct counting across pages and subdomains. With the same tracking code, a visit is counted as one visit across pages and subdomains, also in cookieless mode
  • More accurate page view totals in reports. Since October 10, 2026, the regular activity signals an open tab sends no longer count as page views in the daily totals behind reports, the weekly summary email, AI insights, exports, the API and MCP. Page view totals there can be noticeably lower from that day on, earlier days stay as they were. The Analytics tab was not affected
  • Cookieless until consent. With data-cookieless="until-consent" the tracker stays cookieless until your banner calls zenovay('consent', 'granted'), then switches to its cookie without splitting the ongoing visit

The Funnels tab in Journeys: a three-step funnel with Started, Finished and Conversion, and how many visitors stopped between the steps

Scroll Depth counts every page view

Scroll depth is now measured for each page view, so every page gets complete numbers, including the pages people reach by clicking through your site.

  • Every page view counts. A visit that opens your homepage, then pricing, then sign-up now adds a view to each of the three pages, each with how far the visitor scrolled on that page. Until now only visits that stayed on a single page could be counted
  • Single-page apps included. Each route change is measured as its own page view, and a page that is still loading is never counted as read to the end
  • Same basis everywhere. The Scroll Depth card, My pages and the scroll heatmap overlay count the same page views
  • API. avg_scroll_depth in GET /api/v1/analytics/pages now reports the measured average for each page
  • Works with your existing tracking code. Data from before this update stays as it was: for those dates the card still counts visits that viewed a single page

Watch your own pages in Scroll Depth, with more accurate numbers

The Scroll Depth card can now follow any page you choose, and its numbers per page are more accurate.

  • My pages. Add a page by URL, by path or as a whole section such as /blog/*, or pin a page straight from Top pages with the bookmark icon. A page you add shows its visits for the selected period right away; a page without visits yet says so and fills in within minutes of its next visit. Up to 25 pages per website, shared with your workspace
  • More accurate numbers per page. A visit's scroll value covers every page it saw, so a page people reach by clicking through your site, such as pricing, was credited with the scroll on the page before it and often looked much deeper than it was. The card now counts visits that viewed only that page, and Avg depth is the true average. Expect lower, more realistic numbers for such pages
  • A chart that explains itself. The depth labels (25% to End) sit once above the bars, and hovering a bar shows the counts behind it, for example "27% of visits (54 of 200) scrolled at least 50% down the page"
  • Fits any width. In a half-width card or on a phone, each row stacks instead of running off the side
  • Filtered and unfiltered views now count pages the same way

The My pages tab of the Scroll Depth card: four watched pages with their scroll bars, a /blog/* section combined into one row, and a newly added page waiting for its first visits

Crawler content freshness checks every tracked page again

Pages already tracked on the Crawler content freshness card stopped being re-checked, so their last-checked dates froze, some as early as August, and a later edit to those pages could go unnoticed. Every tracked page is re-checked again in the daily sweep, starting with the next run.

Hostnames in Journeys, GitHub reconnect and a clearer Retention tab

Fixes for sites tracked on several hostnames, for the GitHub integration and for the Retention tab.

  • Journeys shows the real hostname of every page. On a site tracked on several hostnames, Top User Paths showed every page under your main domain, so a page on auth.example.com read as example.com/auth/... Each step now carries its own hostname, and pages with the same path on two hostnames are no longer added together
  • The Page Flow diagram names the host of each page. On a site with several hostnames, every page starts with a short host name such as "docs › /en", and a Hosts legend above the diagram shows what each short name stands for. Hover a page for its full address. Sites on a single hostname look as before
  • The Page Flow diagram uses the full width of its card, so deep flows (up to 7 steps) are no longer squeezed into part of the space, and page names get more room
  • Hostname filters now work in Journeys, and the Flows tab of a public dashboard now shows the full page sequence of each session
  • Top pages in scheduled and agency reports show the hostname when a site spans several, instead of listing every page under the main domain
  • GitHub commits keep reaching your chart after you connect once. Commits that GitHub failed to deliver are fetched automatically. If GitHub stops accepting the connection, for example because the Zenovay app was removed from your GitHub organization, the integration now shows Disconnected instead of Connected, you get an inbox notification, and the chart shows an info marker that leads to a Reconnect GitHub button. Reconnecting keeps your existing commit history
  • The Retention tab explains when retention can't be measured. When your tracking script runs cookieless, every visit gets a fresh anonymous ID, so a returning visitor can't be recognised. The tab now says so and links to your tracking settings, instead of suggesting the data will appear later

The Top User Paths table of a site tracked on several hostnames: auth.zenovay.com, help.zenovay.com and docs.zenovay.com pages each show their own hostname

Hostnames in the weekly summary email

The weekly summary email now tells your hostnames apart, like your dashboard does.

  • Top Pages in the weekly email show the hostname when your site spans several. If one domain tracks both example.com and docs.example.com, the email used to add their "/en/" pages together in a single "/en/" row. Each hostname now gets its own row, such as "docs.example.com/en/", with its own count. Sites on a single hostname get the same email as before

The Top Pages list of the weekly summary email for a site tracked on several hostnames: example.com/en/, docs.example.com/en/ and help.example.com/en/ each have their own row

Reliable visit durations, an hourly 24h chart and hostnames in page lists

Fixes to how your numbers are collected and how they are shown.

  • One bad value can no longer inflate your average visit duration. Durations are reported by the visitor's browser, and a single malformed report, for example from an automated security scanner, could push Avg time into the thousands of minutes. Each session now counts for at most 4 hours when the data comes in, so one outlier cannot outweigh hundreds of real visits
  • The 24h chart on your overview now shows visitors hour by hour. It used to place a whole day of visitors on a single hour, so the chart drew one spike. It now covers the last 24 hours in your own time zone, like the chart on each domain's analytics tab
  • Metric cards stay inside their boxes. Long durations read as "3h 05m" or "2d 4h", counts from 10,000 up read as "12.3K" or "1.2M" (hover for the exact number), and changes above 999% read as ">999%"
  • Page lists show the hostname when your site spans several. If one domain tracks both example.com and docs.example.com, the Page and Entry page lists now show "docs.example.com/en" instead of two identical "/en" rows. Sites on a single hostname look exactly as before, and search in the details view now matches hostnames too
  • The globe shows which of your hostnames a live visitor is on. When a visitor is on a hostname other than your site's main domain, such as docs.example.com, it now appears in front of the page path
  • Automated security scanners that attack your site no longer count as visitors. When one address keeps sending attack payloads (injected scripts, path probes), its traffic for the rest of the day is still recorded but marked as bot traffic and left out of your numbers
  • Bot traffic is now also left out of the weekly summary email and of the daily totals behind the API, the CLI and scheduled reports, matching what your dashboard shows
  • CLI alerts on average session duration now work. They always read 0 before

The Page list of a site tracked on several hostnames: zenovay.com/en, docs.zenovay.com/en/changelog and help.zenovay.com/en are told apart by their hostname

Globe fullscreen button fixes

The fullscreen button on the globe now matches what your browser will actually do.

  • Leaving fullscreen with Escape left the button showing its "exit fullscreen" icon. It now always shows what the next click will do
  • On a public dashboard embedded in another page, the button only appears when that page allows fullscreen. Before, it showed up anyway and did nothing when clicked. To turn it on in your own embed, add allow="fullscreen" to the iframe
  • The button is also hidden in browsers that can't show the globe in fullscreen

Importing your history is now free on every plan

Bringing your past analytics into Zenovay no longer requires a paid plan.

  • The GA4, Matomo, Simple Analytics, Fathom, PostHog and DataFast importers now work on every plan, including Free. Plausible's file upload was always free, so the same migration used to cost nothing or require Pro depending purely on which tool you were leaving
  • Nothing about the imports themselves changed: same data, same fill-gaps protection, same one-shot run
  • Your plan's data retention still applies to how far back the dashboard displays. Imported history beyond it is kept rather than discarded, so upgrading reveals it instead of asking you to import again