Hydra logoHydra · Hydra Support

Configuration

Site Activity privacy controls

Per-widget tracking toggle, retention window, and the public REST endpoints that let you fulfill visitor "right to know" and "right to delete" requests under GDPR and CCPA.

Site Activity privacy controls

Site Activity records what your visitors do on your site (see Site Activity tracking for the data path). This article covers the privacy controls that let you deploy that tracking under GDPR, CCPA, and other regimes: a per-widget on/off, a per-widget retention window, an opt-in toggle that injects visitor activity into bot replies, and two public REST endpoints — one for "right to know" exports and one for "right to delete" requests.

These settings live on each widget at Widgets → [widget] → Tracking, and the data-subject endpoints are part of the public /api/v1 REST surface.

Your responsibilities as the data controller

The legal model for Site Activity is the same one Google Analytics, PostHog, Plausible, and similar tools follow:

  • You are the data controller. The visitors browsing your site are your data subjects. You decide whether and how to track them.
  • Hydra is the data processor. We hold and process the data on your behalf, under contract.
  • You're responsible for consent. 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 auto-pageview behind your existing consent banner — same as you would for GA4.
  • You're responsible for your privacy policy. Add Hydra to the list of processors. The sample DPA addendum copy at the bottom of this article is a starting point — not legal advice.
  • You're responsible for responding to data-subject requests under GDPR, CCPA, or any other applicable regime. Hydra ships the tooling (the export and delete endpoints below); you execute the request when one comes in.

Turn tracking on or off

The setting lives at Widgets → [widget] → Tracking. There's one switch per widget — tracking is configured separately for each one. New widgets ship with tracking off by default; you have to flip it on per widget before any events get recorded.

When tracking is off:

  • The widget script's auto-pageview and hydra.track() / hydra.identify() calls return early in the browser without making an ingest request.
  • Already-recorded events for that widget stay in the database under the retention window — turning tracking off is not a delete. Use the delete endpoint below (or wait out the retention window) if you also need the existing rows gone.
  • The widget's chat path is unaffected. /api/widget/init and /api/chat always work regardless of tracking state.

Flipping tracking on or off is admin-controlled and recorded in Team → Audit log as an "Updated widget" entry.

Choose a retention period

Each widget has a Retention dropdown with five options:

  • 30 days — minimum exposure. Pick this if your privacy policy commits to a short retention window or you only need recent behavior for live agent context.
  • 60 days
  • 90 days — the default. A reasonable middle ground for most teams: enough history for trend analysis and high-intent visitor surfacing, not so much that you accumulate years of behavioral data.
  • 180 days
  • 365 days — maximum analytics value. Pick this if you need quarter-over-quarter and year-over-year cohort analysis on anonymous visitor behavior.

A daily cron purges visitor_events rows whose occurred_at is older than the configured window, per widget. The purge applies to events only — it doesn't touch the linked customer records, just the event history attached to them.

You can shorten or lengthen retention at any time. Shortening it means the next purge cycle will remove anything that now falls outside the new window. Lengthening it doesn't bring back already-purged events; it only changes what future purges will keep.

Bot context (opt-in)

Below the tracking toggle is a Use recent activity in bot replies switch. It's visually disabled — greyed out and unclickable — until tracking is on for the widget, because there's no activity for the bot to read from a widget that isn't tracking anything.

When this toggle is on, the visitor's recent activity (recent pageviews, key custom events, the last few sessions) gets injected into the bot's context on each reply. The bot can then answer things like "I see you were on the pricing page a minute ago — were you comparing the Growth and Scale tiers?" without you having to wire that into a flow.

Two things to know before turning it on:

  • It adds per-message token cost. The visitor-activity blob is a few hundred to a few thousand tokens depending on how active the visitor has been. Multiply by your bot conversation volume to estimate. The blob is sent on every turn, not once per conversation.
  • The toggle controls live behavior in two places. When it's on, the visitor's recent activity gets injected into the bot's prompt on each reply and into the "Recent site activity" section of the handoff email that fires when the bot escalates to a human — so the teammate picking up the conversation sees what the visitor was doing right before they asked for help. When it's off, both paths skip the injection entirely and behave as if no tracking exists for the visitor. The toggle is only consulted for identified visitors with at least one event in the last 90 days; anonymous-only sessions don't receive the block regardless.

The toggle is admin-controlled. Members can see it; only admins and owners can change it.

Responding to a "right to know" request

GDPR Article 15 and the CCPA "right to know" both entitle a data subject to a copy of the personal data you hold about them. For Site Activity, that's their event history plus the linked customer record if they've been identified.

Use the public export endpoint:

curl https://hydra-one-tau.vercel.app/api/v1/visitors/<anon_visitor_id>/export \
  -H "Authorization: Bearer <your_api_key>"

The endpoint requires the crm:read scope on your API key (same MCP-issued key system documented in MCP and API keys — the public REST API and the MCP server share the same key format and scopes).

The response is JSON in this shape:

{
  "anon_visitor_id": "v_8829abf3...",
  "customer": {
    "id": "c_7e3f...",
    "type": "contact",
    "email": "paul@arrakis.example",
    "name": "Paul Atreides",
    "created_at": "2026-04-12T14:22:08Z"
  },
  "event_count": 47,
  "truncated": false,
  "events": [
    {
      "id": "ev_...",
      "widget_id": "w_4815",
      "event_type": "pageview",
      "event_name": null,
      "occurred_at": "2026-05-09T18:14:22Z",
      "url": "https://example.com/pricing",
      "referrer": "https://google.com/",
      "properties": {},
      "customer_id": null
    },
    {
      "id": "ev_...",
      "widget_id": "w_4815",
      "event_type": "custom",
      "event_name": "clicked_upgrade",
      "occurred_at": "2026-05-09T18:15:01Z",
      "url": "https://example.com/pricing",
      "referrer": null,
      "properties": { "plan": "growth" },
      "customer_id": "c_7e3f..."
    }
  ]
}

