Security at ActivityPulse
Each organisation's captured activity lives in its own database, so tenant isolation is structural rather than a filter someone has to remember to apply. The desktop agent authenticates per device, data is encrypted in transit and at rest, and capture defaults to application metadata only.
Isolation is the architecture, not a WHERE clause
The single decision most of this page follows from.
Most multi-tenant products keep every customer's rows in one table and add a tenant column to every query. It works until one query is written without it, and then it fails silently and completely — the worst possible shape for a bug in a product holding an organisation's activity data.
ActivityPulse does not have that column. Each organisation's captured activity is stored in a separate database, resolved from the authenticated session. There is no query that could return another organisation's rows, because there are no other organisations' rows in the database being queried. An automated architecture check fails the build if a tenant column is ever added to the per-organisation schema.
SELECT * FROM activities WHERE org_id = ?Vulnerable to human developer error, missing clauses, or cache leaks.
env.ORG_DB.prepare("SELECT * FROM activities")Each org has its own physical SQLite/D1 database. Zero cross-tenant data leakage possible.
Less data is the security control
The most reliable way to not leak something is to not hold it. Sensitive capture — screenshots, input activity — is off by default and gated behind both a plan and a compliance review. Keystroke content has no code path at all.
Configuration inherits in one direction only: a team's settings can narrow what the organisation permits, never widen it. So a capability nobody granted at the top cannot appear at the bottom.
When the agent is not visible
By default the agent announces itself on the machine it runs on: a tray presence, a live view of what is being captured, and a pause control. An organisation can turn the tray UI off — quiet mode — and the agent stays disclosed and its “what’s captured” view stays reachable.
There is one exception, and we would rather state it here than bury it. Outside the EU, on the Enterprise plan, an organisation admin can authorise a covert investigation covering the organisation, a team, or one person, for which the agent’s on-screen presence is suppressed. It is the most heavily gated thing the product does: a stated purpose, a DPIA reference and a named attestation are mandatory, the authorisation cannot be open-ended — 90 days is the ceiling and reverting to visible at expiry is enforced by the database, not by a scheduled job — it can be ended early at any time, and both the authorisation and the revocation are written to the organisation’s audit log.
For an EU-region organisation it is switched off outright, in the resolver, in every plan and configuration. Everywhere else it hides the agent and nothing more: it grants no additional capture, and the capture policy the organisation configured still bounds exactly what is collected. Our terms require that this possibility appear in the monitoring notice given to staff — unannounced as to timing, never secret as to existence.
Security controls
- Per-device credentials for the desktop agent, revocable individually from the console.
- Role-scoped reads: a member sees only their own activity, a team admin only their subtree.
- An audit log of configuration changes, recording who changed what and when.
- Erasure that removes the captured activity and the raw archive behind it, not just the login.
- Retention windows enforced per organisation rather than left to accumulate indefinitely.
What the design guarantees
- per-org-database
- Each organisation's captured activity lives in its own database, so isolation is structural rather than a filter someone has to remember to apply.
- no-keystroke-logging
- Keystroke content is never captured — there is no code path that records what a person types.
- sensitive-capture-off-by-default
- Screenshots and input-activity capture are off by default, and a narrower scope can never widen what a broader one allows.
- audited-config
- Every change to what an organisation captures is written to an audit log with who changed it and when.
Reporting a vulnerability
Report security issues to contact@activitypulse.ai. A machine-readable contact is published at /.well-known/security.txt in line with RFC 9116. Please give us a reasonable window to fix an issue before disclosing it publicly.
Frequently asked questions
How is one organisation's data kept separate from another's?
Each organisation's captured activity is stored in its own database. Isolation is structural rather than a filter applied at query time, so there is no query that could return another organisation's rows even if one were written incorrectly.
Is data encrypted?
Data is encrypted in transit over TLS and encrypted at rest by the underlying storage. The desktop agent authenticates with per-device credentials rather than a shared key.
What happens if a laptop is lost or stolen?
The device's credentials can be revoked from the console, which stops that machine syncing. Segments queued on the device are of the same kind already visible in reports: application and window metadata, not documents or screen contents.
Who inside our organisation can see an individual's activity?
Access is scoped by role. A member sees only their own data, a team admin only their team's subtree, an organisation admin their organisation. There is no cross-organisation visibility at all.
How do we report a vulnerability?
Email contact@activitypulse.ai. A machine-readable contact is published at /.well-known/security.txt in line with RFC 9116.
See where the hours actually went
Free for up to three people. Windows and macOS. No keystroke content on any plan, and screenshots off unless an administrator turns them on.