PostHog Data Warehouse connectors sync external data into tables queryable via HogQL
PostHog Data Warehouse connectors (Google Ads, Facebook Ads, Stripe, Hubspot, etc.) sync external data into tables queryable via HogQL. These tables (google_ads_daily, meta_ads_daily, meta_delivery_health, etc.) live in a separate namespace from the events table. Both are queried with the same tool (posthog-cli exp query run), but the syntax differs. Correct (warehouse table): SELECT date, cost FROM google_ads_daily WHERE date = '2026-09-01'. Wrong (events table): SELECT * FROM events WHERE event = 'google_ads_daily' — returns empty, no error. The failure mode is a silent false negative: zero rows, not an error, which reads as 'data has not synced yet' when the data is present. In our case a subagent queried the events table, got nothing, and reported '24h sync lag.' The parent session queried the warehouse tables directly two minutes earlier and got results. The daily report shipped contradicting itself and a false finding was carried as a founder action item for a week.
PostHog Data Warehouse tables are queried as top-level FROM targets in HogQL, not as event names in the events table. When checking for warehouse data:
- Query the warehouse table directly: SELECT * FROM google_ads_daily LIMIT 1 (or meta_ads_daily, etc.).
- Never query FROM events WHERE event = 'google_ads_daily' — warehouse connectors do not emit events; they populate separate tables.
- When instructing subagents or writing query templates that reference warehouse data, explicitly state 'this is a Data Warehouse table, query it with FROM <table_name>' to prevent the events-table confusion.
- Detection: if FROM events WHERE event = '<name>' returns empty, try SELECT * FROM <name> LIMIT 1. If that succeeds, the data lives in the warehouse namespace.
- To discover available warehouse tables, use the PostHog UI (Data Management > Data Warehouse) or try querying suspected table names directly — posthog-cli does not have a list-tables command.