Hulo Global
Plugins Roadmap
Hulo Global

Visitor Analytics

Self-hosted visitor journey, cart abandonment, product recommendations, search analytics — one plugin, one database, no third party.

What it does

Built for production from day one.

Self-hosted analytics that reaches all the way from a visitor's first pageview to a recovered abandoned cart. Journey drawer with parsed UA + MaxMind geo + heuristic intent labels; cart abandonment detection with signed recovery links and Slack notifications; co-view product recommendations (also-viewed, personal, trending); site-search analytics (top queries, zero-result gaps, search-to-cart conversion); rage-click and dead-click hot-spot lists. Privacy-first defaults: DNT respected, IPs anonymised, optional consent gate. Ships a drop-in storefront JS helper at `/ees/hulo.js` — one script tag and every event type is wired.

Cart abandonment

Detects sessions with `cart_snapshot` events but no `checkout_completed` in the abandonment window (default 30 min). Auto-promotes to `converted` when a matching checkout later lands. Signed recovery-link tokens (time-bounded, non-reusable) — `/ees/abandoned-carts/:id/recovery-link` returns a URL you drop into a recovery email. Slack notification for high-value drops.

Product recommendations

Denormalised `ProductCoView` table rebuilt every 6 hours from `product_view` events, bounded per session to 20 events so bot sessions can't skew the table. Three endpoints: `also-viewed` for a product-page rail, `personal` for a homepage/cart rail based on a returning visitor's last 10 product views, `trending` for a most-viewed-in-window rail.

Site search analytics

Zero-schema-cost queries over `search` events. Top queries by volume with average results count, zero-result queries (direct catalogue-gap intel), search-to-cart conversion rate.

Journey drawer buffs

Rage-click + dead-click hot-spot lists per URL. Per-session heuristic `intent` label (`purchase` / `abandon` / `frustrate` / `consider` / `browse` / `bounce`) — one glance per session in the visitor drawer.

Drop-in storefront helper

Ships `/ees/hulo.js` — one script tag and every event helper (`cartSnapshot`, `productView`, `search`, `checkoutCompleted`) is on `window.hulo`. Handles batching, `sendBeacon`, auto rage-click + dead-click detection.

Configurable conversion goals

CRUD a goal with a URL glob (`/checkout/thank-you/*`) and a value. Live matcher tags every pageview that hits the pattern. Dashboard shows completions per goal.

Full visitor journey

Page views, time-on-page, exit pages, configurable funnel, UTM attribution, bot detection. Per-visitor profile drawer with parsed UA + MaxMind GeoLite2 geo. Survives login — guest and signed-in events share the same visitor id.

Privacy-first defaults

DNT respected, IPs anonymised to /24 (IPv4) / /48 (IPv6), optional `requireConsent` gate. All three opt-outable per install.

Live-now SSE widget

Real-time tile on the admin dashboard showing visitors active right now (by country).

CSV export

`/ees/visitors/export.csv?days=N` and `/ees/abandoned-carts/export.csv` for raw event / abandoned-cart data.

Admin dashboards

Angular admin pages for Abandoned Carts (KPIs, filters, recovery-link mint, CSV export) and Analytics Insights (trending, also-viewed lookup, search analytics, rage/dead-click hot spots).

Install

Three steps, five minutes.

Add the package

Or run the one-line installer that does steps 1–3 for you:

curl -sSL https://huloglobal.com/vendure-plugins/visitor-analytics/install.sh | bash

Prefer to do it by hand?

yarn add @huloglobal/vendure-plugin-visitor-analytics

Register it

In your vendure-config.ts:

# vendure-config.ts import { VisitorAnalyticsPlugin } from '@huloglobal/vendure-plugin-visitor-analytics'; export const config: VendureConfig = { plugins: [ VisitorAnalyticsPlugin.init({ publicBaseUrl: 'https://shop.example.com', licenceKey: process.env.HULO_LICENCE_KEY_VISITOR_ANALYTICS, }), // ... your other plugins ], };

Run the migration

The plugin adds its own table(s). Generate + run the migration like any other:

yarn migration:generate AddVisitorAnalyticsPluginTables yarn migration:run

That's it. The admin UI tab appears immediately. Without a licence key the plugin runs in a degraded evaluation mode — fine for trying things out. Buy a key →

HTTP endpoints

Every route exposed.

POST/ees/trackPublic: ingest a batch of events
GET/ees/hulo.jsPublic: drop-in storefront helper JS (0.8.1)
GET/ees/recover-cart?t=…Public: resolve a recovery-link token → cart items
GET/ees/recommendations/also-viewed?productId=…Public: co-view recommendations for one product
GET/ees/recommendations/personal?visitorId=…Public: personalised recs from visitor history
GET/ees/recommendations/trending?hours=…Public: most-viewed products in the window
GET/ees/abandoned-cartsAdmin: paginated list with filters
GET/ees/abandoned-carts/summaryAdmin: totals + recovery rate + lost value
GET/ees/abandoned-carts/:idAdmin: detail incl. parsed items
POST/ees/abandoned-carts/:id/recovery-linkAdmin: mint signed recovery URL
POST/ees/abandoned-carts/:id/statusAdmin: mark recovered / dismissed
GET/ees/abandoned-carts/export.csvAdmin: CSV export
GET/ees/search-analytics/topAdmin: top search queries
GET/ees/search-analytics/no-resultsAdmin: zero-result queries
GET/ees/search-analytics/conversionAdmin: search→cart conversion
GET/ees/journey/rage-clicksAdmin: rage-click hot spots
GET/ees/journey/dead-clicksAdmin: dead-click hot spots
GET/ees/journey/session-summary?visitorId=…Admin: per-session intent labels
GET/ees/visitors/summaryAdmin: top-line counters + daily series
GET/ees/visitors/sourcesAdmin: top sources by visits / sessions
GET/ees/visitors/top-pagesAdmin: most-visited URLs
GET/ees/visitors/funnelAdmin: configurable funnel with drop-offs
GET/ees/visitors/exit-pagesAdmin: top exit pages
GET/ees/visitors/liveAdmin: SSE live-now stream
GET/ees/visitors/journey/:visitorIdAdmin: per-visitor timeline
GET/ees/visitors/export.csvAdmin: CSV export
POST/ees/goalsAdmin: create a conversion goal
GET/ees/goals/statsAdmin: per-goal completion stats

FAQ

Common questions.

How do I get a licence key?

Buy here — Stripe Checkout, monthly or lifetime. You'll receive the JWT key by email; set it as HULO_LICENCE_KEY_VISITOR_ANALYTICS in your .env.

Does it work without a key?

Yes — the plugin boots in a degraded "evaluation" mode. You can install, configure, and inspect the admin UI before committing.

Where is data stored?

In your Vendure database. The plugin adds its own tables via a migration — your data never leaves your server.

Will it survive a Vendure upgrade?

Tested against Vendure >=3.5.0 <4.0.0 — 3.5, 3.6 and 3.7 are all covered by CI. A boot-time compatibility check emits a non-fatal warning if @vendure/core is outside that range, so upgrades to a future 3.x are safe to try. The 4.0 line will be tested and re-declared once its changelog lands.

Ready to ship?

Buy a key, drop the plugin in, ship today.