
BigQuery
×
Papercrane
You already price your queries before you run them. Papercrane writes the SQL, joins datasets across projects, and refreshes dashboards on a schedule you set, so the bill does not depend on who opened the report.
Connect in about a minute with read access you approve on Google's consent screen. Free to connect and ask. Paid plans start when you publish a dashboard. See pricing
Every dashboard on your warehouse runs queries; the only question is when. Viewer triggered tools query when someone opens or filters, Papercrane queries when the dashboard refreshes on the schedule you set.
Same dashboard, 8 tiles, one month
Queries run when viewers look
8 tiles per open, plus filter changes
35 people, ~4 cache missing opens or filter changes a day
≈ 1,120 queries a day
× 0.8 GB scanned per query (partitioned, pruned)
≈ 27 TB a month
≈ $168/month on demand
↗
and it rises every time the link gets forwarded
Queries run when the dashboard refreshes
8 tiles, refreshed hourly across a 12 hour workday
= 96 queries a day
× 0.8 GB scanned per query (same tables)
≈ 2.3 TB a month
≈ $14/month on demand
→
at 5 viewers or 500
Viewers open a hosted dashboard, not your warehouse: filters on a published dashboard work over the last refresh's results and run no new warehouse queries. Next month's number is arithmetic you can do today.
Repeat opens of an unchanged report can hit BigQuery's free result cache. Filter changes and fresh data bust it, which is exactly how viewer triggered bills grow.
The data landed and the models run, but questions still route through whoever writes the SQL. Papercrane answers from the same datasets, and every answer arrives with its SQL attached, so the asker stops needing you and you can still check the work.
Which campaigns drove signups that activated in week one?
Revenue by product line, finance dataset joined to product events
Which tables changed row counts unexpectedly this week?
The same dashboard against the staging and prod projects, side by side
Answers come back as charts on a live hosted dashboard, ready to share the day you build it.
GA4's free export lands your events as nested rows, where pulling three fields takes eighteen lines of UNNEST. The agent already knows the events_ schema: ask about funnels, sessions, or revenue, and read the SQL it wrote.
Signups by source, last 30 days
18 lines of UNNEST, written for you
SELECT event_date, (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'source') AS utm_source, (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'medium') AS utm_medium, (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'campaign') AS utm_campaign, COUNT(DISTINCT CONCAT( user_pseudo_id, '.', CAST((SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS STRING) ) ) AS sessions, COUNTIF(event_name = 'sign_up') AS signupsFROM `project.analytics_123456789.events_*`WHERE event_name IN ('session_start', 'sign_up') AND _TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)) AND FORMAT_DATE('%Y%m%d', CURRENT_DATE())GROUP BY event_date, utm_source, utm_medium, utm_campaignORDER BY signups DESC
Signups by source, last 30 days
18 lines of UNNEST, written for you
SELECT event_date, (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'source') AS utm_source, (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'medium') AS utm_medium, (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'campaign') AS utm_campaign, COUNT(DISTINCT CONCAT( user_pseudo_id, '.', CAST((SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS STRING) ) ) AS sessions, COUNTIF(event_name = 'sign_up') AS signupsFROM `project.analytics_123456789.events_*`WHERE event_name IN ('session_start', 'sign_up') AND _TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)) AND FORMAT_DATE('%Y%m%d', CURRENT_DATE())GROUP BY event_date, utm_source, utm_medium, utm_campaignORDER BY signups DESC
Using GA4 without the export? Papercrane connects the reporting data directly on the Google Analytics page.
1. Connect with read access you approve on Google's consent screen
About a minute. Connect more than one GCP project and address each by name.
2. The agent explores your datasets
It reads schemas across projects, writes SQL with joins across datasets, and every query it runs is visible while it works.
3. Publish a hosted dashboard on a refresh schedule you set
Share it by link, embed it, or put it on a custom domain. When a schema change breaks a query, the error routes back to the agent, and its repair is a change to code you own and can read.
Your data stays in BigQuery. Dashboards run their SQL at refresh time and serve the results to viewers.
When you do not need us
If your tables are a few gigabytes and you need one internal chart today, Looker Studio is free, native, and already inside your Google login: use it, the billing math above will not bite at that size. If your company runs governed metrics through Looker and LookML, keep the semantic layer for board numbers; Papercrane is for the questions that never earn a model. And if you are on capacity pricing with headroom, viewer traffic is already paid for, so our scheduling argument matters less to you than to on demand teams.
The warehouse rarely holds the whole answer. Teams join BigQuery to GA4 for behavior, Google Ads for spend, and Stripe for what the money actually did.
Connect BigQuery, ask the question you'd normally price before running, and read the SQL that answered it.
Free to connect and ask. Works across projects and datasets.
Papercrane
Integrations: