Site Activity tracking
Site Activity is Hydra's first-party analytics layer. Once you enable it on a widget, every pageview on the pages where that widget is embedded — plus any custom events you send and any visitor you identify — gets recorded against the widget's tenant. Anonymous visitors are tracked under a per-origin ID stored in the visitor's browser; identified visitors are stitched to a CRM contact so the same person's history follows them through every later conversation.
The toggle lives on each widget config (per-widget, not tenant-wide). To turn it on for a widget today, contact us at hydrausersupport@gmail.com — the in-app Settings → Widgets → [widget] → Tracking UI is coming in a later wave. Once tracking is on, events start landing immediately the next time the widget loads on a customer page.
Heads up — what's live today vs. what's coming. This release ships the full data path: the database, the public ingest endpoint, the per-widget enable, and the widget script that emits pageviews and exposes the
hydra.track()/hydra.identify()JavaScript APIs. Once you turn tracking on for a widget and the page loads in a visitor's browser, events start landing immediately. The dashboards that surface this data (the Marketing → Site Activity page, the visitor timeline in the inbox right rail, and the visitor history on Lead / Contact detail pages) are still on the way and are flagged in the sections below.
What gets tracked
Site Activity records four event types, all keyed to the widget that emitted them:
- Pageview — emitted automatically on every initial page load and on every SPA route change (the widget hooks the browser's History API, so single-page-app navigations show up the same as full page loads).
- Session start — emitted automatically the first time a visitor produces an event after a 30-minute gap. This is how Hydra defines a session: contiguous activity with no more than 30 minutes of silence between events.
- Custom — emitted when your site code calls
hydra.track('event_name', { ...properties }). Use this for button clicks, plan upgrades, feature use, or anything else you want to slice on later. - Identify — emitted when your site code calls
hydra.identify('user_id', { email, name, plan, ... })from inside an authenticated experience. This stitches the anonymous visitor record to a CRM contact, so every prior pageview and event from that browser is retroactively associated with the right person.
Every event row carries the URL it was emitted from, the referrer (when the browser sends one), and a JSON properties object with whatever you attached.
How visitor identity works
Until a visitor identifies, they're anonymous. The widget script mints a random ID on first contact and stores it in the visitor's localStorage on your domain — not Hydra's. This means:
- The ID is per-origin: the same visitor on
app.example.comandmarketing.example.comlooks like two different anonymous visitors. We don't ship a third-party cookie that would unify them. - Clearing site data, switching browsers, or going incognito creates a new anonymous ID.
- The ID is never shared across tenants. A visitor browsing two different Hydra customers' sites is two unrelated anonymous IDs, period.
When hydra.identify('user_id', { ... }) runs from inside an authenticated app, Hydra records the call as an identify event with the user id and any traits attached. The retro-link step — connecting the anonymous visitor's earlier events to a CRM contact so the full history surfaces in one timeline — ships in a follow-up release alongside the visitor-timeline UI. Until then, identify calls land as events but don't yet stitch past anonymous activity to a contact record.
The two JavaScript APIs
Once the new widget script is live, two functions are available on the global hydra object:
hydra.track(eventName, properties?)
hydra.track('clicked_upgrade', { plan: 'growth', source: 'pricing_page' })
hydra.track('exported_report', { report_id: 'r_4815', rows: 120 })
eventName is required and capped at 100 characters. properties is an optional plain object capped at 4KB when JSON-stringified. Larger payloads are rejected by the server with a 400 — keep properties small and use it for facets you want to filter on later, not for full record dumps.
hydra.identify(userId, traits?)
hydra.identify('u_88291', {
email: 'paul@arrakis.example',
name: 'Paul Atreides',
plan: 'growth',
})
Call identify once per session as soon as you know who the user is — typically right after login in your app. Calling it again with the same userId and updated traits is safe; later calls overwrite earlier traits on the matched contact.
Both calls batch automatically. The widget flushes events every 5 seconds or after 25 events, whichever comes first, so a burst of track calls won't fan out into 25 separate network requests.
Per-widget settings
Two columns on each widget config control tracking behavior:
tracking_enabled— a per-widget on/off switch. Default is off for every widget, including newly created ones. When off, the widget's tracking calls are silently dropped at the ingest endpoint (the script makes the request; the server returns204and writes nothing) so flipping tracking off doesn't fill consoles with errors.event_retention_days— how many days of events Hydra keeps for this widget before purging. Default 90 days, configurable between 1 and 365. The daily purge runs againstoccurred_atand is per-widget, so you can keep marketing-site widgets on a long retention while keeping in-app dashboard widgets on a short one. The purge cron itself ships alongside the in-app Settings UI in a later release; until that lands, events are retained indefinitely regardless of the configured value.
Both settings are admin-controlled. For now, changing either requires emailing hydrausersupport@gmail.com — the in-app Settings UI lands in a later wave.
Where the data shows up
Today, Site Activity events are recorded but no in-product surface reads from them yet. As later waves ship, this is where you'll find them:
- Inbox right rail — when an active conversation belongs to an identified visitor, the right rail will show their recent pageviews and custom events alongside the conversation. Useful for the agent who wants to know "what page were they on when they opened this chat?"
- Lead and Contact detail — the activity timeline on each Lead and Contact page will include their Site Activity events (pageviews, custom events, identify calls), interleaved with conversations and CRM events.
- Marketing → Site Activity dashboard — a top-level dashboard with rolling pageview counts, top pages, top custom events, and a visitor browser for ad-hoc investigation.
All three are coming in subsequent waves of this release. Until they ship, the events still land in the database and the retention window is still ticking — the data is yours from day one, you just need to wait for the surfaces to read it.
Privacy, consent, and your responsibilities
The way Hydra handles Site Activity is the same model Google Analytics, PostHog, Plausible, and similar tools follow:
- You are the data controller. Hydra is the processor. The visitors browsing your site are your data subjects. Hydra holds and processes the data on your behalf.
- Your consent banner is your responsibility. If your jurisdiction requires explicit consent before setting an analytics identifier (most of the EU, the UK, and a growing list of other regions), you need to gate
hydra.track()and the widget's auto-pageview behind your existing consent banner — same as you would for GA4 or any other analytics tool. - The anonymous visitor ID lives in the visitor's
localStorageon your domain. It's a first-party identifier scoped to your origin. We don't set a third-party cookie and we don't share the ID across tenants. - Your existing data-processing agreement with Hydra continues to govern Site Activity events. If you need a Site-Activity-specific addendum or have processor questions ahead of a procurement review, reach out at
hydrausersupport@gmail.comand we'll send a counter-signed copy.
If you're enabling tracking on a widget that runs on a public marketing site, treat it like you'd treat enabling any other analytics tool. If you're enabling it on a widget that runs inside your authenticated app, the consent picture is usually simpler — your existing terms of service and privacy policy typically already cover product analytics — but check with your own counsel.
Permissions
- Any teammate can view the widget config page once the Settings UI ships.
- Only admins and owners will be able to flip
tracking_enabledand changeevent_retention_days. - Until the UI ships, the only path to enable tracking is emailing
hydrausersupport@gmail.com. We log who requested the change against the tenant's audit log.
Frequently asked questions
If I enable tracking, when do events start showing up? The next time the widget script loads in a visitor's browser. Tracking is per-page-load — there's no historical backfill. If you enable tracking today, you'll see today-onward events; you won't see what visitors did yesterday.
Does enabling tracking slow down my site?
The widget script flushes events in 5-second batches (or every 25 events) and uses a keepalive fetch so an in-flight flush doesn't block page navigation. The ingest endpoint returns 204 and writes nothing visible to the user. There's no measurable rendering impact in our testing, but if you're sensitive to widget script weight, the existing widget loader is the same one that already handles your chat — Site Activity adds a few KB on top, not a separate script.
What if I call hydra.track() before the widget script has loaded?
Calls placed before the script loads need a small init snippet that buffers them — the same pattern Segment, PostHog, and most analytics tools use. Add this above your <script src="…/widget.js"> tag:
<script>
(function () {
var q = []
window.hydra = {
_q: q,
track: function () { q.push(['track', arguments]) },
identify: function () { q.push(['identify', arguments]) },
}
})()
</script>
When the widget script finishes loading, it drains the queue and replays each call through the real implementation. If you load widget.js synchronously (no async or defer) and only call hydra.track() from code that runs after the script tag, the snippet is optional — window.hydra will already be defined by the time your code runs.
Do bot-driven widget conversations count as visitor events?
No. The widget's chat interactions (opening the chat, sending a message, getting a bot reply) flow through /api/widget/init and /api/chat, not through /api/widget/track. Pageviews and custom events are a separate stream. A visitor who chats with the bot but never triggers a pageview won't have a Site Activity row from the chat itself — but if tracking is on, the pageview that loaded the page they opened the chat on will be there.
Can I track activity from a widget I haven't fully embedded yet? No. Tracking events come from the widget script. If the widget isn't on a page, that page generates no events. The same widget can be embedded on as many pages as you like — every embedded page contributes events to the same widget's stream.
What happens to events when I delete a widget?
Events are stored with a foreign key to widget_configs with ON DELETE CASCADE. Deleting a widget removes its visitor events along with the config row. If you want to preserve the data, disable tracking on the widget instead of deleting it — the rows stay until the retention window purges them.
What happens to events when I delete a customer record?
The customer_id foreign key on visitor events is ON DELETE SET NULL. Deleting a customer record clears the link but preserves the events themselves under their anonymous visitor ID, so your aggregate counts (pageviews, custom event volume) don't change. The events just lose their identified-person association.
Is there a webhook or Slack delivery for Site Activity events?
Not in v1. Events land in the database and surface in the dashboards once those ship. A REST endpoint on the public /api/v1 surface and a visitor_event.created outbound webhook are both on the roadmap for a follow-up release; reach out if either is a hard blocker for your team and we'll factor your use case into the prioritization.
Can I export my visitor events?
Visitor events are not yet wired into the Data Export bundle — that's tracked as a follow-up alongside the dashboard surfaces. Until then, if you need a one-off export for a contract or audit, email hydrausersupport@gmail.com and we'll pull the rows for your tenant directly.
