# Register of processing activities

_GDPR art. 30 · MVSP Analytics (mvsp.ai)_

Last reviewed: 2026-10-10

## Design principle

MVSP Analytics is built so that individual visitors cannot be identified. No direct identifiers or cookies are collected, IPs are truncated before storage, session ids are random and unlinkable to a person, and all reporting is aggregated and anonymised.

## Controller / processor

- **Service:** MVSP Analytics — event and pageview analytics for websites.
- **Role:** Data _processor_ on behalf of the site operator (controller) who embeds `analytics.js`. The site operator determines the purposes and means of processing; MVSP acts only on documented instructions from the DPA (see `DPA.md`).
- **Contact:** privacy@mvsp.ai

## Categories of data subjects

- Visitors to websites that embed the MVSP Analytics script or call the ingest API directly.

## Categories of personal data

| Category           | Field                                           | Basis for collection                            |
| ------------------ | ----------------------------------------------- | ----------------------------------------------- |
| Online identifiers | `session_id` (random UUID in localStorage)      | Aggregation of pageviews within a single visit  |
| Anonymised IP      | `ip_address` — IPv4 /24 or IPv6 /48             | Visit counting, abuse and bot detection         |
| Device info        | `user_agent`, `viewport_width`, `viewport_height` | Browser / device breakdown                    |
| Origin data        | `referrer`, `origin`, `page_path`, `page_title` | Traffic-source attribution                      |
| Geo               | `country` (ISO-3166 alpha-2, from CDN header)   | Country-level breakdown                         |
| Custom            | `event_*`, `custom_params`                      | Whatever the site operator sends                |

Not collected: name, email, phone, government id, precise geolocation, direct user identifier, cookies, canvas / WebGL fingerprints, cross-site profile.

## Purposes of processing

1. Provide aggregate web analytics to the site operator (controller).
2. Detect abuse (rate limiting, per-site burst caps).
3. Meet the site operator's own record-keeping obligations.

## Legal basis

Legitimate interest of the controller (site operator) in understanding aggregate site usage, balanced against the low-risk, anonymised nature of the data collected (GDPR art. 6(1)(f)). The site operator is responsible for their own consent / notice obligations. The MVSP script honours Do Not Track and Global Privacy Control signals as an extra safeguard.

## Recipients

- Sub-processors listed in `SUBPROCESSORS.md`. No other recipients.

## Transfers outside the EEA

None for analytics data. Data is stored in Google Cloud EU multi-region (BigQuery `EU`), Firestore `eur3`, Cloud Run `europe-north1` (Finland). Firebase Hosting serves static assets from a global CDN but the origin is EU and only public HTML/CSS/JS is served through it (no personal data).

The separate MVSP Email API (see below) uses Resend, Inc. (US entity). E-mail is delivered through Resend's EU region, with EU Standard Contractual Clauses as the transfer safeguard. No analytics data is sent to Resend.

## MVSP Email API (`/email`)

A separate processing activity from analytics, used by the operator's own applications to send transactional e-mail.

- **Personal data:** recipient e-mail address(es), recipient name if supplied, subject and message body, as provided by the calling application (which determines purpose and content).
- **Retained by MVSP:** metadata only in Firestore (`email_log`: calling client, status, recipient count, sender domain, provider message id; `email_usage`: daily send counters). No recipient addresses, subject or body are stored by MVSP.
- **Retained by Resend:** delivery logs and message content as governed by Resend's own retention settings.
- **Access:** per-application secret API keys (hash only stored), sender allow-list, optional recipient allow-list, daily quota.

## Retention

- BigQuery event and pageview rows: 365 days, enforced by day-partitioned table expiry. No soft-delete.
- Firestore `sites`, `ads`: retained until manually deleted (contain no visitor personal data).
- Firestore `audit_log`: 365 days.
- Firestore `erasure_requests`: 90 days after status = `processed`.

## Erasure

Any data subject can trigger deletion of their own rows by calling `POST /privacy/erase-session` (or `mvspAnalytics.erase()` in the browser). Requests are queued and drained within the 30-day GDPR window; BigQuery's ~90-minute streaming buffer is respected.

## Access and portability

Any data subject can retrieve their own rows as JSON by calling `POST /privacy/access-session` with their `session_id` (or `mvspAnalytics.exportData()` in the browser). No e-mail request is needed.

## Technical and organisational measures

- TLS 1.2+ everywhere (Firebase Hosting + Cloud Run).
- HttpOnly + SameSite=Strict + Secure session cookies for the admin console.
- HMAC-derived session cookie; the raw admin token is never stored client-side after login.
- Per-IP and per-site rate limiting (120 writes / IP / min, 600 writes / site / min).
- Host allowlist enforced at the edge.
- CSP with no third-party origins on API pages.
- IP anonymisation is unconditional in code; there is no runtime flag to disable it.
- No geo-IP library runs against the raw IP — country data comes only from CDN / load-balancer headers.
- Audit log for every admin mutation.
- Source hosted on GitHub with pull-request review.

## Reviews

The register is reviewed at least annually and whenever a sub-processor or purpose changes.
