> ## Documentation Index
> Fetch the complete documentation index at: https://docs.erdo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Page analytics

> Query how your published pages perform with real visitors — views, conversions, and campaign attribution — with a read-only HogQL query over the org's own analytics events, from chat, MCP, REST, or the CLI

# Page analytics

When Erdo publishes a page for you, real visits to it are recorded into your
organization's own analytics project. **Page analytics** is the read side of that: a
single query surface that answers quantitative questions about how your published pages
perform — how many people viewed a page, which variant converts, where the traffic came
from. It is the same data the growth engine measures a variant against, exposed so your
own products and dashboards can read it too.

You ask the question as a query, not by picking from a fixed menu of reports. That is
deliberate: the events carry enough structure that a new question — views this week,
conversions by campaign, a daily series — is a new query, never a new endpoint to wait
for. The query language is **HogQL**, PostHog's SQL dialect (ClickHouse under the hood),
and it runs read-only against your organization's own project — the project is resolved
server-side from your org, so a query can only ever see your own traffic regardless of
what it selects.

## What every event carries

The tracking snippet Erdo injects into a published page stamps each event with the
properties you need to attribute it. The main table is **`events`** — one row per event,
with `event` (the event name), `timestamp`, `distinct_id` (the visitor), and JSON
properties you read as `properties.<name>`:

| Property                                                                       | What it identifies                                           |
| ------------------------------------------------------------------------------ | ------------------------------------------------------------ |
| `properties.artifact_id`                                                       | The published page the event fired on                        |
| `properties.variant`                                                           | The experiment variant, when the page is running an A/B test |
| `properties.page_url`                                                          | The page URL                                                 |
| `properties.utm_source`, `properties.utm_campaign`, `properties.utm_medium`, … | The campaign the visitor arrived from                        |

PostHog auto-captures a `$pageview` event on every view, so `$pageview` is your
denominator when you compute a rate. Pages can also emit named conversion events (a form
start, a lead, a video play); if you're not sure what event names exist, list them first
with a `SELECT event, count() FROM events GROUP BY event`.

## enabled: false means analytics is off, not empty

Every result comes back as `{ enabled, columns, types, rows, truncated }`. The one field
to read first is **`enabled`**. When it is `false`, page analytics is switched *off* for
your organization — it does **not** mean zero traffic. Treat it as a prompt to turn
analytics on (publishing a page, or the first view of one, also turns it on), not as an
empty dashboard. When `enabled` is `true`, `columns` names the columns, `rows` holds the
result positionally per column, and `truncated` is `true` when the result hit the row cap
— aggregate further or add a tighter filter if you see it.

## Example queries

**Views per page over the last week** — the everyday "how much traffic did each page
get" read, grouped by the page's `artifact_id`:

```sql theme={null}
SELECT properties.artifact_id, count() AS views
FROM events
WHERE event = '$pageview' AND timestamp > now() - INTERVAL 7 DAY
GROUP BY 1
ORDER BY views DESC
```

**Views by campaign** — attribute traffic to the campaign that brought it, so you can see
which `utm_campaign` is actually landing visitors:

```sql theme={null}
SELECT properties.utm_campaign, count() AS views
FROM events
WHERE event = '$pageview' AND timestamp > now() - INTERVAL 30 DAY
GROUP BY 1
ORDER BY views DESC
```

**Daily \$pageview series** — traffic over time, one row per day, to spot a launch spike or
a slow week:

```sql theme={null}
SELECT toDate(timestamp) AS day, count() AS views
FROM events
WHERE event = '$pageview' AND timestamp > now() - INTERVAL 30 DAY
GROUP BY day
ORDER BY day
```

Always bound a query by `timestamp` and add a `LIMIT` — the events table grows with your
traffic, and an unbounded scan is slower and more likely to be truncated. If a query is
rejected, the error carries PostHog's own diagnosis (an unknown column, a syntax slip),
so you can fix the query and retry in place.

## In chat

The simplest way in is to ask — the agent writes the HogQL for you:

> "How many views did each of my published pages get this week, and which campaign drove
> the most traffic?"

The agent runs the query, reads the result, and summarizes it. If analytics isn't on yet,
it will tell you and offer to enable it.

## CLI

```bash theme={null}
# Views per page over the last 7 days, printed as a table
erdo analytics query "SELECT properties.artifact_id, count() AS views FROM events WHERE event = '\$pageview' AND timestamp > now() - INTERVAL 7 DAY GROUP BY 1 ORDER BY views DESC"

# Get the raw JSON result instead (columns, types, rows, truncated)
erdo analytics query "SELECT count() FROM events WHERE event = '\$pageview'" --json
```

By default the CLI prints an aligned table of the result. When analytics is off for the
org, it says so rather than printing an empty table.

## MCP

The `erdo_page_analytics_query` tool takes a single `query` argument (the HogQL) and
returns the `{ enabled, columns, types, rows, truncated }` result. Its description carries
the events schema above, so an agent can write a correct query without first
reverse-engineering the properties.

## REST

| MCP tool                    | REST endpoint              | Method |
| --------------------------- | -------------------------- | ------ |
| `erdo_page_analytics_query` | `/v1/page-analytics/query` | POST   |

```bash theme={null}
curl -X POST https://api.erdo.ai/v1/page-analytics/query \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "query": "SELECT properties.artifact_id, count() AS views FROM events WHERE event = '"'"'$pageview'"'"' AND timestamp > now() - INTERVAL 7 DAY GROUP BY 1 ORDER BY views DESC" }'
```

The response mirrors the tool exactly:

```json theme={null}
{
  "enabled": true,
  "columns": ["artifact_id", "views"],
  "types": ["Nullable(String)", "UInt64"],
  "rows": [
    ["a1b2c3d4-0000-0000-0000-000000000000", 412],
    ["e5f6a7b8-0000-0000-0000-000000000000", 190]
  ],
  "truncated": false
}
```

Querying needs **member** access to the organization; the query only ever reads that
organization's own analytics project.
