# Datahop > Self-hosted, agent-first analytics: product analytics (trends, funnels, retention), people (persons, cohorts, groups), web analytics, feature flags and Bayesian A/B experiments. Humans use the web UI; agents get exactly the same capabilities over MCP, a CLI and a REST API. This instance: https://app.datahop.dev Full documentation: https://docs.datahop.dev/llms.txt (index) · https://docs.datahop.dev/llms-full.txt (everything in one file) ## Authenticate Create a project API key in the UI (Settings → API keys & MCP). Keys look like `dh_sk_…`, belong to one project and are read-only or read+write. Send it as `Authorization: Bearer dh_sk_…`. Every change made with a key is attributed to it in the project's activity log. The public project token (`dh_…`) is different: it only sends events and reads feature flags, and is safe in client code. ## Use it - [MCP server](https://app.datahop.dev/mcp): streamable HTTP, stateless. Claude Code: `claude mcp add --transport http datahop https://app.datahop.dev/mcp --header "Authorization: Bearer dh_sk_…"`. 62 tools; tools for products switched off in the project are hidden, read-only keys see only read tools. - [CLI](https://app.datahop.dev/cli/install.sh): `curl -fsSL https://app.datahop.dev/cli/install.sh | sh`, then `datahop login --host https://app.datahop.dev --key dh_sk_…` (or env DATAHOP_HOST / DATAHOP_API_KEY). `datahop overview`, `datahop tools`, `datahop query ''`, `datahop sql ""`, `datahop call --arg value`. - REST: `https://app.datahop.dev/api/projects//…` with the same Bearer header. Errors are `{ "error", "message", "hint" }`. ## Work like this 1. Orient: `project_overview` (enabled products, top events, cohorts, running experiments, recent activity). 2. Learn the real schema before querying: `list_events`, `get_event` (properties, types, sample values), `list_properties`. Never guess event or property names. 3. Analyse with `query` (one JSON language, see below). Every result starts with a plain-text summary. 4. Segment with cohorts; compare segments with a cohort breakdown. 5. Test changes: `create_experiment` (hypothesis + primary metric + segment cohorts) → `launch_experiment` → `get_experiment_results` → `conclude_experiment` with your reasoning. Leave `create_annotation` notes for humans. ## Query language (POST /api/projects//query, MCP `query`, CLI `datahop query`) - `{"kind":"trends","series":[{"event":"$pageview","math":"unique_persons"}],"interval":"day","dateRange":{"from":"-30d"}}` math: total | unique_persons | unique_sessions | unique_groups (+groupTypeIndex) | sum | avg | min | max | median | p90 | p99 (+mathProperty) - `{"kind":"funnel","steps":[{"event":"signed_up"},{"event":"order_completed"}],"windowDays":14,"breakdown":{"type":"cohort","cohortIds":[1,2]}}` - `{"kind":"retention","startEvent":{"event":"signed_up"},"returnEvent":{"event":"session_started"},"period":"week","periods":8}` - `{"kind":"paths","include":"pageviews","startPoint":"/pricing","steps":5,"per":"session"}` (include: pageviews | events | both; endPoint shows what leads to a page/event) - `{"kind":"lifecycle","event":{"event":"board_opened"},"interval":"week","dateRange":{"from":"-8w"}}` → new / returning / resurrecting / dormant per period - `{"kind":"stickiness","series":[{"event":"board_opened"}],"interval":"day","dateRange":{"from":"-30d"}}` → people by number of active days - `{"kind":"events","event":"order_completed","limit":50}` · `{"kind":"sql","sql":"SELECT event, count() FROM events GROUP BY event"}` (see SQL below) - Web: `web_overview`, `web_stats` (by: page | entry_page | exit_page | referrer | channel | utm_* | country | device_type | browser | os), `web_trend` - Filters (any query): `{"type":"event"|"person"|"group","key":"plan","operator":"eq","value":"pro"}`, `{"type":"cohort","value":,"operator":"in"}`; operators: eq neq contains not_contains regex gt gte lt lte is_set is_not_set in not_in - Breakdowns: `{"type":"event"|"person"|"group","key":"…"}` or `{"type":"cohort","cohortIds":[…]}` - Date ranges: "-24h", "-7d", "-12w", "-6m", "mtd", "ytd", "all" or ISO dates; buckets use the project timezone. ## SQL (MCP `sql` / `sql_schema` / `save_query`, CLI `datahop sql`) Read-only ClickHouse SQL, already scoped to this project; timestamps are in the project's timezone. Tables: - events(uuid, event, distinct_id, person_id, session_id, timestamp, properties, current_url, pathname, host, referrer, referrer_domain, utm_source, utm_medium, utm_campaign, browser, os, device_type, country, lib, group_0..group_4). person_id is already resolved through identity merges, so uniq(person_id) counts real people. - persons(id, properties, is_identified, created_at) - sessions(session_id, person_id, distinct_id, started_at, ended_at, duration_seconds, pageviews, event_count, entry_url, entry_pathname, exit_url, exit_pathname, referrer_domain, utm_source, utm_medium, utm_campaign, browser, os, device_type, country, is_bounce) - groups(group_type_index, group_key, properties, created_at) - every saved query, by name (e.g. SELECT * FROM active_accounts). Shorthands: properties.plan → the event/person/group property as a string (also properties['my key']); person.properties.email on events → the person's property; toFloat64OrNull(properties.amount) for numbers; inCohort(person_id, 3) → is the person in cohort 3. Save a query with `save_query` (snake_case name) to define a reusable table such as active_accounts; every person and agent can then SELECT FROM it. Up to 20 s and 10,000 rows per run. ## Send data - Browser SDK: `` or the ESM build https://app.datahop.dev/sdk/browser.js — `datahop.init('', { host: 'https://app.datahop.dev' })`, `identify`, `group`, `capture`, `getFeatureFlag`. - Node/Bun SDK: https://app.datahop.dev/sdk/node.js — `new Datahop({ token, host })`, `capture`, `identify`, `groupIdentify`, `getFeatureFlag`, `shutdown`. - HTTP: `POST https://app.datahop.dev/i/batch` `{ "token", "batch": [{ "uuid", "event", "distinct_id", "timestamp", "properties", "$set"? }] }`. ## Products - Product analytics (core): Events, insights, dashboards, people, cohorts and groups. - Web analytics: Traffic, sources, pages and devices. - Feature flags: Rollouts and targeting. - Experiments: A/B tests with Bayesian results. - Alerts: Get told in Slack or by webhook when a number crosses a line or moves sharply. - Destinations: Forward events as they arrive to a webhook or Slack. - Feedback: Store feedback from your own UI and triage it by person, cohort or group.