
Querying Canvas Data
FreeIntegrate PostHog data seamlessly into your canvas.
Free · Opens the source repo
What Querying Canvas Data does
The Querying Canvas Data skill enables developers to effectively integrate PostHog analytics into canvas applications. By utilizing the host-injected ph SDK, this skill allows for the retrieval and display of metrics, charts, and tables directly from PostHog. It ensures that all interactions with PostHog data are secure and compliant with sandbox restrictions, as credentials remain with the host. This skill is particularly useful for developers looking to visualize analytics data within their applications without needing to manage authentication or data fetching manually.
The skill employs a structured data hierarchy for querying metrics, emphasizing the importance of using saved insights whenever possible. Developers can create insights using various query types such as TrendsQuery and FunnelsQuery, ensuring that the metrics displayed are reliable and consistent with what users see in the PostHog UI. If a saved insight does not fit the use case, developers can resort to ad-hoc queries or inline HogQL, although the latter should be used as a last resort due to potential inaccuracies in metrics.
Additionally, the skill provides clear guidelines on how to handle result shapes from queries, ensuring that developers can accurately render data in their applications. It emphasizes the importance of managing loading states and error handling to enhance user experience. By adhering to these practices, developers can avoid common pitfalls like displaying incorrect data or failing to communicate errors effectively.
Overall, Querying Canvas Data is designed for developers who need to integrate PostHog analytics into their canvas applications efficiently. It streamlines the process of querying and displaying data while ensuring best practices are followed for optimal performance and accuracy.
When to use it
Use this skill when you need to display PostHog metrics, charts, or tables in a canvas application or capture analytics events.
When not to use it
This skill is not suitable for applications that do not use PostHog for analytics or require raw SQL queries without the structured insights.
What you can build with it
Displaying Metrics on a Dashboard
Integrate PostHog metrics into a canvas-based dashboard, using saved insights to ensure accuracy.
Capturing User Interactions
Capture analytics events from user interactions within the canvas using the `ph.capture` method.
Handling Date Ranges for Insights
Dynamically adjust the date range of insights displayed in the canvas based on user-selected date windows.
How to install Querying Canvas Data
View source1. Install with the skills CLI
npx skills add posthog/posthog/querying-canvas-data --agent claude-code2. Or install it manually
Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.
Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs
Inside SKILL.md
Written by posthogQuerying canvas data
The global ph object (injected by the host — never imported, never initialized) is the only way
a canvas talks to PostHog. Credentials stay in the host; fetch(), posthog-js, and hand-rolled
clients fail in the sandbox.
Data hierarchy — back every metric with a saved insight
- Preferred — save an insight, load it by reference. Use the PostHog MCP insight tools to
create/save an insight that computes the metric with an insight query type (TrendsQuery,
FunnelsQuery, RetentionQuery, PathsQuery, or the web-analytics kinds WebOverviewQuery /
WebStatsTableQuery — not raw SQL). Confirm its numbers, note the
short_id, and render it withawait ph.loadInsight(shortId, { dateRange }). These are proven queries — numbers match the PostHog UI exactly (sessionization, unique users, breakdowns, bounce rate). Never fabricate a query or guess event/property names; discover and save them via MCP first. - Secondary — an ad-hoc typed node:
ph.query({ kind: "TrendsQuery", series: [...], dateRange: {...} })when saving an insight genuinely doesn't fit. - Last resort — inline HogQL:
ph.query("SELECT …"), only when no insight kind can express the metric; you then own the SQL and its date window.
For web-analytics boards specifically, use the web-analytics query kinds — raw HogQL subtly gets bounce rate, sessionization, channel attribution, and unique-visitor counts wrong.
Whatever tier you use, declare it in the project's capabilities before publishing: every
ph.loadInsight short id in capabilities.posthog.insights, every ph.capture event name in
captureEvents, and inlineQueries: true for any ph.query use. The host rejects undeclared
calls at runtime, and validation fails on undeclared literals.
Result shapes — read them correctly or every value renders 0
- Trends-style results (insight query types, via
ph.loadInsightor a typed node):resultsis an array of series objects, not rows. Each series hasdata: number[](per interval),days: string[](ISO),labels: string[],count(sum),aggregated_value(single-value total),label, and optionalcompare_label: "current" | "previous". A KPI total isresults[0].count(or.aggregated_value); a line chart plotsresults[0].dataoverresults[0].days. With a compare period, find the prior series bycompare_label === "previous"— never by index.columnsis empty here. - SQL results:
{ columns: string[], results: rows[][] }— each row an array of cell values incolumnsorder.
Load data in useEffect with useState, show a loading state, and aggregate in the query; never
fetch raw event dumps. Treat a rejected query and an empty result as different states: .catch
must set an error state that renders visibly (message + retry), never fall through to zeros, an
empty chart, or a "no data" message — a swallowed error makes real breakage (a missing table, an
auth failure) look like missing data. Reserve the empty state for a query that succeeded with no
rows.
Date windows
- Pass the canvas's date-picker window straight into
dateRange:ph.loadInsight(shortId, { dateRange: { date_from: win.start.toISOString(), date_to: win.end.toISOString() } })— the saved insight re-scopes to the window with no time SQL. Typed nodes take the samedateRange. Re-run every query when the window changes. - A saved SQL insight may ignore
dateRange(its window lives inside the SQL) — a reason to prefer insight query types. - Inline HogQL escape hatch only: never bake
now()or a hardcoded INTERVAL. Compute unix bounds (Math.floor(win.start.getTime() / 1000)) and write half-opentimestamp >= toDateTime(fromUnix) AND timestamp < toDateTime(toUnix). Prior period = the equal-length window immediately before; bucket withtoStartOfDay/toStartOfHour.
Side effects
ph.capture(event, properties?, distinctId?)— analytics events for interactions (fire-and-forget). Session replay,$session_id, and person attribution are handled by the host automatically; never roll your own capture.ph.openExternal(url)— openshttps://posthog.com/*.posthog.comURLs only, and only from a user interaction (opens outside focus are ignored). Don't link elsewhere.ph.navigate.toTask(id)/.toNewTask()/.toCanvas(id)/.toNewCanvas()— in-app navigation within the canvas's own channel.
Frequently asked questions about Querying Canvas Data
Similar skills
WinMD API Search
Easily find and explore Windows desktop APIs.
WebMCPify
Transform any web app into an agent-ready platform.
Phoenix Tracing
Instrument LLM applications with OpenInference tracing.
Foundry Hosted Agent CopilotKit
Guidance for developing agentic web apps on Azure.
Power Automate Foundation
Connect AI agents to Power Automate seamlessly.
Power Automate Flow Builder
Efficiently build and deploy Power Automate flows programmatically.