The customer block is null if the visitor was never identified. events[] returns the full history within the retention window up to a hard cap of 50,000 rows per call. If the visitor has more than that, truncated flips to true and the response holds the oldest 50,000 events. In practice no real visitor hits this — if you have one that does, contact us at hydrausersupport@gmail.com and we'll help you assemble the full export.

Gotcha — one anon ID per origin per device. The export endpoint scopes by anon_visitor_id. If the same person visited from both their laptop and their phone, or from both app.example.com and marketing.example.com, they have multiple anon IDs — one per origin per device. To fulfill the request completely, you'll need to call the export endpoint once per anon ID linked to the customer record. The customer record is the join key — query customers.anon_visitor_id (or run a quick lookup in the admin UI) to find every anon ID associated with a person before running the export.

Responding to a "right to delete" request

GDPR Article 17 and the CCPA "right to delete" entitle a data subject to have their data erased.

Use the public delete endpoint:

curl -X DELETE https://hydra-one-tau.vercel.app/api/v1/visitors/<anon_visitor_id> \
  -H "Authorization: Bearer <your_api_key>"

The endpoint requires the crm:write scope. The response shape:

{
  "anon_visitor_id": "v_8829abf3...",
  "deleted_count": 47
}

The call is idempotent — running it twice returns {"deleted_count": 0} on the second call because there's nothing left to delete. The same goes for an anon_visitor_id that never existed: you get a 200 with deleted_count: 0, not a 404.

Important — this deletes events, not the customer record. If a visitor identified at any point, deleting their events does not delete the linked row in customers. That's an explicit scope choice: many tenants want to keep the lead or contact record (with email, name, account link) while erasing the behavioral history. If the data subject wants the customer record gone too, call the existing delete endpoints documented on the API reference:

  • DELETE /api/v1/leads/{id} — for unconverted leads.
  • DELETE /api/v1/contacts/{id} — for converted contacts.

You'll typically run the visitor delete first (to erase behavioral history per the retention obligation) and then the customer delete second if the request covers the identified record too.

As with the export endpoint, you may need to run the delete once per anon ID if the visitor has multiple — one per origin per device. The customer record is the join key.

Sample DPA addendum copy

Below is sample copy you can paste into a Hydra-specific addendum to your existing Data Processing Agreement with your customers. It names Hydra as the processor and describes the controls available.

Hydra (operated by Hydra Help) acts as a data processor for visitor analytics data collected via the Hydra widget on the Controller's site. Data is collected only when the Controller explicitly enables tracking on a given widget configuration. Retention of visitor event data is configurable by the Controller on a per-widget basis between 30 and 365 days, after which the data is automatically purged. The Controller may at any time request export or deletion of any individual visitor's event history via the documented /api/v1/visitors/:id/export and DELETE /api/v1/visitors/:id endpoints, which are also available to the Controller's own systems via API key. Hydra will fulfill any escalated deletion request submitted in writing within thirty (30) calendar days of receipt.

Disclaimer: this is sample copy, not legal advice. Your DPA, privacy policy, and any addenda should be reviewed by your own counsel before publication — particularly if you operate in regulated industries (healthcare, financial services) or in jurisdictions with prescriptive data-protection regimes.

Frequently asked questions

If I turn tracking off on a widget, do the existing events get deleted? No. Turning tracking off stops new events from being recorded but leaves the existing rows in place until they fall outside the retention window or you delete them explicitly via the API. If a request requires immediate deletion, use DELETE /api/v1/visitors/:anon_id for each affected visitor.

Can the same person have more than one anon_visitor_id? Yes — one per origin per device. The widget mints the ID in localStorage on your domain, so a visitor on their laptop's Chrome and the same visitor on their phone's Safari look like two different anonymous IDs. They get unified only if they identify (via chat capture or hydra.identify()) — at which point the linked customers row becomes the join key across both anon IDs. Run the export or delete once per anon ID to cover them all.

Does the export endpoint return events from deleted widgets? No. Events are stored with a foreign key to widget_configs with ON DELETE CASCADE — deleting a widget removes its events along with the config row. After a widget delete, the export endpoint will return event_count: 0 for any anon ID that only had events on that widget. If you anticipate needing the data after a widget deletion, export it before deleting the widget.

What exactly does the bot context toggle change when I turn it on? Two things, both gated by the same switch. On every bot reply, a "Recent Activity" block (top pages, total sessions, last few events with timestamps) gets appended to the bot's system prompt so it can reference what the visitor was just doing. And on every bot-driven handoff, the same activity summary gets included as a "Recent site activity" section in the handoff email that goes out to the assigned teammate or channel — so whoever picks up the escalation walks in with context. Turning the toggle off skips both injections; bot replies and handoff emails behave as if no tracking exists for the visitor.

Is there a webhook that fires on a visitor delete? Not in v1. The delete endpoint returns the deletion count synchronously and updates the audit log; there's no outbound webhook for it today. If you need a delete event piped into a downstream system, reach out at hydrausersupport@gmail.com and we'll factor it into the next round of API webhook coverage.