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 isevents — one row per event,
with event (the event name), timestamp, distinct_id (the visitor), and JSON
properties you read as properties.<name>:
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.
What these numbers can’t tell you
These events record what visitors did. They do not record whether anything was tagging those visitors while they did it, and the two come apart in a way that matters: a month of well-engaged sessions looks identical whether or not a Meta pixel was cookieing the people in it, but only in the first case is there a retargeting audience to campaign against. Before you act on a number here — especially an audience size — read page tracking to see which destinations are actually installed.Example queries
Views per page over the last week — the everyday “how much traffic did each page get” read, grouped by the page’sartifact_id:
utm_campaign is actually landing visitors:
create_google_ads_campaign
sets a campaign-level final URL suffix of utm_source=google&utm_medium=cpc&utm_campaign=<slug>&utm_content={adgroupid}&utm_term={keyword},
where the slug is the campaign name lower-cased with every run of non-alphanumeric characters
collapsed to a dash (so “Summer Sale — 2026” tags as summer-sale-2026). Pass final_url_suffix
on the create to dictate the value instead. Google’s auto-tagging alone appends a gclid, which
names the click rather than the campaign, so a campaign with neither a suffix nor a template
lands visitors this query cannot attribute.
Google replaces {adgroupid} with the ad group ID and {keyword} with the matched keyword
at click time; the keyword is empty for non-keyword matches. Page events and leads capture
these as utm_content and utm_term, letting you split modal opens, form starts, and leads
by ad group and keyword. Rows collected with the previous default have these fields empty;
updating a campaign does not backfill them.
For an existing campaign missing either parameter, read its final URL suffix and its
tracking template, then change both in a single mutate_google_ads_campaign update
operation with mask final_url_suffix,tracking_url_template. Add the missing
utm_content={adgroupid} / utm_term={keyword} to the suffix, keeping the existing
utm_campaign value and other parameters unchanged, and drop the template’s own
utm_content / utm_term in the same write — use creative={creative} to keep a
creative ID separately.
Both settings have to move together because Google appends them to the same click, and a
parameter sent twice gives the page two values for one tag. A suffix-only write is refused
when the template still carries either parameter, and because the check runs just before
the write, the refusal arrives after you have approved the change. Campaigns predating
this default usually do carry those parameters in their template, so plan the migration
as one operation rather than discovering the refusal on your ad account.
A campaign that sets no tracking template of its own inherits the account’s, and an
account-level template carrying utm_content / utm_term is refused the same way.
Setting the campaign’s own template in that one operation overrides it; otherwise clear
the account-level template in the Google Ads UI. In an ad account shared across
organizations Erdo cannot read the account level, so it reports what it could not check
rather than refusing the write — the note rides both the result and the confirmation card
the write leaves in the thread, so the manual cleanup is still there to act on later.
Daily $pageview series — traffic over time, one row per day, to spot a launch spike or
a slow week:
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
MCP
Theerdo_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.

